11// This file originates from https://github.com/zentered/next-product-docs on
2- // the branch "feat/cert-manager-adjustments " (commit f4fb801 ), copyright
2+ // the branch "main " (commit fdcc8b5 ), copyright
33// Zentered 2022, licensed under the Apache 2.0 license.
44
55import { visit } from 'unist-util-visit'
6+ import { resolve , sep } from 'node:path'
67
78export default function relativeLinks ( options ) {
8- if ( ! options || ! options . prefix ) {
9- throw Error ( 'Missing required "prefix" option' )
10- }
11-
12- let pathParts = [ ]
139 let extensions = [ '.mdx' , '.md' ]
14- const slug = options . slug
15-
10+ const moduleRootPath = options . rootPath
11+ const prefix = options . prefix
1612 if ( options . extensions ) {
1713 extensions = options . extensions
1814 }
1915
16+ /**
17+ * This function takes an internal url and converts it into a web url.
18+ * It handles relative and absolute paths.
19+ *
20+ * @param {* } node
21+ * @returns node
22+ */
2023 function visitor ( node ) {
21- let nodePrefix = options . prefix
22- if ( node && node . url && ! node . url . startsWith ( 'http' ) ) {
23- if ( process . env . DEBUG === 'true' ) {
24- // helps to identify "special cases" and add those to the tests
25- console . log ( node . url , options )
24+ if (
25+ node &&
26+ node . url &&
27+ ! node . url . startsWith ( 'http' ) &&
28+ ! node . url . startsWith ( 'mailto:' )
29+ ) {
30+ // keep a copy of the original node url for comparison
31+ const originalUrl = node . url
32+ let rootPath = moduleRootPath
33+
34+ if ( options . debug ) {
35+ console . log ( rootPath , node . url , options )
2636 }
2737
28- // ignore mailto: links
29- if ( node . url . startsWith ( 'mailto: ' ) ) {
30- return
38+ // remove the filename from the rootPath if it's an anchor link
39+ if ( ! node . url . startsWith ( '# ' ) ) {
40+ rootPath = rootPath . split ( '/' ) . slice ( 0 , - 1 ) . join ( '/' )
3141 }
3242
33- // handle relative paths
34- if ( node . url . startsWith ( '#' ) ) {
35- if ( slug [ 0 ] === nodePrefix ) {
36- pathParts = slug . slice ( 1 )
37- } else {
38- pathParts = slug
39- }
40- } else if ( slug && Array . isArray ( slug ) ) {
41- if ( slug [ 0 ] === nodePrefix ) {
42- slug . shift ( )
43- }
44- const depth = ( node . url . match ( / \. \. \/ / g) || [ ] ) . length
45- if ( slug . length <= 1 ) {
46- pathParts = slug
47- } else if ( depth >= slug . length ) {
48- nodePrefix = ''
49- pathParts = [ ]
50- } else {
51- const removeLast = slug . length - depth - 1
52- pathParts = slug . slice ( 0 , removeLast )
53- }
43+ // drop all extensions from root and node url
44+ for ( const ext of extensions ) {
45+ rootPath = rootPath . replace ( ext , '' )
46+ node . url = node . url . replace ( ext , '' )
5447 }
5548
56- if ( node . url . startsWith ( '/' ) ) {
57- node . url = node . url . replace ( '/' , '' )
49+ // add prefix to rootPath if it has been passed
50+ if ( prefix && ! rootPath . startsWith ( `/${ prefix } ` ) ) {
51+ rootPath = `/${ prefix } ${ rootPath } `
5852 }
5953
60- if ( node . url . startsWith ( './' ) ) {
61- node . url = node . url . replace ( './' , '' )
54+ // drop README from root and node url
55+ rootPath = rootPath . replace ( '/README' , '' )
56+ node . url = node . url . replace ( '/README' , '' )
57+
58+ // check if the depth of the node.url goes beyond the rootPath
59+ const rootPathParts = rootPath . split ( sep ) . slice ( 1 )
60+ const depth = ( originalUrl . match ( / \. \. \/ / g) || [ ] ) . length
61+ const skipPrefix = depth > 0 && rootPathParts . length === depth
62+ const relative = resolve ( rootPath , node . url )
63+ if (
64+ ! skipPrefix &&
65+ ! relative . startsWith ( `/${ prefix } ` ) &&
66+ ! originalUrl . startsWith ( '/' )
67+ ) {
68+ node . url = `/${ prefix } ${ relative } `
69+ } else {
70+ node . url = relative
6271 }
6372
64- if ( node . url . startsWith ( '../' ) ) {
65- node . url = node . url . replace ( / \. \. \/ / g, '' )
73+ if ( options . debug ) {
74+ console . log ( `rootPath: ${ rootPath } ` )
75+ console . log ( `nodeUrl: ${ originalUrl } ` )
76+ console . log ( `calculated URL: ${ relative } ` )
6677 }
6778
68- let path = ''
69- if ( pathParts ) {
70- if ( pathParts . length >= 1 ) {
71- if ( pathParts [ 0 ] !== nodePrefix ) {
72- path = nodePrefix + '/' + pathParts . join ( '/' )
73- }
74- path += '/'
75- } else {
76- if ( nodePrefix ) {
77- path = nodePrefix + '/'
78- }
79+ // add trailing slash and handle anchor link if needed
80+ if ( options . trailingSlash && originalUrl . includes ( '#' ) ) {
81+ if ( ! node . url . includes ( '/#' ) ) {
82+ node . url = node . url . replace ( '#' , '/#' )
7983 }
80- }
81-
82- node . url = `/${ path } ${ node . url } `
83-
84- if ( options . trailingSlash && node . url . includes ( '#' ) ) {
85- node . url = node . url . replace ( '#' , '/#' )
8684 } else if ( options . trailingSlash === true && ! node . url . endsWith ( '/' ) ) {
8785 node . url += '/'
8886 }
89-
90- for ( const ext of extensions ) {
91- if ( node . url . includes ( ext ) ) {
92- node . url = node . url . replace ( ext , '' )
93- }
94- }
95-
96- if ( node . url . includes ( 'README' ) ) {
97- node . url = node . url . replace ( 'README' , '' )
98- }
9987 }
10088 }
10189
@@ -104,4 +92,4 @@ export default function relativeLinks(options) {
10492 }
10593
10694 return transform
107- }
95+ }
0 commit comments