diff --git a/scripts/js/lib/links/extractLinks.test.ts b/scripts/js/lib/links/extractLinks.test.ts index 44626d066a6..8da3804329e 100644 --- a/scripts/js/lib/links/extractLinks.test.ts +++ b/scripts/js/lib/links/extractLinks.test.ts @@ -29,6 +29,16 @@ test("parseAnchors()", () => { ## \`code-header\` + ## Header.with periods-and wild! punctuation?? and numbers 1234 8 (parentheses) + + ## header_using\_underscores + + ## UpperCase Should Be lowercase + + ## repeated + ## repeated + ## repeated + Convert to dictionary. @@ -36,15 +46,26 @@ test("parseAnchors()", () => { \`Dict\` + + + ### Header inside a component + `); expect(result).toEqual( new Set([ "#my-top-level-heading", "#header-2", "#code-header", + "#headerwith-periods-and-wild-punctuation-and-numbers-1234-8-parentheses", + "#header_using_underscores", + "#uppercase-should-be-lowercase", "#this-is-a-hardcoded-anchor", "#another_span", "#mdx.component.testId", + "#header-inside-a-component", + "#repeated", + "#repeated-1", + "#repeated-2", ]), ); }); diff --git a/scripts/js/lib/links/extractLinks.ts b/scripts/js/lib/links/extractLinks.ts index 822a2d21728..5f4a7d8a3ea 100644 --- a/scripts/js/lib/links/extractLinks.ts +++ b/scripts/js/lib/links/extractLinks.ts @@ -35,11 +35,28 @@ export type ParsedFile = { }; export function parseAnchors(markdown: string): Set { - // Anchors generated from markdown titles. - const mdAnchors = markdownLinkExtractor(markdown).anchors; - // Anchors from HTML id tags. - const idAnchors = markdown.match(/(?<=id=")(.+?)(?=")/gm) || []; - return new Set([...mdAnchors, ...idAnchors.map((id) => `#${id}`)]); + const lines = markdown.split("\n"); + const anchors = new Set(); + for (const line of lines) { + const heading = line.match(/^\s*#{1,6}\s+(.+?)\s*$/); + if (heading) { + const normalized = heading[1] + .toLowerCase() + .trim() + .replaceAll(" ", "-") + .replaceAll(/[\.,;!?`\\\(\)]/g, ""); + let deduplicated = normalized; + let i = 1; + while (anchors.has(`#${deduplicated}`)) { + deduplicated = `${normalized}-${i}`; + i += 1; + } + anchors.add(`#${deduplicated}`); + } + const id = line.match(/(?<=id=")(.+?)(?=")/); + if (id) anchors.add(`#${id[1]}`); + } + return anchors; } export async function parseLinks(