This repository has been archived by the owner on Sep 28, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
/
tocModule.js
116 lines (100 loc) · 2.67 KB
/
tocModule.js
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// Pulled from here, which uses an outdated version of @mdx-js/mdx
// https://github.com/frontarm/mdx-util/tree/master/packages/mdx-table-of-contents
const toJSX = require('@mdx-js/mdx/mdx-hast-to-jsx').toJSX;
function mdxTableOfContents(options = {}) {
let OldCompiler = this.Compiler;
let info;
this.Compiler = tree => {
let code = OldCompiler(tree, {}, options);
if (!info.hasTableOfContentsExport) {
code += `\nexport const tableOfContents = (components={}) => ${tableOfContentsListSerializer(
info.tableOfContents
)}\n`;
}
return code;
};
return function transformer(node) {
info = getInfo(node, options);
};
}
function getInfo(
root,
{ minTableOfContentsLevel = 1, maxTableOfContentsLevel = 6 } = {}
) {
let info = {
hasFrontMatterExport: false,
hasTableOfContentsExport: false,
tableOfContents: [],
};
let levelIds = [];
let tableOfContentsIds = {};
for (let i = 0; i < root.children.length; i++) {
let node = root.children[i];
if (
node.type === 'export' &&
node.value.indexOf('tableOfContents') !== -1
) {
info.hasTableOfContentsExport = true;
}
if (node.type === 'element' && /^h\d$/.test(node.tagName)) {
let level = parseInt(node.tagName[1]);
if (
level >= minTableOfContentsLevel &&
level <= maxTableOfContentsLevel
) {
let id = node.properties.id;
levelIds[level - 1] = id;
let parent = tableOfContentsIds[levelIds[level - 2]];
let item = {
id,
level,
title: toFragment(node.children),
children: [],
};
if (parent) {
parent.children.push(item);
} else {
info.tableOfContents.push(item);
}
tableOfContentsIds[id] = item;
}
}
}
return info;
}
function toFragment(nodes) {
if (nodes.length === 1 && nodes[0].type === 'text') {
return JSON.stringify(nodes[0].value);
} else {
return '<React.Fragment>' + nodes.map(toJSX).join('') + '</React.Fragment>';
}
}
function tableOfContentsListSerializer(nodes, indent = 0) {
return indentString(
indent,
`[
${nodes
.map(node => tableOfContentsNodeSerializer(node, indent + 2))
.join(',\n')}
]`
);
}
function tableOfContentsNodeSerializer(node, indent = 0) {
return indentString(
indent,
`{
id: ${JSON.stringify(node.id)},
level: ${node.level},
title: ${node.title},
children: ${tableOfContentsListSerializer(node.children, indent + 2)}
}`
);
}
function indentString(size, string) {
return string
.split('\n')
.map(x => ' '.repeat(size) + x)
.join('\n')
.trim();
}
module.exports = mdxTableOfContents;