@docusaurus/mdx-loader 2.0.0-beta.7babfe036 → 2.0.0-beta.8
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 +12 -0
- package/lib/index.js +161 -0
- package/lib/remark/headings/index.d.ts +9 -0
- package/lib/remark/headings/index.js +62 -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 +80 -0
- package/lib/remark/transformLinks/index.d.ts +13 -0
- package/lib/remark/transformLinks/index.js +104 -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 +13 -8
- package/src/index.ts +200 -0
- package/src/remark/headings/__tests__/{index.test.js → index.test.ts} +0 -2
- package/src/remark/headings/{index.js → index.ts} +22 -14
- 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__/__snapshots__/{index.test.js.snap → index.test.ts.snap} +0 -0
- package/src/remark/transformImage/__tests__/{index.test.js → index.test.ts} +0 -0
- package/src/remark/transformImage/{index.js → index.ts} +31 -21
- package/src/remark/transformLinks/__tests__/__snapshots__/{index.test.js.snap → index.test.ts.snap} +5 -1
- package/src/remark/transformLinks/__tests__/fixtures/asset.md +4 -0
- package/src/remark/transformLinks/__tests__/{index.test.js → index.test.ts} +0 -0
- package/src/remark/transformLinks/{index.js → index.ts} +62 -39
- 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/src/types.d.ts +40 -0
- package/tsconfig.json +4 -3
- package/src/index.d.ts +0 -19
- package/src/index.js +0 -107
- package/src/remark/toc/search.js +0 -73
- package/src/remark/utils/index.js +0 -39
|
@@ -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
|
+
}
|
package/src/remark/transformImage/__tests__/__snapshots__/{index.test.js.snap → index.test.ts.snap}
RENAMED
|
File without changes
|
|
File without changes
|
|
@@ -5,26 +5,35 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
import visit from 'unist-util-visit';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import url from 'url';
|
|
11
|
+
import fs from 'fs-extra';
|
|
12
|
+
import escapeHtml from 'escape-html';
|
|
13
|
+
import {getFileLoaderUtils} from '@docusaurus/core/lib/webpack/utils';
|
|
14
|
+
import {
|
|
15
15
|
posixPath,
|
|
16
16
|
escapePath,
|
|
17
17
|
toMessageRelativeFilePath,
|
|
18
|
-
}
|
|
18
|
+
} from '@docusaurus/utils';
|
|
19
|
+
import type {Plugin, Transformer} from 'unified';
|
|
20
|
+
import type {Image, Literal} from 'mdast';
|
|
19
21
|
|
|
20
22
|
const {
|
|
21
23
|
loaders: {inlineMarkdownImageFileLoader},
|
|
22
24
|
} = getFileLoaderUtils();
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
interface PluginOptions {
|
|
27
|
+
filePath: string;
|
|
28
|
+
staticDir: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const createJSX = (node: Image, pathUrl: string) => {
|
|
25
32
|
const jsxNode = node;
|
|
26
|
-
jsxNode.type = 'jsx';
|
|
27
|
-
jsxNode.value = `<img ${
|
|
33
|
+
(jsxNode as unknown as Literal).type = 'jsx';
|
|
34
|
+
(jsxNode as unknown as Literal).value = `<img ${
|
|
35
|
+
node.alt ? `alt={"${escapeHtml(node.alt)}"} ` : ''
|
|
36
|
+
}${
|
|
28
37
|
node.url
|
|
29
38
|
? `src={require("${inlineMarkdownImageFileLoader}${escapePath(
|
|
30
39
|
pathUrl,
|
|
@@ -33,7 +42,7 @@ const createJSX = (node, pathUrl) => {
|
|
|
33
42
|
}${node.title ? ` title="${escapeHtml(node.title)}"` : ''} />`;
|
|
34
43
|
|
|
35
44
|
if (jsxNode.url) {
|
|
36
|
-
delete jsxNode.url;
|
|
45
|
+
delete (jsxNode as Partial<Image>).url;
|
|
37
46
|
}
|
|
38
47
|
if (jsxNode.alt) {
|
|
39
48
|
delete jsxNode.alt;
|
|
@@ -43,7 +52,7 @@ const createJSX = (node, pathUrl) => {
|
|
|
43
52
|
}
|
|
44
53
|
};
|
|
45
54
|
|
|
46
|
-
async function ensureImageFileExist(imagePath, sourceFilePath) {
|
|
55
|
+
async function ensureImageFileExist(imagePath: string, sourceFilePath: string) {
|
|
47
56
|
const imageExists = await fs.pathExists(imagePath);
|
|
48
57
|
if (!imageExists) {
|
|
49
58
|
throw new Error(
|
|
@@ -54,7 +63,10 @@ async function ensureImageFileExist(imagePath, sourceFilePath) {
|
|
|
54
63
|
}
|
|
55
64
|
}
|
|
56
65
|
|
|
57
|
-
async function processImageNode(
|
|
66
|
+
async function processImageNode(
|
|
67
|
+
node: Image,
|
|
68
|
+
{filePath, staticDir}: PluginOptions,
|
|
69
|
+
) {
|
|
58
70
|
if (!node.url) {
|
|
59
71
|
throw new Error(
|
|
60
72
|
`Markdown image URL is mandatory in "${toMessageRelativeFilePath(
|
|
@@ -71,8 +83,6 @@ async function processImageNode(node, {filePath, staticDir}) {
|
|
|
71
83
|
// it's mostly to make next release less risky (2.0.0-alpha.59)
|
|
72
84
|
if (parsedUrl.protocol === 'pathname:') {
|
|
73
85
|
node.url = node.url.replace('pathname://', '');
|
|
74
|
-
} else {
|
|
75
|
-
// noop
|
|
76
86
|
}
|
|
77
87
|
}
|
|
78
88
|
// images without protocol
|
|
@@ -92,10 +102,10 @@ async function processImageNode(node, {filePath, staticDir}) {
|
|
|
92
102
|
}
|
|
93
103
|
}
|
|
94
104
|
|
|
95
|
-
const plugin = (options) => {
|
|
96
|
-
const transformer = async (root) => {
|
|
97
|
-
const promises = [];
|
|
98
|
-
visit(root, 'image', (node) => {
|
|
105
|
+
const plugin: Plugin<[PluginOptions]> = (options) => {
|
|
106
|
+
const transformer: Transformer = async (root) => {
|
|
107
|
+
const promises: Promise<void>[] = [];
|
|
108
|
+
visit(root, 'image', (node: Image) => {
|
|
99
109
|
promises.push(processImageNode(node, options));
|
|
100
110
|
});
|
|
101
111
|
await Promise.all(promises);
|
|
@@ -103,4 +113,4 @@ const plugin = (options) => {
|
|
|
103
113
|
return transformer;
|
|
104
114
|
};
|
|
105
115
|
|
|
106
|
-
|
|
116
|
+
export default plugin;
|
package/src/remark/transformLinks/__tests__/__snapshots__/{index.test.js.snap → index.test.ts.snap}
RENAMED
|
@@ -14,7 +14,9 @@ exports[`transformAsset plugin transform md links to <a /> 1`] = `
|
|
|
14
14
|
|
|
15
15
|
<a target=\\"_blank\\" href={require('!file-loader?name=assets/files/[name]-[hash].[ext]!./asset.pdf').default}>asset</a>
|
|
16
16
|
|
|
17
|
-
<a target=\\"_blank\\" href={require('!file-loader?name=assets/files/[name]-[hash].[ext]!./asset.pdf').default}
|
|
17
|
+
<a target=\\"_blank\\" href={require('!file-loader?name=assets/files/[name]-[hash].[ext]!./asset.pdf').default + '#page=2'}>asset with hash</a>
|
|
18
|
+
|
|
19
|
+
<a target=\\"_blank\\" href={require('!file-loader?name=assets/files/[name]-[hash].[ext]!./asset.pdf').default} title=\\"Title\\">asset</a>
|
|
18
20
|
|
|
19
21
|
## Heading
|
|
20
22
|
|
|
@@ -32,6 +34,8 @@ exports[`transformAsset plugin transform md links to <a /> 1`] = `
|
|
|
32
34
|
|
|
33
35
|
<a target=\\"_blank\\" href={require('!file-loader?name=assets/files/[name]-[hash].[ext]!./static/staticAsset.pdf').default}>@site/static/staticAsset.pdf</a>
|
|
34
36
|
|
|
37
|
+
<a target=\\"_blank\\" href={require('!file-loader?name=assets/files/[name]-[hash].[ext]!./static/staticAsset.pdf').default + '#page=2'} title=\\"Title\\">@site/static/staticAsset.pdf</a>
|
|
38
|
+
|
|
35
39
|
<a target=\\"_blank\\" href={require('!file-loader?name=assets/files/[name]-[hash].[ext]!./static/staticAsset.pdf').default}>Just staticAsset.pdf</a>, and <a target=\\"_blank\\" href={require('!file-loader?name=assets/files/[name]-[hash].[ext]!./static/staticAsset.pdf').default}><strong>awesome</strong> staticAsset 2.pdf 'It is really "AWESOME"'</a>, but also <a target=\\"_blank\\" href={require('!file-loader?name=assets/files/[name]-[hash].[ext]!./static/staticAsset.pdf').default}>coded <code>staticAsset 3.pdf</code></a>
|
|
36
40
|
|
|
37
41
|
<a target=\\"_blank\\" href={require('!file-loader?name=assets/files/[name]-[hash].[ext]!./static/staticAssetImage.png').default}><img alt={\\"Clickable Docusaurus logo\\"} src={require(\\"!url-loader?limit=10000&name=assets/images/[name]-[hash].[ext]&fallback=file-loader!./static/staticAssetImage.png\\").default} /></a>
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
[asset](./asset.pdf)
|
|
6
6
|
|
|
7
|
+
[asset with hash](./asset.pdf#page=2)
|
|
8
|
+
|
|
7
9
|
[asset](asset.pdf 'Title')
|
|
8
10
|
|
|
9
11
|
## Heading
|
|
@@ -22,6 +24,8 @@
|
|
|
22
24
|
|
|
23
25
|
[@site/static/staticAsset.pdf](@site/static/staticAsset.pdf)
|
|
24
26
|
|
|
27
|
+
[@site/static/staticAsset.pdf](@site/static/staticAsset.pdf#page=2 'Title')
|
|
28
|
+
|
|
25
29
|
[Just staticAsset.pdf](/staticAsset.pdf), and [**awesome** staticAsset 2.pdf 'It is really "AWESOME"'](/staticAsset.pdf), but also [coded `staticAsset 3.pdf`](/staticAsset.pdf)
|
|
26
30
|
|
|
27
31
|
[](/staticAssetImage.png)
|
|
File without changes
|