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 +4 -4
- package/libs/path.ts +4 -0
- package/libs/remark.ts +12 -4
- package/libs/validation.ts +24 -6
- package/package.json +1 -1
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
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
|
-
|
|
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 {
|
package/libs/validation.ts
CHANGED
|
@@ -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(
|
|
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,
|
|
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,
|
|
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,
|
|
171
|
-
|
|
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
|