-
Notifications
You must be signed in to change notification settings - Fork 10.3k
/
remark-infer-toc-meta.ts
95 lines (77 loc) · 2.01 KB
/
remark-infer-toc-meta.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
92
93
94
95
import type { Plugin } from "unified"
import type { Node } from "unist"
import type {
BlockContent,
DefinitionContent,
ListItem,
TableCell,
} from "mdast"
import type { IMdxVFile } from "./types"
import type { Options, toc } from "mdast-util-toc"
import type { visit } from "unist-util-visit"
interface ITocNodeEntry {
url?: string
title?: string
}
type TocNodeType =
| ITocNodeEntry
| {
items: Array<TocNodeType>
}
interface IRemarkTocOptions {
maxDepth?: Options["maxDepth"]
toc: typeof toc
visit: typeof visit
}
const remarkInferTocMeta: Plugin<[IRemarkTocOptions]> = options => {
const { toc, visit, maxDepth }: IRemarkTocOptions = {
maxDepth: 6,
...options,
}
const processToC = (
node: BlockContent | DefinitionContent | ListItem | null,
current: TocNodeType
): TocNodeType => {
if (!node) {
return {}
}
switch (node.type) {
case `paragraph`: {
const typedCurrent = current as ITocNodeEntry
visit(node, item => {
if (item.type === `link`) {
typedCurrent.url = item.url
}
if (item.type === `text`) {
typedCurrent.title = item.value
}
})
return current
}
case `list`: {
const typedCurrent = current as { items: Array<TocNodeType> }
typedCurrent.items = node.children.map(item => processToC(item, {}))
return typedCurrent
}
case `listItem`: {
if (node.children.length) {
const heading = processToC(node.children[0], {})
if (node.children.length > 1) {
processToC(node.children[1], heading)
}
return heading
}
}
}
return {}
}
return (tree: Node, file): void => {
const generatedToC = toc(tree as TableCell, { maxDepth })
const mdxFile: IMdxVFile = file
if (!mdxFile.data.meta) {
mdxFile.data.meta = {}
}
mdxFile.data.meta.toc = processToC(generatedToC.map, {})
}
}
export default remarkInferTocMeta