Skip to content

Commit

Permalink
fix: fixes validation issues when using the Astro base option
Browse files Browse the repository at this point in the history
  • Loading branch information
HiDeoo committed Dec 14, 2023
1 parent 073755b commit 60f317a
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 9 deletions.
6 changes: 3 additions & 3 deletions packages/starlight-links-validator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export default function starlightLinksValidatorPlugin(
return {
name: 'starlight-links-validator-plugin',
hooks: {
setup({ addIntegration, config: starlightConfig, logger }) {
setup({ addIntegration, astroConfig, config: starlightConfig, logger }) {
addIntegration({
name: 'starlight-links-validator-integration',
hooks: {
Expand All @@ -59,12 +59,12 @@ export default function starlightLinksValidatorPlugin(

updateConfig({
markdown: {
remarkPlugins: [remarkStarlightLinksValidator],
remarkPlugins: [[remarkStarlightLinksValidator, astroConfig.base]],
},
})
},
'astro:build:done': ({ dir, pages }) => {
const errors = validateLinks(pages, dir, starlightConfig, options.data)
const errors = validateLinks(pages, dir, astroConfig.base, starlightConfig, options.data)

logErrors(logger, errors)

Expand Down
4 changes: 4 additions & 0 deletions packages/starlight-links-validator/libs/path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ export function ensureLeadingSlash(path: string): string {
export function ensureTrailingSlash(path: string): string {
return path.endsWith('/') ? path : `${path}/`
}

export function stripLeadingSlash(path: string) {
return path.replace(/^\//, '')
}
16 changes: 12 additions & 4 deletions packages/starlight-links-validator/libs/remark.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,17 @@ import { toString } from 'mdast-util-to-string'
import type { Plugin } from 'unified'
import { visit } from 'unist-util-visit'

import { stripLeadingSlash } from './path'

// All the headings keyed by file path.
const headings: Headings = new Map()
// All the internal links keyed by file path.
const links: Links = new Map()

export const remarkStarlightLinksValidator: Plugin<[], Root> = function () {
export const remarkStarlightLinksValidator: Plugin<[base: string], Root> = function (base) {
return (tree, file) => {
const slugger = new GitHubSlugger()
const filePath = normalizeFilePath(file.history[0])
const filePath = normalizeFilePath(base, file.history[0])

const fileHeadings: string[] = []
const fileLinks: string[] = []
Expand Down Expand Up @@ -134,19 +136,25 @@ function isInternalLink(link: string) {
return nodePath.isAbsolute(link) || link.startsWith('#') || link.startsWith('.')
}

function normalizeFilePath(filePath?: string) {
function normalizeFilePath(base: string, filePath?: string) {
if (!filePath) {
throw new Error('Missing file path to validate links.')
}

return nodePath
const path = nodePath
.relative(nodePath.join(process.cwd(), 'src/content/docs'), filePath)
.replace(/\.\w+$/, '')
.replace(/index$/, '')
.replace(/[/\\]?$/, '/')
.split(/[/\\]/)
.map((segment) => slug(segment))
.join('/')

if (base !== '/') {
return nodePath.join(stripLeadingSlash(base), path)
}

return path
}

function isMdxIdAttribute(attribute: MdxJsxAttribute | MdxJsxExpressionAttribute): attribute is MdxIdAttribute {
Expand Down
10 changes: 8 additions & 2 deletions packages/starlight-links-validator/libs/validation.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { statSync } from 'node:fs'
import { join } from 'node:path'
import { fileURLToPath } from 'node:url'

import type { StarlightPlugin } from '@astrojs/starlight/types'
Expand All @@ -8,7 +9,7 @@ import { bgGreen, black, blue, dim, green, red } from 'kleur/colors'
import type { StarlightLinksValidatorOptions } from '..'

import { getFallbackHeadings, getLocaleConfig, isInconsistentLocaleLink, type LocaleConfig } from './i18n'
import { ensureTrailingSlash } from './path'
import { ensureTrailingSlash, stripLeadingSlash } from './path'
import { getValidationData, type Headings } from './remark'

export const ValidationErrorType = {
Expand All @@ -21,14 +22,19 @@ export const ValidationErrorType = {
export function validateLinks(
pages: PageData[],
outputDir: URL,
base: string,
starlightConfig: StarlightUserConfig,
options: StarlightLinksValidatorOptions,
): ValidationErrors {
process.stdout.write(`\n${bgGreen(black(` validating links `))}\n`)

const localeConfig = getLocaleConfig(starlightConfig)
const { headings, links } = getValidationData()
const allPages: Pages = new Set(pages.map((page) => ensureTrailingSlash(page.pathname)))
const allPages: Pages = new Set(
pages.map((page) =>
ensureTrailingSlash(base === '/' ? page.pathname : join(stripLeadingSlash(base), page.pathname)),
),
)

const errors: ValidationErrors = new Map()

Expand Down
26 changes: 26 additions & 0 deletions packages/starlight-links-validator/tests/base-path.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { expect, test } from 'vitest'

import { ValidationErrorType } from '../libs/validation'

import { expectValidationErrorCount, expectValidationErrors, loadFixture } from './utils'

test('should validate links when the `base` Astro option is set', async () => {
expect.assertions(2)

try {
await loadFixture('base-path')
} catch (error) {
expectValidationErrorCount(error, 8, 1)

expectValidationErrors(error, 'test/test/', [
['/guides/example', ValidationErrorType.InvalidLink],
['/guides/example/', ValidationErrorType.InvalidLink],
['/guides/example#description', ValidationErrorType.InvalidLink],
['/guides/example/#description', ValidationErrorType.InvalidLink],
['/unknown', ValidationErrorType.InvalidLink],
['/unknown/', ValidationErrorType.InvalidLink],
['/test/guides/example#unknown', ValidationErrorType.InvalidAnchor],
['/test/guides/example/#unknown', ValidationErrorType.InvalidAnchor],
])
}
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import starlight from '@astrojs/starlight'
import { defineConfig } from 'astro/config'

import starlightLinksValidator from '../..'

export default defineConfig({
base: '/test',
integrations: [
starlight({
plugins: [starlightLinksValidator()],
title: 'Starlight Links Validator Tests - trailing always',
}),
],
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
title: Example
---

## Description

This is an example page.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
title: Test
---

# Some links

- [External link](https://starlight.astro.build/)

- [Example page](/test/guides/example)
- [Example page](/test/guides/example/)

- [Example page with hash](/test/guides/example#description)
- [Example page with hash](/test/guides/example/#description)

- [Example page with missing base](/guides/example)
- [Example page with missing base](/guides/example/)

- [Example page with missing base and hash](/guides/example#description)
- [Example page with missing base and hash](/guides/example/#description)

- [Unknown page](/unknown)
- [Unknown page](/unknown/)

- [Example page with unknown hash](/test/guides/example#unknown)
- [Example page with unknown hash](/test/guides/example/#unknown)

0 comments on commit 60f317a

Please sign in to comment.