-
-
Notifications
You must be signed in to change notification settings - Fork 620
/
markdown.ts
91 lines (83 loc) · 2.62 KB
/
markdown.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import { parseMarkdown } from '@nuxtjs/mdc/dist/runtime'
import { type State } from 'mdast-util-to-hast'
import { normalizeUri } from 'micromark-util-sanitize-uri'
import { type Properties, type Element } from 'hast'
import { type Link } from 'mdast'
import { isRelative } from 'ufo'
import type { MarkdownOptions, MarkdownPlugin, MarkdownParsedContent } from '../types'
import { defineTransformer } from './utils'
import { generatePath } from './path-meta'
export default defineTransformer({
name: 'markdown',
extensions: ['.md'],
parse: async (_id, content, options = {}) => {
const config = { ...options } as MarkdownOptions
config.rehypePlugins = await importPlugins(config.rehypePlugins)
config.remarkPlugins = await importPlugins(config.remarkPlugins)
const parsed = await parseMarkdown(content as string, {
highlight: options.highlight,
remark: {
plugins: config.remarkPlugins
},
rehype: {
options: {
handlers: {
link: link as any
}
},
plugins: config.rehypePlugins
},
toc: config.toc
})
return <MarkdownParsedContent> {
...parsed.data,
excerpt: parsed.excerpt,
body: {
...parsed.body,
toc: parsed.toc
},
_type: 'markdown',
_id
}
}
})
async function importPlugins (plugins: Record<string, false | MarkdownPlugin> = {}) {
const resolvedPlugins: Record<string, false | MarkdownPlugin & { instance: any }> = {}
for (const [name, plugin] of Object.entries(plugins)) {
if (plugin) {
resolvedPlugins[name] = {
instance: plugin.instance || await import(/* @vite-ignore */ name).then(m => m.default || m),
options: plugin
}
} else {
resolvedPlugins[name] = false
}
}
return resolvedPlugins
}
function link (state: State, node: Link & { attributes?: Properties }) {
const properties: Properties = {
...((node.attributes || {})),
href: normalizeUri(normalizeLink(node.url))
}
if (node.title !== null && node.title !== undefined) {
properties.title = node.title
}
const result: Element = {
type: 'element',
tagName: 'a',
properties,
children: state.all(node)
}
state.patch(node, result)
return state.applyData(node, result)
}
function normalizeLink (link: string) {
const match = link.match(/#.+$/)
const hash = match ? match[0] : ''
if (link.replace(/#.+$/, '').endsWith('.md') && (isRelative(link) || (!/^https?/.test(link) && !link.startsWith('/')))) {
return (generatePath(link.replace('.md' + hash, ''), { forceLeadingSlash: false }) + hash)
} else {
return link
}
}