diff --git a/lib/examples.mjs b/lib/examples.mjs index 09aedcf..754e0ab 100644 --- a/lib/examples.mjs +++ b/lib/examples.mjs @@ -104,23 +104,29 @@ export function catalogueFiles() { *
text the summary sentence (normal type) *
text the search terms, then the docs links */ -const ROW = /^\|\s*(?:\*\*(?[^*]+)\*\*\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) => { diff --git a/test/unit.test.mjs b/test/unit.test.mjs index be0fa92..62a2b93 100644 --- a/test/unit.test.mjs +++ b/test/unit.test.mjs @@ -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) {