starlight-links-validator 0.6.0 → 0.7.0
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 +1 -1
- package/libs/validation.ts +24 -12
- package/package.json +1 -1
package/index.ts
CHANGED
|
@@ -64,7 +64,7 @@ export default function starlightLinksValidatorPlugin(
|
|
|
64
64
|
})
|
|
65
65
|
},
|
|
66
66
|
'astro:build:done': ({ dir, pages }) => {
|
|
67
|
-
const errors = validateLinks(pages, dir, astroConfig
|
|
67
|
+
const errors = validateLinks(pages, dir, astroConfig, starlightConfig, options.data)
|
|
68
68
|
|
|
69
69
|
logErrors(logger, errors)
|
|
70
70
|
|
package/libs/validation.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { posix } from 'node:path'
|
|
|
3
3
|
import { fileURLToPath } from 'node:url'
|
|
4
4
|
|
|
5
5
|
import type { StarlightPlugin } from '@astrojs/starlight/types'
|
|
6
|
-
import type { AstroIntegrationLogger } from 'astro'
|
|
6
|
+
import type { AstroConfig, AstroIntegrationLogger } from 'astro'
|
|
7
7
|
import { bgGreen, black, blue, dim, green, red } from 'kleur/colors'
|
|
8
8
|
|
|
9
9
|
import type { StarlightLinksValidatorOptions } from '..'
|
|
@@ -17,12 +17,13 @@ export const ValidationErrorType = {
|
|
|
17
17
|
InvalidAnchor: 'invalid anchor',
|
|
18
18
|
InvalidLink: 'invalid link',
|
|
19
19
|
RelativeLink: 'relative link',
|
|
20
|
+
TrailingSlash: 'trailing slash',
|
|
20
21
|
} as const
|
|
21
22
|
|
|
22
23
|
export function validateLinks(
|
|
23
24
|
pages: PageData[],
|
|
24
25
|
outputDir: URL,
|
|
25
|
-
|
|
26
|
+
astroConfig: AstroConfig,
|
|
26
27
|
starlightConfig: StarlightUserConfig,
|
|
27
28
|
options: StarlightLinksValidatorOptions,
|
|
28
29
|
): ValidationErrors {
|
|
@@ -33,7 +34,9 @@ export function validateLinks(
|
|
|
33
34
|
const allPages: Pages = new Set(
|
|
34
35
|
pages.map((page) =>
|
|
35
36
|
ensureTrailingSlash(
|
|
36
|
-
base === '/'
|
|
37
|
+
astroConfig.base === '/'
|
|
38
|
+
? stripLeadingSlash(page.pathname)
|
|
39
|
+
: posix.join(stripLeadingSlash(astroConfig.base), page.pathname),
|
|
37
40
|
),
|
|
38
41
|
),
|
|
39
42
|
)
|
|
@@ -43,7 +46,7 @@ export function validateLinks(
|
|
|
43
46
|
for (const [filePath, fileLinks] of links) {
|
|
44
47
|
for (const link of fileLinks) {
|
|
45
48
|
const validationContext: ValidationContext = {
|
|
46
|
-
|
|
49
|
+
astroConfig,
|
|
47
50
|
errors,
|
|
48
51
|
filePath,
|
|
49
52
|
headings,
|
|
@@ -103,12 +106,12 @@ export function logErrors(pluginLogger: AstroIntegrationLogger, errors: Validati
|
|
|
103
106
|
* Validate a link to another internal page that may or may not have a hash.
|
|
104
107
|
*/
|
|
105
108
|
function validateLink(context: ValidationContext) {
|
|
106
|
-
const { errors, filePath, link, localeConfig, options, pages } = context
|
|
109
|
+
const { astroConfig, errors, filePath, link, localeConfig, options, pages } = context
|
|
107
110
|
|
|
108
111
|
const sanitizedLink = link.replace(/^\//, '')
|
|
109
112
|
const segments = sanitizedLink.split('#')
|
|
110
113
|
|
|
111
|
-
|
|
114
|
+
const path = segments[0]
|
|
112
115
|
const hash = segments[1]
|
|
113
116
|
|
|
114
117
|
if (path === undefined) {
|
|
@@ -127,10 +130,10 @@ function validateLink(context: ValidationContext) {
|
|
|
127
130
|
return
|
|
128
131
|
}
|
|
129
132
|
|
|
130
|
-
|
|
133
|
+
const sanitizedPath = ensureTrailingSlash(path)
|
|
131
134
|
|
|
132
|
-
const isValidPage = pages.has(
|
|
133
|
-
const fileHeadings = getFileHeadings(
|
|
135
|
+
const isValidPage = pages.has(sanitizedPath)
|
|
136
|
+
const fileHeadings = getFileHeadings(sanitizedPath, context)
|
|
134
137
|
|
|
135
138
|
if (!isValidPage || !fileHeadings) {
|
|
136
139
|
addError(errors, filePath, link, ValidationErrorType.InvalidLink)
|
|
@@ -144,6 +147,15 @@ function validateLink(context: ValidationContext) {
|
|
|
144
147
|
|
|
145
148
|
if (hash && !fileHeadings.includes(hash)) {
|
|
146
149
|
addError(errors, filePath, link, ValidationErrorType.InvalidAnchor)
|
|
150
|
+
return
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (
|
|
154
|
+
(astroConfig.trailingSlash === 'always' && !path.endsWith('/')) ||
|
|
155
|
+
(astroConfig.trailingSlash === 'never' && path.endsWith('/'))
|
|
156
|
+
) {
|
|
157
|
+
addError(errors, filePath, link, ValidationErrorType.TrailingSlash)
|
|
158
|
+
return
|
|
147
159
|
}
|
|
148
160
|
}
|
|
149
161
|
|
|
@@ -177,8 +189,8 @@ function validateSelfAnchor({ errors, link, filePath, headings }: ValidationCont
|
|
|
177
189
|
* Check if a link is a valid asset in the build output directory.
|
|
178
190
|
*/
|
|
179
191
|
function isValidAsset(path: string, context: ValidationContext) {
|
|
180
|
-
if (context.base !== '/') {
|
|
181
|
-
const base = stripLeadingSlash(context.base)
|
|
192
|
+
if (context.astroConfig.base !== '/') {
|
|
193
|
+
const base = stripLeadingSlash(context.astroConfig.base)
|
|
182
194
|
|
|
183
195
|
if (path.startsWith(base)) {
|
|
184
196
|
path = path.replace(new RegExp(`^${stripLeadingSlash(base)}/?`), '')
|
|
@@ -226,7 +238,7 @@ interface PageData {
|
|
|
226
238
|
type Pages = Set<PageData['pathname']>
|
|
227
239
|
|
|
228
240
|
interface ValidationContext {
|
|
229
|
-
|
|
241
|
+
astroConfig: AstroConfig
|
|
230
242
|
errors: ValidationErrors
|
|
231
243
|
filePath: string
|
|
232
244
|
headings: Headings
|