1
+ import { getHostForTabRouteFile } from '@/features/tabs' ;
1
2
import type { Root } from 'hast' ;
2
3
import path from 'path' ;
3
- import { lodash , winPath } from 'umi/plugin-utils' ;
4
+ import { lodash , logger , winPath } from 'umi/plugin-utils' ;
4
5
import type { Transformer } from 'unified' ;
5
6
import url from 'url' ;
6
7
import type { IMdTransformerOptions } from '.' ;
@@ -13,10 +14,7 @@ let SKIP: typeof import('unist-util-visit').SKIP;
13
14
( { visit, SKIP } = await import ( 'unist-util-visit' ) ) ;
14
15
} ) ( ) ;
15
16
16
- type IRehypeLinkOptions = Pick <
17
- IMdTransformerOptions ,
18
- 'fileAbsPath' | 'routers'
19
- > ;
17
+ type IRehypeLinkOptions = Pick < IMdTransformerOptions , 'fileAbsPath' | 'routes' > ;
20
18
21
19
export default function rehypeLink (
22
20
opts : IRehypeLinkOptions ,
@@ -26,22 +24,55 @@ export default function rehypeLink(
26
24
if ( node . tagName === 'a' && typeof node . properties ?. href === 'string' ) {
27
25
const href = node . properties . href ;
28
26
const parsedUrl = url . parse ( href ) ;
27
+ const hostAbsPath = getHostForTabRouteFile ( opts . fileAbsPath ) ;
29
28
30
29
// handle internal link
31
30
if ( parsedUrl . hostname ) return SKIP ;
32
31
33
- // handle markdown link
34
32
if ( / \. m d $ / i. test ( parsedUrl . pathname ! ) ) {
35
- const { routers } = opts ;
33
+ // handle markdown link
34
+ const { routes } = opts ;
36
35
const absPath = winPath (
37
- path . resolve ( opts . fileAbsPath , '..' , parsedUrl . pathname ! ) ,
36
+ path . resolve ( hostAbsPath , '..' , parsedUrl . pathname ! ) ,
38
37
) ;
39
38
40
- Object . keys ( routers ) . forEach ( ( key ) => {
41
- if ( routers [ key ] . file === absPath ) {
42
- parsedUrl . pathname = routers [ key ] . absPath ;
39
+ Object . keys ( routes ) . forEach ( ( key ) => {
40
+ if ( routes [ key ] . file === absPath ) {
41
+ parsedUrl . pathname = routes [ key ] . absPath ;
43
42
}
44
43
} ) ;
44
+ } else if (
45
+ / ^ \. ? \. \/ / . test ( parsedUrl . pathname ! ) ||
46
+ / ^ ( \w + : ) ? \/ \/ / . test ( parsedUrl . pathname ! )
47
+ ) {
48
+ // handle relative link
49
+ // transform relative link to absolute link
50
+ // because react-router@6 and HTML href are different in processing relative link
51
+ // e.g. in /a page, <Link to="./b">b</Link> will be resolved to /a/b in react-router@6
52
+ // but will be resolved to /b in <a href="./b">b</a>
53
+ const routes = Object . values ( opts . routes ) ;
54
+ const basePath = routes . find (
55
+ ( route ) => route . file === hostAbsPath ,
56
+ ) ! . absPath ;
57
+ const htmlTargetPath = url . resolve ( basePath , parsedUrl . pathname ! ) ;
58
+ const rr6TargetPath = winPath (
59
+ path . resolve ( basePath , parsedUrl . pathname ! ) ,
60
+ ) ;
61
+
62
+ // use html way first
63
+ parsedUrl . pathname = htmlTargetPath ;
64
+
65
+ // warn if user already use react-router@6 way
66
+ if (
67
+ routes . every ( ( route ) => route . absPath !== htmlTargetPath ) &&
68
+ routes . some ( ( route ) => route . absPath === rr6TargetPath )
69
+ ) {
70
+ parsedUrl . pathname = rr6TargetPath ;
71
+ logger . warn (
72
+ `Detected ambiguous link \`${ href } \` in \`${ opts . fileAbsPath } \`, please use \`./xxx.md\` file path instead of normal relative path, dumi will deprecate this behavior in the future.
73
+ See more: https://github.com/umijs/dumi/pull/1491` ,
74
+ ) ;
75
+ }
45
76
}
46
77
47
78
parent ! . children . splice ( i ! , 1 , {
0 commit comments