Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 15 additions & 9 deletions lib/examples.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -104,23 +104,29 @@ export function catalogueFiles() {
* <br>text the summary sentence (normal type)
* <br><sub>text</sub> the search terms, then the docs links
*/
const ROW = /^\|\s*(?:\*\*(?<title>[^*]+)\*\*\s*(?:—|--)\s*)?(?<sub>[^|<]*?)\s*(?<blocks>(?:<br>(?:<sub>[^<]*<\/sub>|[^<]*))*)\s*\|\s*\[`(?<cls>[A-Z0-9_]+)`\]\((?<path>[^)]+)\)\s*\|/;
const ROW = /^\|\s*(?:\*\*(?<title>[^*]+)\*\*\s*(?:—|--)\s*)?(?<sub>[^|<]*?)\s*(?<blocks>(?:<br>(?:<[a-z]+>[^<]*<\/[a-z]+>|[^<]*))*)\s*\|\s*\[`(?<cls>[A-Z0-9_]+)`\]\((?<path>[^)]+)\)\s*\|/;

/** The blocks under a row title, in order, as `{ small, text }`. */
/* The blocks under a row title, in order, as `{ tag, text }`.
*
* A block wrapped in a tag nobody here knows is kept as a block with that tag
* and then ignored by both readers below - which is the whole reason the row
* pattern accepts any tag rather than `<sub>` alone. Twice now a new KIND of
* block has made every row unmatchable over here, and that failure reads as
* "there are no samples for that" rather than as a parse error. */
function blocksOf(blocks) {
return [...(blocks || '').matchAll(/<br>(?:<sub>([^<]*)<\/sub>|([^<]*))/g)]
return [...(blocks || '').matchAll(/<br>(?:<([a-z]+)>([^<]*)<\/[a-z]+>|([^<]*))/g)]
.map((m) => (m[1] !== undefined
? { small: true, text: m[1].trim() }
: { small: false, text: (m[2] || '').trim() }))
? { tag: m[1], text: (m[2] || '').trim() }
: { tag: '', text: (m[3] || '').trim() }))
.filter((b) => b.text);
}

/** The sentence: the first block in NORMAL type. */
const summaryOf = (blocks) => (blocksOf(blocks).find((b) => !b.small)?.text || '');
/** The sentence: the first block in NORMAL type (no tag at all). */
const summaryOf = (blocks) => (blocksOf(blocks).find((b) => !b.tag)?.text || '');

/** The keywords: the first SMALL block that is not the `docs:` one. */
/** The keywords: the first `<sub>` block that is not the `docs:` one. */
const keywordsOf = (blocks) =>
(blocksOf(blocks).find((b) => b.small && !b.text.startsWith('docs:'))?.text || '');
(blocksOf(blocks).find((b) => b.tag === 'sub' && !b.text.startsWith('docs:'))?.text || '');

/** src/01 is the supported set; src/00 is experimental (97) or a test app (98). */
const areaOf = (repo, p) => {
Expand Down
21 changes: 21 additions & 0 deletions test/unit.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,27 @@ test('a row without a summary still parses', () => {
assert.equal(e.keywords, 'f4 search help suggestion input');
});

/* The row shape is maintained in three OTHER repositories, and a new kind of
* block has twice made every row unmatchable here. A block whose tag this
* parser has never seen must cost it nothing - the sample still has to be
* findable, because "no rows parsed" reads as "there are no samples for that"
* rather than as a parse error. */
test('a row survives a block this parser has never seen', () => {
const md = [
'## Basics',
'',
'| Sample | Class |',
'|---|---|',
'| **Future** — Something<br>The sentence.<br><span>a block from a later generator</span><br><sub>terms here</sub> | [`Z2UI5_CL_SMP_APP_999`](src/01/z2ui5_cl_smp_app_999.clas.abap) |',
].join('\n');
const [e] = parseExamples(md);
assert.ok(e, 'the row with an unknown block was dropped');
assert.equal(e.cls, 'Z2UI5_CL_SMP_APP_999');
// and the two blocks this parser DOES read are still told apart correctly
assert.equal(e.summary, 'The sentence.');
assert.equal(e.keywords, 'terms here');
});

test('every catalogue names its repository and its env var when it is missing', () => {
assert.deepEqual(CATALOGUES.map((c) => c.repo), ['samples', 'samples-controls', 'samples-stack']);
for (const c of CATALOGUES) {
Expand Down