/
mdast.ts
85 lines (71 loc) · 1.95 KB
/
mdast.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
import vfile from 'to-vfile'
import unified from 'unified'
import remark from 'remark-parse'
import matter from 'remark-frontmatter'
import slug from 'remark-slug'
import parseFrontmatter from 'remark-parse-yaml'
import find from 'unist-util-find'
import is from 'unist-util-is'
import visit from 'unist-util-visit'
import humanize from 'humanize-string'
import flatten from 'lodash/flatten'
import get from 'lodash/get'
export const parseMdx = (file: string, plugins: any[]): Promise<string> => {
const raw = vfile.readSync(file, 'utf-8')
const parser = unified()
.use(remark, { type: 'yaml', marker: '-' })
.use(matter)
.use(parseFrontmatter)
.use(slug)
for (const plugin of plugins) {
const [item, opts = {}] = Array.isArray(plugin) ? plugin : [plugin]
parser.use(item, opts)
}
return parser.run(parser.parse(raw))
}
const getChildValue = (children: any) =>
children.map((child: any) =>
child.children ? getChildValue(child.children) : child.value
)
const valueFromHeading = (node: any) => {
const children = get(node, 'children')
const slug = get(node, 'data.id')
if (Array.isArray(children)) {
return flatten(getChildValue(children))
.filter(Boolean)
.join(' ')
}
return humanize(slug)
}
function extractAst<T>(
callback: (node: any) => T,
type: string
): (ast: any) => T[] {
return ast => {
const results: T[] = []
visit(ast, type, (node: any) => {
results.push(callback(node))
})
return results
}
}
export interface Heading {
depth: number
slug: string
value: string
}
export const headingsFromAst = extractAst<Heading>(
(node: any) => ({
slug: get(node, 'data.id'),
depth: get(node, 'depth'),
value: valueFromHeading(node),
}),
'heading'
)
export interface ParsedData {
[key: string]: any
}
export const getParsedData = (ast: any): ParsedData => {
const node = find(ast, (node: any) => is(node, 'yaml'))
return get(node, `data.parsedValue`) || {}
}