@docusaurus/mdx-loader 2.0.0-beta.0f144213d → 2.0.0-beta.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/.tsbuildinfo +1 -0
- package/lib/index.d.ts +23 -0
- package/lib/index.js +167 -0
- package/lib/remark/headings/index.d.ts +9 -0
- package/lib/remark/headings/index.js +60 -0
- package/lib/remark/toc/index.d.ts +12 -0
- package/lib/remark/toc/index.js +67 -0
- package/lib/remark/toc/search.d.ts +13 -0
- package/lib/remark/toc/search.js +66 -0
- package/lib/remark/transformImage/index.d.ts +13 -0
- package/lib/remark/transformImage/index.js +90 -0
- package/lib/remark/transformLinks/index.d.ts +14 -0
- package/lib/remark/transformLinks/index.js +106 -0
- package/lib/remark/unwrapMdxCodeBlocks/index.d.ts +9 -0
- package/lib/remark/unwrapMdxCodeBlocks/index.js +28 -0
- package/lib/remark/utils/index.d.ts +10 -0
- package/lib/remark/utils/index.js +39 -0
- package/package.json +16 -12
- package/src/deps.d.ts +29 -0
- package/src/index.ts +216 -0
- package/src/{index.d.ts → mdx-loader.d.ts} +7 -8
- package/src/remark/headings/__tests__/{index.test.js → index.test.ts} +0 -2
- package/src/remark/headings/{index.js → index.ts} +21 -16
- package/src/remark/toc/__tests__/__snapshots__/{index.test.js.snap → index.test.ts.snap} +20 -10
- package/src/remark/toc/__tests__/{index.test.js → index.test.ts} +29 -15
- package/src/remark/toc/__tests__/search.test.ts +182 -0
- package/src/remark/toc/{index.js → index.ts} +24 -16
- package/src/remark/toc/search.ts +82 -0
- package/src/remark/transformImage/__tests__/{fixtures → __fixtures__}/fail.md +0 -0
- package/src/remark/transformImage/__tests__/__fixtures__/img.md +19 -0
- package/src/remark/transformImage/__tests__/{fixtures → __fixtures__}/noUrl.md +0 -0
- package/src/remark/transformImage/__tests__/{fixtures → __fixtures__}/pathname.md +0 -0
- package/src/remark/transformImage/__tests__/{fixtures → __fixtures__/static}/img.png +0 -0
- package/src/remark/{transformLinks/__tests__/fixtures/asset.pdf → transformImage/__tests__/__fixtures__/static2/img2.png} +0 -0
- package/src/remark/transformImage/__tests__/__snapshots__/index.test.ts.snap +33 -0
- package/src/remark/transformImage/__tests__/{index.test.js → index.test.ts} +23 -19
- package/src/remark/transformImage/{index.js → index.ts} +52 -24
- package/src/remark/transformLinks/__tests__/{fixtures → __fixtures__}/asset.md +6 -0
- package/src/remark/transformLinks/__tests__/{fixtures/static/staticAsset.pdf → __fixtures__/asset.pdf} +0 -0
- package/src/remark/transformLinks/__tests__/{fixtures → __fixtures__}/noUrl.md +0 -0
- package/src/remark/transformLinks/__tests__/{fixtures → __fixtures__}/pathname.md +0 -0
- package/src/remark/transformLinks/__tests__/__fixtures__/static/staticAsset.pdf +0 -0
- package/src/remark/transformLinks/__tests__/{fixtures → __fixtures__}/static/staticAssetImage.png +0 -0
- package/src/remark/transformLinks/__tests__/__fixtures__/static2/asset2.pdf +0 -0
- package/src/remark/transformLinks/__tests__/__snapshots__/index.test.ts.snap +47 -0
- package/src/remark/transformLinks/__tests__/{index.test.js → index.test.ts} +19 -8
- package/src/remark/transformLinks/{index.js → index.ts} +66 -44
- package/src/remark/unwrapMdxCodeBlocks/__tests__/__snapshots__/{index.test.js.snap → index.test.ts.snap} +0 -0
- package/src/remark/unwrapMdxCodeBlocks/__tests__/{index.test.js → index.test.ts} +0 -0
- package/src/remark/unwrapMdxCodeBlocks/{index.js → index.ts} +11 -9
- package/src/remark/utils/index.ts +39 -0
- package/tsconfig.json +5 -5
- package/src/index.js +0 -107
- package/src/remark/toc/search.js +0 -73
- package/src/remark/transformImage/__tests__/__snapshots__/index.test.js.snap +0 -31
- package/src/remark/transformImage/__tests__/fixtures/img.md +0 -17
- package/src/remark/transformLinks/__tests__/__snapshots__/index.test.js.snap +0 -41
- package/src/remark/utils/index.js +0 -39
|
@@ -7,29 +7,33 @@
|
|
|
7
7
|
|
|
8
8
|
/* Based on remark-slug (https://github.com/remarkjs/remark-slug) and gatsby-remark-autolink-headers (https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-remark-autolink-headers) */
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
import {parseMarkdownHeadingId, createSlugger} from '@docusaurus/utils';
|
|
11
|
+
import visit, {Visitor} from 'unist-util-visit';
|
|
12
|
+
import toString from 'mdast-util-to-string';
|
|
13
|
+
import type {Transformer} from 'unified';
|
|
14
|
+
import type {Parent} from 'unist';
|
|
15
|
+
import type {Heading, Text} from 'mdast';
|
|
14
16
|
|
|
15
|
-
function headings() {
|
|
16
|
-
const transformer = (ast) => {
|
|
17
|
-
slugs
|
|
17
|
+
function headings(): Transformer {
|
|
18
|
+
const transformer: Transformer = (ast) => {
|
|
19
|
+
const slugs = createSlugger();
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
const data = headingNode.data || (headingNode.data = {});
|
|
21
|
-
const properties = data.hProperties || (data.hProperties = {})
|
|
21
|
+
const visitor: Visitor<Heading> = (headingNode) => {
|
|
22
|
+
const data = headingNode.data || (headingNode.data = {});
|
|
23
|
+
const properties = (data.hProperties || (data.hProperties = {})) as {
|
|
24
|
+
id: string;
|
|
25
|
+
};
|
|
22
26
|
let {id} = properties;
|
|
23
27
|
|
|
24
28
|
if (id) {
|
|
25
|
-
id = slugs.slug(id, true);
|
|
29
|
+
id = slugs.slug(id, {maintainCase: true});
|
|
26
30
|
} else {
|
|
27
31
|
const headingTextNodes = headingNode.children.filter(
|
|
28
32
|
({type}) => !['html', 'jsx'].includes(type),
|
|
29
33
|
);
|
|
30
34
|
const heading = toString(
|
|
31
35
|
headingTextNodes.length > 0
|
|
32
|
-
? {children: headingTextNodes}
|
|
36
|
+
? ({children: headingTextNodes} as Parent)
|
|
33
37
|
: headingNode,
|
|
34
38
|
);
|
|
35
39
|
|
|
@@ -42,8 +46,9 @@ function headings() {
|
|
|
42
46
|
// When there's an id, it is always in the last child node
|
|
43
47
|
// Sometimes heading is in multiple "parts" (** syntax creates a child node):
|
|
44
48
|
// ## part1 *part2* part3 {#id}
|
|
45
|
-
const lastNode =
|
|
46
|
-
headingNode.children
|
|
49
|
+
const lastNode = headingNode.children[
|
|
50
|
+
headingNode.children.length - 1
|
|
51
|
+
] as Text;
|
|
47
52
|
|
|
48
53
|
if (headingNode.children.length > 1) {
|
|
49
54
|
const lastNodeText = parseMarkdownHeadingId(lastNode.value).text;
|
|
@@ -63,7 +68,7 @@ function headings() {
|
|
|
63
68
|
|
|
64
69
|
data.id = id;
|
|
65
70
|
properties.id = id;
|
|
66
|
-
}
|
|
71
|
+
};
|
|
67
72
|
|
|
68
73
|
visit(ast, 'heading', visitor);
|
|
69
74
|
};
|
|
@@ -71,4 +76,4 @@ function headings() {
|
|
|
71
76
|
return transformer;
|
|
72
77
|
}
|
|
73
78
|
|
|
74
|
-
|
|
79
|
+
export default headings;
|
|
@@ -9,24 +9,29 @@ exports[`inline code should be escaped 1`] = `
|
|
|
9
9
|
{
|
|
10
10
|
value: '<code><Head>Test</Head></code>',
|
|
11
11
|
id: 'headtesthead',
|
|
12
|
-
children: []
|
|
12
|
+
children: [],
|
|
13
|
+
level: 3
|
|
13
14
|
}
|
|
14
|
-
]
|
|
15
|
+
],
|
|
16
|
+
level: 2
|
|
15
17
|
},
|
|
16
18
|
{
|
|
17
19
|
value: '<code><div /></code>',
|
|
18
20
|
id: 'div-',
|
|
19
|
-
children: []
|
|
21
|
+
children: [],
|
|
22
|
+
level: 2
|
|
20
23
|
},
|
|
21
24
|
{
|
|
22
25
|
value: '<code><div> Test </div></code>',
|
|
23
26
|
id: 'div-test-div',
|
|
24
|
-
children: []
|
|
27
|
+
children: [],
|
|
28
|
+
level: 2
|
|
25
29
|
},
|
|
26
30
|
{
|
|
27
31
|
value: '<code><div><i>Test</i></div></code>',
|
|
28
32
|
id: 'divitestidiv',
|
|
29
|
-
children: []
|
|
33
|
+
children: [],
|
|
34
|
+
level: 2
|
|
30
35
|
}
|
|
31
36
|
];
|
|
32
37
|
|
|
@@ -51,24 +56,29 @@ exports[`non text phrasing content 1`] = `
|
|
|
51
56
|
{
|
|
52
57
|
value: '<strong>Importance</strong>',
|
|
53
58
|
id: 'importance',
|
|
54
|
-
children: []
|
|
59
|
+
children: [],
|
|
60
|
+
level: 3
|
|
55
61
|
}
|
|
56
|
-
]
|
|
62
|
+
],
|
|
63
|
+
level: 2
|
|
57
64
|
},
|
|
58
65
|
{
|
|
59
66
|
value: '<del>Strikethrough</del>',
|
|
60
67
|
id: 'strikethrough',
|
|
61
|
-
children: []
|
|
68
|
+
children: [],
|
|
69
|
+
level: 2
|
|
62
70
|
},
|
|
63
71
|
{
|
|
64
72
|
value: '<i>HTML</i>',
|
|
65
73
|
id: 'html',
|
|
66
|
-
children: []
|
|
74
|
+
children: [],
|
|
75
|
+
level: 2
|
|
67
76
|
},
|
|
68
77
|
{
|
|
69
78
|
value: '<code>inline.code()</code>',
|
|
70
79
|
id: 'inlinecode',
|
|
71
|
-
children: []
|
|
80
|
+
children: [],
|
|
81
|
+
level: 2
|
|
72
82
|
}
|
|
73
83
|
];
|
|
74
84
|
|
|
@@ -12,7 +12,7 @@ import vfile from 'to-vfile';
|
|
|
12
12
|
import plugin from '../index';
|
|
13
13
|
import headings from '../../headings/index';
|
|
14
14
|
|
|
15
|
-
const processFixture = async (name, options) => {
|
|
15
|
+
const processFixture = async (name, options?) => {
|
|
16
16
|
const path = join(__dirname, 'fixtures', `${name}.md`);
|
|
17
17
|
const file = await vfile.read(path);
|
|
18
18
|
const result = await remark()
|
|
@@ -41,7 +41,8 @@ test('text content', async () => {
|
|
|
41
41
|
{
|
|
42
42
|
value: 'Endi',
|
|
43
43
|
id: 'endi',
|
|
44
|
-
children: []
|
|
44
|
+
children: [],
|
|
45
|
+
level: 3
|
|
45
46
|
},
|
|
46
47
|
{
|
|
47
48
|
value: 'Endi',
|
|
@@ -50,14 +51,17 @@ test('text content', async () => {
|
|
|
50
51
|
{
|
|
51
52
|
value: 'Yangshun',
|
|
52
53
|
id: 'yangshun',
|
|
53
|
-
children: []
|
|
54
|
+
children: [],
|
|
55
|
+
level: 3
|
|
54
56
|
}
|
|
55
|
-
]
|
|
57
|
+
],
|
|
58
|
+
level: 2
|
|
56
59
|
},
|
|
57
60
|
{
|
|
58
61
|
value: 'I ♥ unicode.',
|
|
59
62
|
id: 'i--unicode',
|
|
60
|
-
children: []
|
|
63
|
+
children: [],
|
|
64
|
+
level: 2
|
|
61
65
|
}
|
|
62
66
|
];
|
|
63
67
|
|
|
@@ -87,7 +91,8 @@ test('should export even with existing name', async () => {
|
|
|
87
91
|
{
|
|
88
92
|
value: 'Thanos',
|
|
89
93
|
id: 'thanos',
|
|
90
|
-
children: []
|
|
94
|
+
children: [],
|
|
95
|
+
level: 2
|
|
91
96
|
},
|
|
92
97
|
{
|
|
93
98
|
value: 'Tony Stark',
|
|
@@ -96,9 +101,11 @@ test('should export even with existing name', async () => {
|
|
|
96
101
|
{
|
|
97
102
|
value: 'Avengers',
|
|
98
103
|
id: 'avengers',
|
|
99
|
-
children: []
|
|
104
|
+
children: [],
|
|
105
|
+
level: 3
|
|
100
106
|
}
|
|
101
|
-
]
|
|
107
|
+
],
|
|
108
|
+
level: 2
|
|
102
109
|
}
|
|
103
110
|
];
|
|
104
111
|
|
|
@@ -121,7 +128,8 @@ test('should export with custom name', async () => {
|
|
|
121
128
|
{
|
|
122
129
|
value: 'Endi',
|
|
123
130
|
id: 'endi',
|
|
124
|
-
children: []
|
|
131
|
+
children: [],
|
|
132
|
+
level: 3
|
|
125
133
|
},
|
|
126
134
|
{
|
|
127
135
|
value: 'Endi',
|
|
@@ -130,14 +138,17 @@ test('should export with custom name', async () => {
|
|
|
130
138
|
{
|
|
131
139
|
value: 'Yangshun',
|
|
132
140
|
id: 'yangshun',
|
|
133
|
-
children: []
|
|
141
|
+
children: [],
|
|
142
|
+
level: 3
|
|
134
143
|
}
|
|
135
|
-
]
|
|
144
|
+
],
|
|
145
|
+
level: 2
|
|
136
146
|
},
|
|
137
147
|
{
|
|
138
148
|
value: 'I ♥ unicode.',
|
|
139
149
|
id: 'i--unicode',
|
|
140
|
-
children: []
|
|
150
|
+
children: [],
|
|
151
|
+
level: 2
|
|
141
152
|
}
|
|
142
153
|
];
|
|
143
154
|
|
|
@@ -171,7 +182,8 @@ test('should insert below imports', async () => {
|
|
|
171
182
|
{
|
|
172
183
|
value: 'Title',
|
|
173
184
|
id: 'title',
|
|
174
|
-
children: []
|
|
185
|
+
children: [],
|
|
186
|
+
level: 2
|
|
175
187
|
},
|
|
176
188
|
{
|
|
177
189
|
value: 'Test',
|
|
@@ -180,9 +192,11 @@ test('should insert below imports', async () => {
|
|
|
180
192
|
{
|
|
181
193
|
value: 'Again',
|
|
182
194
|
id: 'again',
|
|
183
|
-
children: []
|
|
195
|
+
children: [],
|
|
196
|
+
level: 3
|
|
184
197
|
}
|
|
185
|
-
]
|
|
198
|
+
],
|
|
199
|
+
level: 2
|
|
186
200
|
}
|
|
187
201
|
];
|
|
188
202
|
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import remark from 'remark';
|
|
9
|
+
import mdx from 'remark-mdx';
|
|
10
|
+
import search from '../search';
|
|
11
|
+
import headings from '../../headings/index';
|
|
12
|
+
|
|
13
|
+
const getHeadings = async (mdText: string) => {
|
|
14
|
+
const node = remark().parse(mdText);
|
|
15
|
+
const result = await remark().use(headings).use(mdx).run(node);
|
|
16
|
+
return search(result);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
test('should process all heading levels', async () => {
|
|
20
|
+
const md = `
|
|
21
|
+
# Alpha
|
|
22
|
+
|
|
23
|
+
## Bravo
|
|
24
|
+
|
|
25
|
+
### Charlie
|
|
26
|
+
|
|
27
|
+
#### Delta
|
|
28
|
+
|
|
29
|
+
##### Echo
|
|
30
|
+
|
|
31
|
+
###### Foxtrot
|
|
32
|
+
|
|
33
|
+
`;
|
|
34
|
+
|
|
35
|
+
expect(await getHeadings(md)).toEqual([
|
|
36
|
+
{
|
|
37
|
+
children: [
|
|
38
|
+
{
|
|
39
|
+
children: [
|
|
40
|
+
{
|
|
41
|
+
children: [
|
|
42
|
+
{
|
|
43
|
+
children: [
|
|
44
|
+
{
|
|
45
|
+
children: [],
|
|
46
|
+
id: 'foxtrot',
|
|
47
|
+
level: 6,
|
|
48
|
+
value: 'Foxtrot',
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
id: 'echo',
|
|
52
|
+
level: 5,
|
|
53
|
+
value: 'Echo',
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
id: 'delta',
|
|
57
|
+
level: 4,
|
|
58
|
+
value: 'Delta',
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
id: 'charlie',
|
|
62
|
+
level: 3,
|
|
63
|
+
value: 'Charlie',
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
id: 'bravo',
|
|
67
|
+
level: 2,
|
|
68
|
+
value: 'Bravo',
|
|
69
|
+
},
|
|
70
|
+
]);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('should process real-world well-formatted md', async () => {
|
|
74
|
+
const md = `
|
|
75
|
+
# title
|
|
76
|
+
|
|
77
|
+
some text
|
|
78
|
+
|
|
79
|
+
## section 1
|
|
80
|
+
|
|
81
|
+
some text
|
|
82
|
+
|
|
83
|
+
### subsection 1-1
|
|
84
|
+
|
|
85
|
+
some text
|
|
86
|
+
|
|
87
|
+
#### subsection 1-1-1
|
|
88
|
+
|
|
89
|
+
some text
|
|
90
|
+
|
|
91
|
+
#### subsection 1-1-2
|
|
92
|
+
|
|
93
|
+
some text
|
|
94
|
+
|
|
95
|
+
### subsection 1-2
|
|
96
|
+
|
|
97
|
+
some text
|
|
98
|
+
|
|
99
|
+
### subsection 1-3
|
|
100
|
+
|
|
101
|
+
some text
|
|
102
|
+
|
|
103
|
+
## section 2
|
|
104
|
+
|
|
105
|
+
some text
|
|
106
|
+
|
|
107
|
+
### subsection 2-1
|
|
108
|
+
|
|
109
|
+
some text
|
|
110
|
+
|
|
111
|
+
### subsection 2-1
|
|
112
|
+
|
|
113
|
+
some text
|
|
114
|
+
|
|
115
|
+
## section 3
|
|
116
|
+
|
|
117
|
+
some text
|
|
118
|
+
|
|
119
|
+
### subsection 3-1
|
|
120
|
+
|
|
121
|
+
some text
|
|
122
|
+
|
|
123
|
+
### subsection 3-2
|
|
124
|
+
|
|
125
|
+
some text
|
|
126
|
+
|
|
127
|
+
`;
|
|
128
|
+
|
|
129
|
+
expect(await getHeadings(md)).toEqual([
|
|
130
|
+
{
|
|
131
|
+
children: [
|
|
132
|
+
{
|
|
133
|
+
children: [
|
|
134
|
+
{
|
|
135
|
+
children: [],
|
|
136
|
+
id: 'subsection-1-1-1',
|
|
137
|
+
level: 4,
|
|
138
|
+
value: 'subsection 1-1-1',
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
children: [],
|
|
142
|
+
id: 'subsection-1-1-2',
|
|
143
|
+
level: 4,
|
|
144
|
+
value: 'subsection 1-1-2',
|
|
145
|
+
},
|
|
146
|
+
],
|
|
147
|
+
id: 'subsection-1-1',
|
|
148
|
+
level: 3,
|
|
149
|
+
value: 'subsection 1-1',
|
|
150
|
+
},
|
|
151
|
+
{children: [], id: 'subsection-1-2', level: 3, value: 'subsection 1-2'},
|
|
152
|
+
{children: [], id: 'subsection-1-3', level: 3, value: 'subsection 1-3'},
|
|
153
|
+
],
|
|
154
|
+
id: 'section-1',
|
|
155
|
+
level: 2,
|
|
156
|
+
value: 'section 1',
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
children: [
|
|
160
|
+
{children: [], id: 'subsection-2-1', level: 3, value: 'subsection 2-1'},
|
|
161
|
+
{
|
|
162
|
+
children: [],
|
|
163
|
+
id: 'subsection-2-1-1',
|
|
164
|
+
level: 3,
|
|
165
|
+
value: 'subsection 2-1',
|
|
166
|
+
},
|
|
167
|
+
],
|
|
168
|
+
id: 'section-2',
|
|
169
|
+
level: 2,
|
|
170
|
+
value: 'section 2',
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
children: [
|
|
174
|
+
{children: [], id: 'subsection-3-1', level: 3, value: 'subsection 3-1'},
|
|
175
|
+
{children: [], id: 'subsection-3-2', level: 3, value: 'subsection 3-2'},
|
|
176
|
+
],
|
|
177
|
+
id: 'section-3',
|
|
178
|
+
level: 2,
|
|
179
|
+
value: 'section 3',
|
|
180
|
+
},
|
|
181
|
+
]);
|
|
182
|
+
});
|
|
@@ -5,34 +5,42 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
import {parse, ParserOptions} from '@babel/parser';
|
|
9
|
+
import type {Identifier} from '@babel/types';
|
|
10
|
+
import traverse from '@babel/traverse';
|
|
11
|
+
import stringifyObject from 'stringify-object';
|
|
12
|
+
import search from './search';
|
|
13
|
+
import type {Plugin, Transformer} from 'unified';
|
|
14
|
+
import type {Node, Parent} from 'unist';
|
|
15
|
+
import type {Literal} from 'mdast';
|
|
12
16
|
|
|
13
|
-
const parseOptions = {
|
|
17
|
+
const parseOptions: ParserOptions = {
|
|
14
18
|
plugins: ['jsx'],
|
|
15
19
|
sourceType: 'module',
|
|
16
20
|
};
|
|
17
|
-
const isImport = (child) => child.type === 'import';
|
|
18
|
-
const hasImports = (index) => index > -1;
|
|
19
|
-
const isExport = (child) => child.type === 'export';
|
|
20
21
|
|
|
21
|
-
const
|
|
22
|
+
const isImport = (child: Node): child is Literal => child.type === 'import';
|
|
23
|
+
const hasImports = (index: number) => index > -1;
|
|
24
|
+
const isExport = (child: Node): child is Literal => child.type === 'export';
|
|
25
|
+
|
|
26
|
+
interface PluginOptions {
|
|
27
|
+
name?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const isTarget = (child: Literal, name: string) => {
|
|
22
31
|
let found = false;
|
|
23
32
|
const ast = parse(child.value, parseOptions);
|
|
24
33
|
traverse(ast, {
|
|
25
34
|
VariableDeclarator: (path) => {
|
|
26
|
-
if (path.node.id.name === name) {
|
|
35
|
+
if ((path.node.id as Identifier).name === name) {
|
|
27
36
|
found = true;
|
|
28
37
|
}
|
|
29
38
|
},
|
|
30
39
|
});
|
|
31
|
-
|
|
32
40
|
return found;
|
|
33
41
|
};
|
|
34
42
|
|
|
35
|
-
const getOrCreateExistingTargetIndex = (children, name) => {
|
|
43
|
+
const getOrCreateExistingTargetIndex = (children: Node[], name: string) => {
|
|
36
44
|
let importsIndex = -1;
|
|
37
45
|
let targetIndex = -1;
|
|
38
46
|
|
|
@@ -58,12 +66,12 @@ const getOrCreateExistingTargetIndex = (children, name) => {
|
|
|
58
66
|
return targetIndex;
|
|
59
67
|
};
|
|
60
68
|
|
|
61
|
-
const plugin = (options = {}) => {
|
|
69
|
+
const plugin: Plugin<[PluginOptions?]> = (options = {}) => {
|
|
62
70
|
const name = options.name || 'toc';
|
|
63
71
|
|
|
64
|
-
const transformer = (node) => {
|
|
72
|
+
const transformer: Transformer = (node) => {
|
|
65
73
|
const headings = search(node);
|
|
66
|
-
const {children} = node
|
|
74
|
+
const {children} = node as Parent<Literal>;
|
|
67
75
|
const targetIndex = getOrCreateExistingTargetIndex(children, name);
|
|
68
76
|
|
|
69
77
|
if (headings && headings.length) {
|
|
@@ -76,4 +84,4 @@ const plugin = (options = {}) => {
|
|
|
76
84
|
return transformer;
|
|
77
85
|
};
|
|
78
86
|
|
|
79
|
-
|
|
87
|
+
export default plugin;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import toString from 'mdast-util-to-string';
|
|
9
|
+
import visit, {Visitor} from 'unist-util-visit';
|
|
10
|
+
import {toValue} from '../utils';
|
|
11
|
+
import type {TOCItem} from '@docusaurus/types';
|
|
12
|
+
import type {Node} from 'unist';
|
|
13
|
+
import type {Heading} from 'mdast';
|
|
14
|
+
|
|
15
|
+
// Intermediate interface for TOC algorithm
|
|
16
|
+
interface SearchItem {
|
|
17
|
+
node: TOCItem;
|
|
18
|
+
level: number;
|
|
19
|
+
parentIndex: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
*
|
|
24
|
+
* Generate a TOC AST from the raw Markdown contents
|
|
25
|
+
*/
|
|
26
|
+
export default function search(node: Node): TOCItem[] {
|
|
27
|
+
const headings: SearchItem[] = [];
|
|
28
|
+
|
|
29
|
+
const visitor: Visitor<Heading> = (child, _index, parent) => {
|
|
30
|
+
const value = toString(child);
|
|
31
|
+
|
|
32
|
+
// depth:1 headings are titles and not included in the TOC
|
|
33
|
+
if (parent !== node || !value || child.depth < 2) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
headings.push({
|
|
38
|
+
node: {
|
|
39
|
+
value: toValue(child),
|
|
40
|
+
id: child.data!.id as string,
|
|
41
|
+
children: [],
|
|
42
|
+
level: child.depth,
|
|
43
|
+
},
|
|
44
|
+
level: child.depth,
|
|
45
|
+
parentIndex: -1,
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
visit(node, 'heading', visitor);
|
|
50
|
+
|
|
51
|
+
// Keep track of which previous index would be the current heading's direcy parent.
|
|
52
|
+
// Each entry <i> is the last index of the `headings` array at heading level <i>.
|
|
53
|
+
// We will modify these indices as we iterate through all headings.
|
|
54
|
+
// e.g. if an ### H3 was last seen at index 2, then prevIndexForLevel[3] === 2
|
|
55
|
+
// indices 0 and 1 will remain unused.
|
|
56
|
+
const prevIndexForLevel = Array(7).fill(-1);
|
|
57
|
+
|
|
58
|
+
headings.forEach((curr, currIndex) => {
|
|
59
|
+
// take the last seen index for each ancestor level. the highest
|
|
60
|
+
// index will be the direct ancestor of the current heading.
|
|
61
|
+
const ancestorLevelIndexes = prevIndexForLevel.slice(2, curr.level);
|
|
62
|
+
curr.parentIndex = Math.max(...ancestorLevelIndexes);
|
|
63
|
+
// mark that curr.level was last seen at the current index
|
|
64
|
+
prevIndexForLevel[curr.level] = currIndex;
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const rootNodeIndexes: number[] = [];
|
|
68
|
+
|
|
69
|
+
// For a given parentIndex, add each Node into that parent's `children` array
|
|
70
|
+
headings.forEach((heading, i) => {
|
|
71
|
+
if (heading.parentIndex >= 0) {
|
|
72
|
+
headings[heading.parentIndex].node.children.push(heading.node);
|
|
73
|
+
} else {
|
|
74
|
+
rootNodeIndexes.push(i);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const toc = headings
|
|
79
|
+
.filter((_, k) => rootNodeIndexes.includes(k)) // only return root nodes
|
|
80
|
+
.map((heading) => heading.node); // only return Node, no metadata
|
|
81
|
+
return toc;
|
|
82
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
 
|
|
12
|
+
|
|
13
|
+

|
|
14
|
+
|
|
15
|
+
## Heading
|
|
16
|
+
|
|
17
|
+
```md
|
|
18
|
+

|
|
19
|
+
```
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`transformImage plugin fail if image does not exist 1`] = `"Image packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/__fixtures__/static/img/doesNotExist.png or packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/__fixtures__/static2/img/doesNotExist.png used in packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/__fixtures__/fail.md not found."`;
|
|
4
|
+
|
|
5
|
+
exports[`transformImage plugin fail if image url is absent 1`] = `"Markdown image URL is mandatory in \\"packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/__fixtures__/noUrl.md\\" file"`;
|
|
6
|
+
|
|
7
|
+
exports[`transformImage plugin pathname protocol 1`] = `
|
|
8
|
+
"
|
|
9
|
+
"
|
|
10
|
+
`;
|
|
11
|
+
|
|
12
|
+
exports[`transformImage plugin transform md images to <img /> 1`] = `
|
|
13
|
+
"
|
|
14
|
+
|
|
15
|
+
<img src={require(\\"![CWD]/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[hash].[ext]&fallback=[CWD]/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} />
|
|
16
|
+
|
|
17
|
+
<img alt={\\"img\\"} src={require(\\"![CWD]/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[hash].[ext]&fallback=[CWD]/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} />
|
|
18
|
+
|
|
19
|
+
<img alt={\\"img from second static folder\\"} src={require(\\"![CWD]/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[hash].[ext]&fallback=[CWD]/node_modules/file-loader/dist/cjs.js!packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/__fixtures__/static2/img2.png\\").default} />
|
|
20
|
+
|
|
21
|
+
<img alt={\\"img from second static folder\\"} src={require(\\"![CWD]/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[hash].[ext]&fallback=[CWD]/node_modules/file-loader/dist/cjs.js!./static2/img2.png\\").default} />
|
|
22
|
+
|
|
23
|
+
<img alt={\\"img\\"} src={require(\\"![CWD]/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[hash].[ext]&fallback=[CWD]/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} title=\\"Title\\" /> <img alt={\\"img\\"} src={require(\\"![CWD]/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[hash].[ext]&fallback=[CWD]/node_modules/file-loader/dist/cjs.js!packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/__fixtures__/static/img.png\\").default} />
|
|
24
|
+
|
|
25
|
+
<img alt={\\"img with "quotes"\\"} src={require(\\"![CWD]/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[hash].[ext]&fallback=[CWD]/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} title=\\"'Quoted' title\\" />
|
|
26
|
+
|
|
27
|
+
## Heading
|
|
28
|
+
|
|
29
|
+
\`\`\`md
|
|
30
|
+

|
|
31
|
+
\`\`\`
|
|
32
|
+
"
|
|
33
|
+
`;
|