Repository: HiDeoo/starlight-links-validator
Pull request #32 (2024-03-04 17:03:22)

Add support for validating links to pages using a custom slug


Patch:
diff --git a/packages/starlight-links-validator/libs/remark.ts b/packages/starlight-links-validator/libs/remark.ts
index 0b2f3e4..c244c8f 100644
--- a/packages/starlight-links-validator/libs/remark.ts
+++ b/packages/starlight-links-validator/libs/remark.ts
@@ -13,7 +13,7 @@ import { toString } from 'mdast-util-to-string'
 import type { Plugin } from 'unified'
 import { visit } from 'unist-util-visit'
 
-import { stripLeadingSlash } from './path'
+import { ensureTrailingSlash, stripLeadingSlash } from './path'
 
 // All the headings keyed by file path.
 const headings: Headings = new Map()
@@ -24,6 +24,7 @@ export const remarkStarlightLinksValidator: Plugin<[base: string], Root> = funct
   return (tree, file) => {
     const slugger = new GitHubSlugger()
     const filePath = normalizeFilePath(base, file.history[0])
+    const slug = file.data.astro?.frontmatter?.slug
 
     const fileHeadings: string[] = []
     const fileLinks: string[] = []
@@ -124,8 +125,8 @@ export const remarkStarlightLinksValidator: Plugin<[base: string], Root> = funct
       }
     })
 
-    headings.set(filePath, fileHeadings)
-    links.set(filePath, fileLinks)
+    headings.set(getFilePath(filePath, slug), fileHeadings)
+    links.set(getFilePath(filePath, slug), fileLinks)
   }
 }
 
@@ -137,6 +138,10 @@ function isInternalLink(link: string) {
   return !isAbsoluteUrl(link)
 }
 
+function getFilePath(filePath: string, slug: string | undefined) {
+  return slug ? stripLeadingSlash(ensureTrailingSlash(slug)) : filePath
+}
+
 function normalizeFilePath(base: string, filePath?: string) {
   if (!filePath) {
     throw new Error('Missing file path to validate links.')
@@ -170,3 +175,13 @@ interface MdxIdAttribute {
   type: 'mdxJsxAttribute'
   value: string
 }
+
+declare module 'vfile' {
+  interface DataMap {
+    astro?: {
+      frontmatter?: {
+        slug?: string
+      }
+    }
+  }
+}
diff --git a/packages/starlight-links-validator/libs/validation.ts b/packages/starlight-links-validator/libs/validation.ts
index a88546d..c37e5e0 100644
--- a/packages/starlight-links-validator/libs/validation.ts
+++ b/packages/starlight-links-validator/libs/validation.ts
@@ -32,7 +32,9 @@ export function validateLinks(
   const { headings, links } = getValidationData()
   const allPages: Pages = new Set(
     pages.map((page) =>
-      ensureTrailingSlash(base === '/' ? page.pathname : posix.join(stripLeadingSlash(base), page.pathname)),
+      ensureTrailingSlash(
+        base === '/' ? stripLeadingSlash(page.pathname) : posix.join(stripLeadingSlash(base), page.pathname),
+      ),
     ),
   )
 
diff --git a/packages/starlight-links-validator/package.json b/packages/starlight-links-validator/package.json
index ea12a64..918d57d 100644
--- a/packages/starlight-links-validator/package.json
+++ b/packages/starlight-links-validator/package.json
@@ -31,6 +31,7 @@
     "mdast-util-mdx-jsx": "3.0.0",
     "typescript": "5.1.3",
     "unified": "11.0.4",
+    "vfile": "6.0.1",
     "vitest": "1.0.4"
   },
   "peerDependencies": {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index fbe4453..4641de2 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -108,6 +108,9 @@ importers:
       unified:
         specifier: 11.0.4
         version: 11.0.4
+      vfile:
+        specifier: 6.0.1
+        version: 6.0.1
       vitest:
         specifier: 1.0.4
         version: 1.0.4(@types/node@18.17.18)


Test patch:
diff --git a/packages/starlight-links-validator/tests/basics.test.ts b/packages/starlight-links-validator/tests/basics.test.ts
index 4485937..c2e8bbe 100644
--- a/packages/starlight-links-validator/tests/basics.test.ts
+++ b/packages/starlight-links-validator/tests/basics.test.ts
@@ -18,7 +18,7 @@ test('should not build with invalid links', async () => {
   try {
     await loadFixture('basics-invalid-links')
   } catch (error) {
-    expectValidationErrorCount(error, 26, 4)
+    expectValidationErrorCount(error, 28, 4)
 
     expectValidationErrors(error, 'test/', [
       ['/', ValidationErrorType.InvalidLink],
@@ -33,6 +33,8 @@ test('should not build with invalid links', async () => {
       ['/unknown-ref', ValidationErrorType.InvalidLink],
       ['#unknown-ref', ValidationErrorType.InvalidAnchor],
       ['#anotherDiv', ValidationErrorType.InvalidAnchor],
+      ['/guides/page-with-custom-slug', ValidationErrorType.InvalidLink],
+      ['/release/@pkg/v0.2.0', ValidationErrorType.InvalidLink],
     ])
 
     expectValidationErrors(error, 'guides/example/', [
diff --git a/packages/starlight-links-validator/tests/fixtures/basics-invalid-links/src/content/docs/guides/page-with-custom-slug.md b/packages/starlight-links-validator/tests/fixtures/basics-invalid-links/src/content/docs/guides/page-with-custom-slug.md
new file mode 100644
index 0000000..eda6ec7
--- /dev/null
+++ b/packages/starlight-links-validator/tests/fixtures/basics-invalid-links/src/content/docs/guides/page-with-custom-slug.md
@@ -0,0 +1,6 @@
+---
+title: Page with custom slug
+slug: release/@pkg/v0.1.0
+---
+
+Some content
diff --git a/packages/starlight-links-validator/tests/fixtures/basics-invalid-links/src/content/docs/test.md b/packages/starlight-links-validator/tests/fixtures/basics-invalid-links/src/content/docs/test.md
index b0ef577..b1afc42 100644
--- a/packages/starlight-links-validator/tests/fixtures/basics-invalid-links/src/content/docs/test.md
+++ b/packages/starlight-links-validator/tests/fixtures/basics-invalid-links/src/content/docs/test.md
@@ -44,3 +44,8 @@ some content
     test
   </a>
 </div>
+
+## Links to page with custom slug
+
+- [Link to page not using its custom slug](/guides/page-with-custom-slug)
+- [Link to page using an invalid custom slug](/release/@pkg/v0.2.0)
diff --git a/packages/starlight-links-validator/tests/fixtures/basics-valid-links/src/content/docs/guides/page-with-custom-slug.md b/packages/starlight-links-validator/tests/fixtures/basics-valid-links/src/content/docs/guides/page-with-custom-slug.md
new file mode 100644
index 0000000..eda6ec7
--- /dev/null
+++ b/packages/starlight-links-validator/tests/fixtures/basics-valid-links/src/content/docs/guides/page-with-custom-slug.md
@@ -0,0 +1,6 @@
+---
+title: Page with custom slug
+slug: release/@pkg/v0.1.0
+---
+
+Some content
diff --git a/packages/starlight-links-validator/tests/fixtures/basics-valid-links/src/content/docs/index.md b/packages/starlight-links-validator/tests/fixtures/basics-valid-links/src/content/docs/index.md
index cffb9f8..96cc519 100644
--- a/packages/starlight-links-validator/tests/fixtures/basics-valid-links/src/content/docs/index.md
+++ b/packages/starlight-links-validator/tests/fixtures/basics-valid-links/src/content/docs/index.md
@@ -40,3 +40,7 @@ title: Index
 [ref]: /test
 [ref-with-anchor-internal]: #some-links
 [ref-with-anchor-external]: /test#title
+
+## Link to page with custom slug
+
+- [A page with custom slug](/release/@pkg/v0.1.0)