From 9a9f2fb4ccdcbeb8e5045825213cf7dccda557e4 Mon Sep 17 00:00:00 2001 From: HiDeoo <494699+HiDeoo@users.noreply.github.com> Date: Mon, 6 Nov 2023 11:01:20 +0100 Subject: [PATCH] fix: validate reference-style links --- .../starlight-links-validator/libs/remark.ts | 16 +++++++++++++++- .../with-invalid-links/src/content/docs/test.md | 8 ++++++++ .../with-valid-links/src/content/docs/index.md | 11 +++++++++++ .../tests/validation.test.ts | 4 +++- 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/packages/starlight-links-validator/libs/remark.ts b/packages/starlight-links-validator/libs/remark.ts index 524c9a7..92b2bec 100644 --- a/packages/starlight-links-validator/libs/remark.ts +++ b/packages/starlight-links-validator/libs/remark.ts @@ -24,8 +24,13 @@ export const remarkStarlightLinksValidator: Plugin<[], Root> = function () { const fileHeadings: string[] = [] const fileLinks: string[] = [] + const fileDefinitions = new Map() - visit(tree, ['heading', 'html', 'link', 'mdxJsxFlowElement', 'mdxJsxTextElement'], (node) => { + visit(tree, 'definition', (node) => { + fileDefinitions.set(node.identifier, node.url) + }) + + visit(tree, ['heading', 'html', 'link', 'linkReference', 'mdxJsxFlowElement', 'mdxJsxTextElement'], (node) => { // https://github.com/syntax-tree/mdast#nodes // https://github.com/syntax-tree/mdast-util-mdx-jsx#nodes switch (node.type) { @@ -47,6 +52,15 @@ export const remarkStarlightLinksValidator: Plugin<[], Root> = function () { break } + case 'linkReference': { + const definition = fileDefinitions.get(node.identifier) + + if (definition && isInternalLink(definition)) { + fileLinks.push(definition) + } + + break + } case 'mdxJsxFlowElement': { for (const attribute of node.attributes) { if (isMdxIdAttribute(attribute)) { diff --git a/packages/starlight-links-validator/tests/fixtures/with-invalid-links/src/content/docs/test.md b/packages/starlight-links-validator/tests/fixtures/with-invalid-links/src/content/docs/test.md index 932b5f9..b0ef577 100644 --- a/packages/starlight-links-validator/tests/fixtures/with-invalid-links/src/content/docs/test.md +++ b/packages/starlight-links-validator/tests/fixtures/with-invalid-links/src/content/docs/test.md @@ -23,6 +23,14 @@ title: Test - [Link to invalid asset](/icon.svg) - [Link to another invalid asset](/guidelines/ui.pdf) +## Links with references + +- [Link reference to unknwon page][ref-unknown-page] +- [Link reference to invalid anchor][ref-invalid-anchor] + +[ref-unknown-page]: /unknown-ref +[ref-invalid-anchor]: #unknown-ref +
some content diff --git a/packages/starlight-links-validator/tests/fixtures/with-valid-links/src/content/docs/index.md b/packages/starlight-links-validator/tests/fixtures/with-valid-links/src/content/docs/index.md index b8bdc35..cffb9f8 100644 --- a/packages/starlight-links-validator/tests/fixtures/with-valid-links/src/content/docs/index.md +++ b/packages/starlight-links-validator/tests/fixtures/with-valid-links/src/content/docs/index.md @@ -29,3 +29,14 @@ title: Index ## A more `complex` heading - [Link to more complex anchor](#a-more-complex-heading) + +## Links with references + +- [ref] +- [Link reference][ref] +- [Link reference with anchor in this page][ref-with-anchor-internal] +- [Link reference with anchor in another page][ref-with-anchor-external] + +[ref]: /test +[ref-with-anchor-internal]: #some-links +[ref-with-anchor-external]: /test#title diff --git a/packages/starlight-links-validator/tests/validation.test.ts b/packages/starlight-links-validator/tests/validation.test.ts index 996fe6c..8b8a8f6 100644 --- a/packages/starlight-links-validator/tests/validation.test.ts +++ b/packages/starlight-links-validator/tests/validation.test.ts @@ -16,7 +16,7 @@ test('should not build with invalid links', async () => { try { await loadFixture('with-invalid-links') } catch (error) { - expect(error).toMatch(/Found 18 invalid links in 3 files./) + expect(error).toMatch(/Found 20 invalid links in 3 files./) expect(error).toMatch( new RegExp(`▶ test/ @@ -29,6 +29,8 @@ test('should not build with invalid links', async () => { ├─ /guides/example/#links ├─ /icon.svg ├─ /guidelines/ui.pdf + ├─ /unknown-ref + ├─ #unknown-ref └─ #anotherDiv`), )