UNPKG

2.75 kBJavaScriptView Raw
1// markdown-it plugin for:
2// 1. adding target="_blank" to external links
3// 2. converting internal links to <router-link>
4
5const url = require('url')
6
7const indexRE = /(^|.*\/)(index|readme).md(#?.*)$/i
8
9module.exports = (md, externalAttrs, pageSuffix = '.html') => {
10 let hasOpenRouterLink = false
11 let hasOpenExternalLink = false
12
13 md.renderer.rules.link_open = (tokens, idx, options, env, self) => {
14 const { relativePath } = env
15 const token = tokens[idx]
16 const hrefIndex = token.attrIndex('href')
17 if (hrefIndex >= 0) {
18 const link = token.attrs[hrefIndex]
19 const href = link[1]
20 const isExternal = /^https?:/.test(href)
21 const isSourceLink = /(\/|\.md|\.html)(#.*)?$/.test(href)
22 if (isExternal) {
23 Object.entries(externalAttrs).forEach(([key, val]) => {
24 token.attrSet(key, val)
25 })
26 if (/_blank/i.test(externalAttrs['target'])) {
27 hasOpenExternalLink = true
28 }
29 } else if (isSourceLink) {
30 hasOpenRouterLink = true
31 tokens[idx] = toRouterLink(token, link, relativePath, pageSuffix)
32 }
33 }
34 return self.renderToken(tokens, idx, options)
35 }
36
37 function toRouterLink (token, link, relativePath, suffix) {
38 link[0] = 'to'
39 let to = link[1]
40
41 // convert link to filename and export it for existence check
42 const links = md.$data.links || (md.$data.links = [])
43 links.push(to)
44
45 // relative path usage.
46 if (!to.startsWith('/')) {
47 to = relativePath
48 ? url.resolve('/' + relativePath, to)
49 : ensureBeginningDotSlash(to)
50 }
51
52 const indexMatch = to.match(indexRE)
53 if (indexMatch) {
54 const [, path, , hash] = indexMatch
55 to = path + hash
56 } else {
57 to = to
58 .replace(/\.md$/, suffix)
59 .replace(/\.md(#.*)$/, `${suffix}$1`)
60 }
61
62 // markdown-it encodes the uri
63 link[1] = decodeURI(to)
64
65 // export the router links for testing
66 const routerLinks = md.$data.routerLinks || (md.$data.routerLinks = [])
67 routerLinks.push(to)
68
69 return Object.create(token, {
70 tag: { value: 'RouterLink' }
71 })
72 }
73
74 md.renderer.rules.link_close = (tokens, idx, options, env, self) => {
75 const token = tokens[idx]
76 if (hasOpenRouterLink) {
77 token.tag = 'RouterLink'
78 hasOpenRouterLink = false
79 }
80 if (hasOpenExternalLink) {
81 hasOpenExternalLink = false
82 // add OutBoundLink to the beforeend of this link if it opens in _blank.
83 return '<OutboundLink/>' + self.renderToken(tokens, idx, options)
84 }
85 return self.renderToken(tokens, idx, options)
86 }
87}
88
89const beginningSlashRE = /^\.\//
90
91function ensureBeginningDotSlash (path) {
92 if (beginningSlashRE.test(path)) {
93 return path
94 }
95 return './' + path
96}