From cccaed0d3d927b34bf44ed1d429b350bd202bdfd Mon Sep 17 00:00:00 2001 From: SkyZeroZx <73321943+SkyZeroZx@users.noreply.github.com> Date: Thu, 19 Feb 2026 18:09:27 -0500 Subject: [PATCH] docs(docs-infra): preserve content before docs-card-container in adev The tokenizer regex pattern `[^<]*` was consuming all non-`<` content before custom HTML tags, causing lost content. Changed to `\s*` which only allows leading whitespace, letting marked properly tokenize preceding content. (cherry picked from commit bc473cf60f735babfacb262150d3d1bed191ce12) --- .../docs-card/docs-card-container.mts | 2 +- .../marked/extensions/docs-card/docs-card.mts | 2 +- .../docs-card-container.md | 39 ++++++++++++- .../docs-card-container.spec.mts | 58 +++++++++++++++++-- 4 files changed, 93 insertions(+), 8 deletions(-) diff --git a/adev/shared-docs/pipeline/shared/marked/extensions/docs-card/docs-card-container.mts b/adev/shared-docs/pipeline/shared/marked/extensions/docs-card/docs-card-container.mts index 3d8cfc0fe01..2c7096ff932 100644 --- a/adev/shared-docs/pipeline/shared/marked/extensions/docs-card/docs-card-container.mts +++ b/adev/shared-docs/pipeline/shared/marked/extensions/docs-card/docs-card-container.mts @@ -21,7 +21,7 @@ interface DocsCardContainerToken extends Tokens.Generic { // Capture group 1: all attributes on the opening tag // Capture group 2: all content between the open and close tags const cardContainerRule = - /^[^<]*]*))?>((?:.(?!\/docs-card-container))*)<\/docs-card-container>/s; + /^\s*]*))?>((?:.(?!\/docs-card-container))*)<\/docs-card-container>/s; const headerTitleRule = /headerTitle="([^"]*)"/; const headerImgSrcRule = /headerImgSrc="([^"]*)"/; diff --git a/adev/shared-docs/pipeline/shared/marked/extensions/docs-card/docs-card.mts b/adev/shared-docs/pipeline/shared/marked/extensions/docs-card/docs-card.mts index f21fa8469bc..3642e813c6b 100644 --- a/adev/shared-docs/pipeline/shared/marked/extensions/docs-card/docs-card.mts +++ b/adev/shared-docs/pipeline/shared/marked/extensions/docs-card/docs-card.mts @@ -23,7 +23,7 @@ interface DocsCardToken extends Tokens.Generic { // Capture group 1: all attributes on the opening tag // Capture group 2: all content between the open and close tags -const cardRule = /^[^<]*]*))?>((?:.(?!\/docs-card))*)<\/docs-card>/s; +const cardRule = /^\s*]*))?>((?:.(?!\/docs-card))*)<\/docs-card>/s; const titleRule = /title="([^"]*)"/; const linkRule = /link="([^"]*)"/; diff --git a/adev/shared-docs/pipeline/shared/marked/test/docs-card-container/docs-card-container.md b/adev/shared-docs/pipeline/shared/marked/test/docs-card-container/docs-card-container.md index 29511a71095..bfdc38e7438 100644 --- a/adev/shared-docs/pipeline/shared/marked/test/docs-card-container/docs-card-container.md +++ b/adev/shared-docs/pipeline/shared/marked/test/docs-card-container/docs-card-container.md @@ -1,4 +1,39 @@ +Introductory paragraph that should be preserved before any card containers. + +## First Section + +This section contains important information about the feature status. + +### Available features + +- Feature one +- Feature two +- Feature three + +### In progress + +The following items are currently being developed: + +1. Item A with description +2. Item B with description + - - + + + +### Additional context + +More text after the first card container that should also be preserved. + +## Second Section + +Another paragraph before the second card container. + + + + + +## Final Section + +Concluding remarks at the end of the document. diff --git a/adev/shared-docs/pipeline/shared/marked/test/docs-card-container/docs-card-container.spec.mts b/adev/shared-docs/pipeline/shared/marked/test/docs-card-container/docs-card-container.spec.mts index 3b8363b56ec..86d39c25822 100644 --- a/adev/shared-docs/pipeline/shared/marked/test/docs-card-container/docs-card-container.spec.mts +++ b/adev/shared-docs/pipeline/shared/marked/test/docs-card-container/docs-card-container.spec.mts @@ -20,10 +20,60 @@ describe('markdown to html', () => { markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, rendererContext)); }); - it('creates card containers containing multiple cards', () => { - const containerEl = markdownDocument.querySelector('.docs-card-grid'); + it('creates multiple card containers with correct card counts', () => { + const containers = markdownDocument.querySelectorAll('.docs-card-grid'); - expect(containerEl!.children.length).toBe(2); - expect(containerEl!.classList.contains('docs-card-grid')).toBeTrue(); + expect(containers.length).toBe(2); + expect(containers[0].children.length).toBe(2); + expect(containers[1].children.length).toBe(1); + }); + + it('preserves all h2 section headings', () => { + const h2Elements = markdownDocument.querySelectorAll('h2'); + + expect(h2Elements.length).toBe(3); + expect(h2Elements[0].textContent).toContain('First Section'); + expect(h2Elements[1].textContent).toContain('Second Section'); + expect(h2Elements[2].textContent).toContain('Final Section'); + }); + + it('preserves all h3 subsection headings outside card containers', () => { + // Card titles also render as h3, so we filter to only h3s not inside card containers + const allH3s = Array.from(markdownDocument.querySelectorAll('h3')); + const sectionH3s = allH3s.filter((h3) => !h3.closest('.docs-card-grid')); + + expect(sectionH3s.length).toBe(3); + expect(sectionH3s[0].textContent).toContain('Available features'); + expect(sectionH3s[1].textContent).toContain('In progress'); + expect(sectionH3s[2].textContent).toContain('Additional context'); + }); + + it('preserves unordered lists before card containers', () => { + const ulElements = markdownDocument.querySelectorAll('ul'); + + expect(ulElements.length).toBeGreaterThanOrEqual(1); + expect(ulElements[0].children.length).toBe(3); + expect(ulElements[0].textContent).toContain('Feature one'); + }); + + it('preserves ordered lists before card containers', () => { + const olElements = markdownDocument.querySelectorAll('ol'); + + expect(olElements.length).toBe(1); + expect(olElements[0].children.length).toBe(2); + expect(olElements[0].textContent).toContain('Item A'); + }); + + it('preserves paragraphs throughout the document', () => { + const paragraphs = markdownDocument.querySelectorAll('p'); + + expect(paragraphs.length).toBeGreaterThanOrEqual(5); + + const paragraphTexts = Array.from(paragraphs).map((p) => p.textContent); + expect(paragraphTexts.some((t) => t?.includes('Introductory paragraph'))).toBeTrue(); + expect(paragraphTexts.some((t) => t?.includes('important information'))).toBeTrue(); + expect(paragraphTexts.some((t) => t?.includes('More text after'))).toBeTrue(); + expect(paragraphTexts.some((t) => t?.includes('Another paragraph'))).toBeTrue(); + expect(paragraphTexts.some((t) => t?.includes('Concluding remarks'))).toBeTrue(); }); });