Skip to content

Commit 42c0cbe

Browse files
committed
fix(markdown): fix query parsing and absolute link fallback in linksPlugin (close #1536)
1 parent 8eb722f commit 42c0cbe

File tree

5 files changed

+52
-48
lines changed

5 files changed

+52
-48
lines changed

packages/markdown/src/plugins/linksPlugin/linksPlugin.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { isLinkExternal, normalizeRoutePath } from '@vuepress/shared'
1+
import { inferRoutePath, isLinkExternal } from '@vuepress/shared'
22
import type { PluginWithOptions } from 'markdown-it'
33
import type Token from 'markdown-it/lib/token.mjs'
44
import type { MarkdownEnv } from '../../types.js'
@@ -67,7 +67,7 @@ export const linksPlugin: PluginWithOptions<LinksPluginOptions> = (
6767

6868
// if `href` attr exists, `token.attrs` is not `null`
6969
const hrefAttr = token.attrs![hrefIndex]
70-
const hrefLink = hrefAttr[1]
70+
const hrefLink: string = hrefAttr[1]
7171

7272
// get `base` and `filePathRelative` from `env`
7373
const { base = '/', filePathRelative = null } = env
@@ -83,7 +83,7 @@ export const linksPlugin: PluginWithOptions<LinksPluginOptions> = (
8383

8484
// check if a link is an internal link
8585
const internalLinkMatch = hrefLink.match(
86-
/^((?:.*)(?:\/|\.md|\.html))(#.*)?$/,
86+
/^([^#?]*?(?:\/|\.md|\.html))([#?].*)?$/,
8787
)
8888

8989
if (!internalLinkMatch) {
@@ -97,7 +97,7 @@ export const linksPlugin: PluginWithOptions<LinksPluginOptions> = (
9797

9898
// notice that the path and hash are encoded by markdown-it
9999
const rawPath = internalLinkMatch[1]
100-
const rawHash = internalLinkMatch[2] || ''
100+
const rawHashAndQueries = internalLinkMatch[2] || ''
101101

102102
// resolve relative and absolute path
103103
const { relativePath, absolutePath } = resolvePaths(
@@ -114,16 +114,19 @@ export const linksPlugin: PluginWithOptions<LinksPluginOptions> = (
114114
// normalize markdown file path to route path
115115
// we are removing the `base` from absolute path because it should not be
116116
// passed to `<RouteLink>` or `<RouterLink>`
117-
const normalizedPath = normalizeRoutePath(
118-
absolutePath.replace(new RegExp(`^${base}`), '/'),
117+
const normalizedPath = inferRoutePath(
118+
absolutePath
119+
? absolutePath.replace(new RegExp(`^${base}`), '/')
120+
: relativePath,
119121
)
120122
// replace the original href link with the normalized path
121-
hrefAttr[1] = `${normalizedPath}${rawHash}`
123+
hrefAttr[1] = `${normalizedPath}${rawHashAndQueries}`
122124
// set `hasOpenInternalLink` to modify the ending tag
123125
hasOpenInternalLink = true
124126
} else {
125-
const normalizedPath = normalizeRoutePath(absolutePath)
126-
hrefAttr[1] = `${normalizedPath}${rawHash}`
127+
const normalizedPath = inferRoutePath(absolutePath ?? relativePath)
128+
// replace the original href link with the normalized path
129+
hrefAttr[1] = `${normalizedPath}${rawHashAndQueries}`
127130
}
128131

129132
// extract internal links for file / page existence check

packages/markdown/src/plugins/linksPlugin/resolvePaths.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const resolvePaths = (
99
base: string,
1010
filePathRelative: string | null,
1111
): {
12-
absolutePath: string
12+
absolutePath: string | null
1313
relativePath: string
1414
} => {
1515
let absolutePath: string
@@ -48,7 +48,7 @@ export const resolvePaths = (
4848
// remove leading './'
4949
relativePath = rawPath.replace(/^(?:\.\/)?(.*)$/, '$1')
5050
// just take relative link as absolute link
51-
absolutePath = relativePath
51+
absolutePath = null
5252
}
5353
}
5454

packages/markdown/src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export type MarkdownHeader = PageHeader
4848
export interface MarkdownLink {
4949
raw: string
5050
relative: string
51-
absolute: string
51+
absolute: string | null
5252
}
5353

5454
/**

packages/markdown/tests/plugins/linksPlugin.spec.ts

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -195,92 +195,92 @@ describe('@vuepress/markdown > plugins > linksPlugin', () => {
195195
{
196196
raw: 'foo.md',
197197
relative: 'foo.md',
198-
absolute: 'foo.md',
198+
absolute: null,
199199
},
200200
{
201201
raw: 'foo.md#hash',
202202
relative: 'foo.md',
203-
absolute: 'foo.md',
203+
absolute: null,
204204
},
205205
{
206206
raw: './foo.md',
207207
relative: 'foo.md',
208-
absolute: 'foo.md',
208+
absolute: null,
209209
},
210210
{
211211
raw: '../bar.md',
212212
relative: '../bar.md',
213-
absolute: '../bar.md',
213+
absolute: null,
214214
},
215215
{
216216
raw: '../bar.md#hash',
217217
relative: '../bar.md',
218-
absolute: '../bar.md',
218+
absolute: null,
219219
},
220220
{
221221
raw: './../bar.md',
222222
relative: '../bar.md',
223-
absolute: '../bar.md',
223+
absolute: null,
224224
},
225225
{
226226
raw: 'foo/bar.md',
227227
relative: 'foo/bar.md',
228-
absolute: 'foo/bar.md',
228+
absolute: null,
229229
},
230230
{
231231
raw: 'foo/bar.md#hash',
232232
relative: 'foo/bar.md',
233-
absolute: 'foo/bar.md',
233+
absolute: null,
234234
},
235235
{
236236
raw: '../foo/bar.md',
237237
relative: '../foo/bar.md',
238-
absolute: '../foo/bar.md',
238+
absolute: null,
239239
},
240240
{
241241
raw: '../foo/bar.md#hash',
242242
relative: '../foo/bar.md',
243-
absolute: '../foo/bar.md',
243+
absolute: null,
244244
},
245245
{
246246
raw: 'index.md',
247247
relative: 'index.md',
248-
absolute: 'index.md',
248+
absolute: null,
249249
},
250250
{
251251
raw: 'index.md#hash',
252252
relative: 'index.md',
253-
absolute: 'index.md',
253+
absolute: null,
254254
},
255255
{
256256
raw: './index.md',
257257
relative: 'index.md',
258-
absolute: 'index.md',
258+
absolute: null,
259259
},
260260
{
261261
raw: '../index.md',
262262
relative: '../index.md',
263-
absolute: '../index.md',
263+
absolute: null,
264264
},
265265
{
266266
raw: '../foo/bar/index.md',
267267
relative: '../foo/bar/index.md',
268-
absolute: '../foo/bar/index.md',
268+
absolute: null,
269269
},
270270
{
271271
raw: 'readme.md',
272272
relative: 'readme.md',
273-
absolute: 'readme.md',
273+
absolute: null,
274274
},
275275
{
276276
raw: '../readme.md#hash',
277277
relative: '../readme.md',
278-
absolute: '../readme.md',
278+
absolute: null,
279279
},
280280
{
281281
raw: '../foo/bar/readme.md',
282282
relative: '../foo/bar/readme.md',
283-
absolute: '../foo/bar/readme.md',
283+
absolute: null,
284284
},
285285
])
286286
})
@@ -320,92 +320,92 @@ describe('@vuepress/markdown > plugins > linksPlugin', () => {
320320
{
321321
raw: 'foo.md',
322322
relative: 'foo.md',
323-
absolute: 'foo.md',
323+
absolute: null,
324324
},
325325
{
326326
raw: 'foo.md#hash',
327327
relative: 'foo.md',
328-
absolute: 'foo.md',
328+
absolute: null,
329329
},
330330
{
331331
raw: './foo.md',
332332
relative: 'foo.md',
333-
absolute: 'foo.md',
333+
absolute: null,
334334
},
335335
{
336336
raw: '../bar.md',
337337
relative: '../bar.md',
338-
absolute: '../bar.md',
338+
absolute: null,
339339
},
340340
{
341341
raw: '../bar.md#hash',
342342
relative: '../bar.md',
343-
absolute: '../bar.md',
343+
absolute: null,
344344
},
345345
{
346346
raw: './../bar.md',
347347
relative: '../bar.md',
348-
absolute: '../bar.md',
348+
absolute: null,
349349
},
350350
{
351351
raw: 'foo/bar.md',
352352
relative: 'foo/bar.md',
353-
absolute: 'foo/bar.md',
353+
absolute: null,
354354
},
355355
{
356356
raw: 'foo/bar.md#hash',
357357
relative: 'foo/bar.md',
358-
absolute: 'foo/bar.md',
358+
absolute: null,
359359
},
360360
{
361361
raw: '../foo/bar.md',
362362
relative: '../foo/bar.md',
363-
absolute: '../foo/bar.md',
363+
absolute: null,
364364
},
365365
{
366366
raw: '../foo/bar.md#hash',
367367
relative: '../foo/bar.md',
368-
absolute: '../foo/bar.md',
368+
absolute: null,
369369
},
370370
{
371371
raw: 'index.md',
372372
relative: 'index.md',
373-
absolute: 'index.md',
373+
absolute: null,
374374
},
375375
{
376376
raw: 'index.md#hash',
377377
relative: 'index.md',
378-
absolute: 'index.md',
378+
absolute: null,
379379
},
380380
{
381381
raw: './index.md',
382382
relative: 'index.md',
383-
absolute: 'index.md',
383+
absolute: null,
384384
},
385385
{
386386
raw: '../index.md',
387387
relative: '../index.md',
388-
absolute: '../index.md',
388+
absolute: null,
389389
},
390390
{
391391
raw: '../foo/bar/index.md',
392392
relative: '../foo/bar/index.md',
393-
absolute: '../foo/bar/index.md',
393+
absolute: null,
394394
},
395395
{
396396
raw: 'readme.md',
397397
relative: 'readme.md',
398-
absolute: 'readme.md',
398+
absolute: null,
399399
},
400400
{
401401
raw: '../readme.md#hash',
402402
relative: '../readme.md',
403-
absolute: '../readme.md',
403+
absolute: null,
404404
},
405405
{
406406
raw: '../foo/bar/readme.md',
407407
relative: '../foo/bar/readme.md',
408-
absolute: '../foo/bar/readme.md',
408+
absolute: null,
409409
},
410410
])
411411
})

packages/shared/src/utils/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export * from './isLinkExternal.js'
77
export * from './isLinkHttp.js'
88
export * from './isLinkWithProtocol.js'
99
export * from './isPlainObject.js'
10+
export * from './inferRoutePath.js'
1011
export * from './normalizeRoutePath.js'
1112
export * from './omit.js'
1213
export * from './removeEndingSlash.js'

0 commit comments

Comments
 (0)