starlight-links-validator 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.ts CHANGED
@@ -48,7 +48,7 @@ export default function starlightLinksValidatorPlugin(
48
48
  return {
49
49
  name: 'starlight-links-validator-plugin',
50
50
  hooks: {
51
- setup({ addIntegration, config: starlightConfig, logger }) {
51
+ setup({ addIntegration, astroConfig, config: starlightConfig, logger }) {
52
52
  addIntegration({
53
53
  name: 'starlight-links-validator-integration',
54
54
  hooks: {
@@ -59,12 +59,12 @@ export default function starlightLinksValidatorPlugin(
59
59
 
60
60
  updateConfig({
61
61
  markdown: {
62
- remarkPlugins: [remarkStarlightLinksValidator],
62
+ remarkPlugins: [[remarkStarlightLinksValidator, astroConfig.base]],
63
63
  },
64
64
  })
65
65
  },
66
66
  'astro:build:done': ({ dir, pages }) => {
67
- const errors = validateLinks(pages, dir, starlightConfig, options.data)
67
+ const errors = validateLinks(pages, dir, astroConfig.base, starlightConfig, options.data)
68
68
 
69
69
  logErrors(logger, errors)
70
70
 
@@ -82,7 +82,7 @@ export default function starlightLinksValidatorPlugin(
82
82
  function throwPluginError(message: string): never {
83
83
  throw new AstroError(
84
84
  message,
85
- `See the error report above for more informations.\n\nIf you believe this is a bug, please file an issue at https://github.com/HiDeoo/starlight-links-validator/issues/new/choose.`,
85
+ `See the error report above for more informations.\n\nIf you believe this is a bug, please file an issue at https://github.com/HiDeoo/starlight-links-validator/issues/new/choose`,
86
86
  )
87
87
  }
88
88
 
package/libs/path.ts CHANGED
@@ -5,3 +5,7 @@ export function ensureLeadingSlash(path: string): string {
5
5
  export function ensureTrailingSlash(path: string): string {
6
6
  return path.endsWith('/') ? path : `${path}/`
7
7
  }
8
+
9
+ export function stripLeadingSlash(path: string) {
10
+ return path.replace(/^\//, '')
11
+ }
package/libs/remark.ts CHANGED
@@ -12,15 +12,17 @@ import { toString } from 'mdast-util-to-string'
12
12
  import type { Plugin } from 'unified'
13
13
  import { visit } from 'unist-util-visit'
14
14
 
15
+ import { stripLeadingSlash } from './path'
16
+
15
17
  // All the headings keyed by file path.
16
18
  const headings: Headings = new Map()
17
19
  // All the internal links keyed by file path.
18
20
  const links: Links = new Map()
19
21
 
20
- export const remarkStarlightLinksValidator: Plugin<[], Root> = function () {
22
+ export const remarkStarlightLinksValidator: Plugin<[base: string], Root> = function (base) {
21
23
  return (tree, file) => {
22
24
  const slugger = new GitHubSlugger()
23
- const filePath = normalizeFilePath(file.history[0])
25
+ const filePath = normalizeFilePath(base, file.history[0])
24
26
 
25
27
  const fileHeadings: string[] = []
26
28
  const fileLinks: string[] = []
@@ -134,12 +136,12 @@ function isInternalLink(link: string) {
134
136
  return nodePath.isAbsolute(link) || link.startsWith('#') || link.startsWith('.')
135
137
  }
136
138
 
137
- function normalizeFilePath(filePath?: string) {
139
+ function normalizeFilePath(base: string, filePath?: string) {
138
140
  if (!filePath) {
139
141
  throw new Error('Missing file path to validate links.')
140
142
  }
141
143
 
142
- return nodePath
144
+ const path = nodePath
143
145
  .relative(nodePath.join(process.cwd(), 'src/content/docs'), filePath)
144
146
  .replace(/\.\w+$/, '')
145
147
  .replace(/index$/, '')
@@ -147,6 +149,12 @@ function normalizeFilePath(filePath?: string) {
147
149
  .split(/[/\\]/)
148
150
  .map((segment) => slug(segment))
149
151
  .join('/')
152
+
153
+ if (base !== '/') {
154
+ return nodePath.posix.join(stripLeadingSlash(base), path)
155
+ }
156
+
157
+ return path
150
158
  }
151
159
 
152
160
  function isMdxIdAttribute(attribute: MdxJsxAttribute | MdxJsxExpressionAttribute): attribute is MdxIdAttribute {
@@ -1,4 +1,5 @@
1
1
  import { statSync } from 'node:fs'
2
+ import { posix } from 'node:path'
2
3
  import { fileURLToPath } from 'node:url'
3
4
 
4
5
  import type { StarlightPlugin } from '@astrojs/starlight/types'
@@ -8,7 +9,7 @@ import { bgGreen, black, blue, dim, green, red } from 'kleur/colors'
8
9
  import type { StarlightLinksValidatorOptions } from '..'
9
10
 
10
11
  import { getFallbackHeadings, getLocaleConfig, isInconsistentLocaleLink, type LocaleConfig } from './i18n'
11
- import { ensureTrailingSlash } from './path'
12
+ import { ensureTrailingSlash, stripLeadingSlash } from './path'
12
13
  import { getValidationData, type Headings } from './remark'
13
14
 
14
15
  export const ValidationErrorType = {
@@ -21,6 +22,7 @@ export const ValidationErrorType = {
21
22
  export function validateLinks(
22
23
  pages: PageData[],
23
24
  outputDir: URL,
25
+ base: string,
24
26
  starlightConfig: StarlightUserConfig,
25
27
  options: StarlightLinksValidatorOptions,
26
28
  ): ValidationErrors {
@@ -28,13 +30,18 @@ export function validateLinks(
28
30
 
29
31
  const localeConfig = getLocaleConfig(starlightConfig)
30
32
  const { headings, links } = getValidationData()
31
- const allPages: Pages = new Set(pages.map((page) => ensureTrailingSlash(page.pathname)))
33
+ const allPages: Pages = new Set(
34
+ pages.map((page) =>
35
+ ensureTrailingSlash(base === '/' ? page.pathname : posix.join(stripLeadingSlash(base), page.pathname)),
36
+ ),
37
+ )
32
38
 
33
39
  const errors: ValidationErrors = new Map()
34
40
 
35
41
  for (const [filePath, fileLinks] of links) {
36
42
  for (const link of fileLinks) {
37
43
  const validationContext: ValidationContext = {
44
+ base,
38
45
  errors,
39
46
  filePath,
40
47
  headings,
@@ -94,7 +101,7 @@ export function logErrors(pluginLogger: AstroIntegrationLogger, errors: Validati
94
101
  * Validate a link to another internal page that may or may not have a hash.
95
102
  */
96
103
  function validateLink(context: ValidationContext) {
97
- const { errors, filePath, link, localeConfig, options, outputDir, pages } = context
104
+ const { errors, filePath, link, localeConfig, options, pages } = context
98
105
 
99
106
  const sanitizedLink = link.replace(/^\//, '')
100
107
  const segments = sanitizedLink.split('#')
@@ -114,7 +121,7 @@ function validateLink(context: ValidationContext) {
114
121
  return
115
122
  }
116
123
 
117
- if (isValidAsset(path, outputDir)) {
124
+ if (isValidAsset(path, context)) {
118
125
  return
119
126
  }
120
127
 
@@ -167,8 +174,18 @@ function validateSelfAnchor({ errors, link, filePath, headings }: ValidationCont
167
174
  /**
168
175
  * Check if a link is a valid asset in the build output directory.
169
176
  */
170
- function isValidAsset(path: string, outputDir: URL) {
171
- const filePath = fileURLToPath(new URL(path, outputDir))
177
+ function isValidAsset(path: string, context: ValidationContext) {
178
+ if (context.base !== '/') {
179
+ const base = stripLeadingSlash(context.base)
180
+
181
+ if (path.startsWith(base)) {
182
+ path = path.replace(new RegExp(`^${stripLeadingSlash(base)}/?`), '')
183
+ } else {
184
+ return false
185
+ }
186
+ }
187
+
188
+ const filePath = fileURLToPath(new URL(path, context.outputDir))
172
189
 
173
190
  try {
174
191
  const stats = statSync(filePath)
@@ -207,6 +224,7 @@ interface PageData {
207
224
  type Pages = Set<PageData['pathname']>
208
225
 
209
226
  interface ValidationContext {
227
+ base: string
210
228
  errors: ValidationErrors
211
229
  filePath: string
212
230
  headings: Headings
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "starlight-links-validator",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "license": "MIT",
5
5
  "description": "Starlight plugin to validate internal links.",
6
6
  "author": "HiDeoo <github@hideoo.dev> (https://hideoo.dev)",