-
Notifications
You must be signed in to change notification settings - Fork 58
/
Copy pathprepareMDX.js
117 lines (110 loc) · 2.88 KB
/
prepareMDX.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
117
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*/
import {Children} from 'react';
// TODO: This logic could be in MDX plugins instead.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
export const PREPARE_MDX_CACHE_BREAKER = 3;
// !!! IMPORTANT !!! Bump this if you change any logic.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
export function prepareMDX(rawChildren) {
const toc = getTableOfContents(rawChildren, /* depth */ 10);
const children = wrapChildrenInMaxWidthContainers(rawChildren);
return {toc, children};
}
function wrapChildrenInMaxWidthContainers(children) {
// Auto-wrap everything except a few types into
// <MaxWidth> wrappers. Keep reusing the same
// wrapper as long as we can until we meet
// a full-width section which interrupts it.
let fullWidthTypes = [
'Sandpack',
'FullWidth',
'Illustration',
'IllustrationBlock',
'Challenges',
'Recipes',
];
let wrapQueue = [];
let finalChildren = [];
function flushWrapper(key) {
if (wrapQueue.length > 0) {
const Wrapper = 'MaxWidth';
finalChildren.push(<Wrapper key={key}>{wrapQueue}</Wrapper>);
wrapQueue = [];
}
}
function handleChild(child, key) {
if (child == null) {
return;
}
if (typeof child !== 'object') {
wrapQueue.push(child);
return;
}
if (fullWidthTypes.includes(child.type)) {
flushWrapper(key);
finalChildren.push(child);
} else {
wrapQueue.push(child);
}
}
Children.forEach(children, handleChild);
flushWrapper('last');
return finalChildren;
}
function getTableOfContents(children, depth) {
const anchors = [];
extractHeaders(children, depth, anchors);
if (anchors.length > 0) {
anchors.unshift({
url: '#',
text: 'Overview',
depth: 2,
});
}
return anchors;
}
const headerTypes = new Set([
'h1',
'h2',
'h3',
'Challenges',
'Recap',
'TeamMember',
]);
function extractHeaders(children, depth, out) {
for (const child of Children.toArray(children)) {
if (child.type && headerTypes.has(child.type)) {
let header;
if (child.type === 'Challenges') {
header = {
url: '#challenges',
depth: 2,
text: 'Challenges',
};
} else if (child.type === 'Recap') {
header = {
url: '#recap',
depth: 2,
text: 'Recap',
};
} else if (child.type === 'TeamMember') {
header = {
url: '#' + child.props.permalink,
depth: 3,
text: child.props.name,
};
} else {
header = {
url: '#' + child.props.id,
depth: (child.type && parseInt(child.type.replace('h', ''), 0)) ?? 0,
text: child.props.children,
};
}
out.push(header);
} else if (child.children && depth > 0) {
extractHeaders(child.children, depth - 1, out);
}
}
}