Skip to content

Commit 292e4bc

Browse files
authored
feat: support generic markdown file path reference (#509)
1 parent 5fcac1b commit 292e4bc

File tree

3 files changed

+132
-6
lines changed

3 files changed

+132
-6
lines changed

lib/markdown/link.js

+30-6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// 1. adding target="_blank" to external links
33
// 2. converting internal links to <router-link>
44

5+
const indexRE = /(.*)(index|readme).md(#?.*)$/i
6+
57
module.exports = (md, externalAttrs) => {
68
let hasOpenRouterLink = false
79
let hasOpenExternalLink = false
@@ -37,15 +39,28 @@ module.exports = (md, externalAttrs) => {
3739
const links = md.__data.links || (md.__data.links = [])
3840
links.push(to)
3941

40-
to = to
41-
.replace(/\.md$/, '.html')
42-
.replace(/\.md(#.*)$/, '.html$1')
43-
// normalize links to README/index
44-
if (/^index|readme\.html/i.test(to)) {
45-
to = '/'
42+
const indexMatch = to.match(indexRE)
43+
if (indexMatch) {
44+
const [, path, , hash] = indexMatch
45+
to = path + hash
46+
} else {
47+
to = to
48+
.replace(/\.md$/, '.html')
49+
.replace(/\.md(#.*)$/, '.html$1')
50+
}
51+
52+
// relative path usage.
53+
if (!to.startsWith('/')) {
54+
to = ensureBeginningDotSlash(to)
4655
}
56+
4757
// markdown-it encodes the uri
4858
link[1] = decodeURI(to)
59+
60+
// export the router links for testing
61+
const routerLinks = md.__data.routerLinks || (md.__data.routerLinks = [])
62+
routerLinks.push(to)
63+
4964
return Object.assign({}, token, {
5065
tag: 'router-link'
5166
})
@@ -65,3 +80,12 @@ module.exports = (md, externalAttrs) => {
6580
return self.renderToken(tokens, idx, options)
6681
}
6782
}
83+
84+
const beginningSlashRE = /^\.\//
85+
86+
function ensureBeginningDotSlash (path) {
87+
if (beginningSlashRE.test(path)) {
88+
return path
89+
}
90+
return './' + path
91+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`link should render external links correctly 1`] = `
4+
<p>
5+
<a href="https://vuejs.org/" target="_blank" rel="noopener noreferrer">vue
6+
<OutboundLink/>
7+
</a>
8+
</p>
9+
`;
10+
11+
exports[`link should render external links correctly 2`] = `
12+
<p>
13+
<a href="http://vuejs.org/" target="_blank" rel="noopener noreferrer">vue
14+
<OutboundLink/>
15+
</a>
16+
</p>
17+
`;
18+
19+
exports[`link should render external links correctly 3`] = `
20+
<p>
21+
<a href="https://google.com" target="_blank" rel="noopener noreferrer">some <strong>link</strong> with <code>code</code>
22+
<OutboundLink/>
23+
</a>
24+
</p>
25+
`;

test/markdown/link.spec.js

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { Md } from './util'
2+
import link from '@/markdown/link.js'
3+
import { dataReturnable } from '@/markdown/index.js'
4+
5+
const mdL = Md().use(link, {
6+
target: '_blank',
7+
rel: 'noopener noreferrer'
8+
})
9+
10+
dataReturnable(mdL)
11+
12+
const internalLinkAsserts = {
13+
// START abosolute path usage
14+
'/': '/',
15+
16+
'/foo/': '/foo/',
17+
'/foo/#hash': '/foo/#hash',
18+
19+
'/foo/two.md': '/foo/two.html',
20+
'/foo/two.html': '/foo/two.html',
21+
// END abosolute path usage
22+
23+
// START relative path usage
24+
'README.md': './',
25+
'./README.md': './',
26+
27+
'index.md': './',
28+
'./index.md': './',
29+
30+
'one.md': './one.html',
31+
'./one.md': './one.html',
32+
33+
'foo/README.md': './foo/',
34+
'./foo/README.md': './foo/',
35+
36+
'foo/README.md#hash': './foo/#hash',
37+
'./foo/README.md#hash': './foo/#hash',
38+
39+
'../README.md': './../',
40+
'../README.md#hash': './../#hash',
41+
42+
'../foo.md': './../foo.html',
43+
'../foo.md#hash': './../foo.html#hash',
44+
45+
'../foo/one.md': './../foo/one.html',
46+
'../foo/one.md#hash': './../foo/one.html#hash'
47+
// END relative path usage
48+
}
49+
50+
const externalLinks = [
51+
'[vue](https://vuejs.org/)',
52+
'[vue](http://vuejs.org/)',
53+
'[some **link** with `code`](https://google.com)' // #496
54+
]
55+
56+
describe('link', () => {
57+
test('should convert internal links to router links correctly', () => {
58+
for (const before in internalLinkAsserts) {
59+
const input = `[${before}](${before})`
60+
const output = mdL.render(input)
61+
const after = getCompiledLink(output)
62+
expect(after).toBe(internalLinkAsserts[before])
63+
}
64+
})
65+
66+
test('should render external links correctly', () => {
67+
for (const link of externalLinks) {
68+
const { html } = mdL.render(link)
69+
expect(html).toMatchSnapshot()
70+
}
71+
})
72+
})
73+
74+
function getCompiledLink (output) {
75+
const { data: { routerLinks }} = output
76+
return routerLinks[0]
77+
}

0 commit comments

Comments
 (0)