@docusaurus/mdx-loader 2.4.1 → 3.0.0-beta.0
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/README.md +13 -0
- package/lib/format.d.ts +14 -0
- package/lib/format.d.ts.map +1 -0
- package/lib/format.js +42 -0
- package/lib/format.js.map +1 -0
- package/lib/frontMatter.d.ts +13 -0
- package/lib/frontMatter.d.ts.map +1 -0
- package/lib/frontMatter.js +23 -0
- package/lib/frontMatter.js.map +1 -0
- package/lib/index.d.ts +7 -7
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/loader.d.ts +5 -14
- package/lib/loader.d.ts.map +1 -1
- package/lib/loader.js +45 -81
- package/lib/loader.js.map +1 -1
- package/lib/preprocessor.d.ts +18 -0
- package/lib/preprocessor.d.ts.map +1 -0
- package/lib/preprocessor.js +34 -0
- package/lib/preprocessor.js.map +1 -0
- package/lib/processor.d.ts +36 -0
- package/lib/processor.d.ts.map +1 -0
- package/lib/processor.js +160 -0
- package/lib/processor.js.map +1 -0
- package/lib/remark/admonitions/index.d.ts +4 -9
- package/lib/remark/admonitions/index.d.ts.map +1 -1
- package/lib/remark/admonitions/index.js +70 -128
- package/lib/remark/admonitions/index.js.map +1 -1
- package/lib/remark/details/index.d.ts +9 -0
- package/lib/remark/details/index.d.ts.map +1 -0
- package/lib/remark/details/index.js +23 -0
- package/lib/remark/details/index.js.map +1 -0
- package/lib/remark/head/index.d.ts +9 -0
- package/lib/remark/head/index.d.ts.map +1 -0
- package/lib/remark/head/index.js +23 -0
- package/lib/remark/head/index.js.map +1 -0
- package/lib/remark/headings/index.d.ts.map +1 -1
- package/lib/remark/headings/index.js +3 -3
- package/lib/remark/headings/index.js.map +1 -1
- package/lib/remark/{unwrapMdxCodeBlocks/index.d.ts → mdx1Compat/codeCompatPlugin.d.ts} +2 -2
- package/lib/remark/mdx1Compat/codeCompatPlugin.d.ts.map +1 -0
- package/lib/remark/mdx1Compat/codeCompatPlugin.js +34 -0
- package/lib/remark/mdx1Compat/codeCompatPlugin.js.map +1 -0
- package/lib/remark/mermaid/index.d.ts.map +1 -1
- package/lib/remark/mermaid/index.js +1 -0
- package/lib/remark/mermaid/index.js.map +1 -1
- package/lib/remark/toc/index.d.ts +8 -2
- package/lib/remark/toc/index.d.ts.map +1 -1
- package/lib/remark/toc/index.js +53 -23
- package/lib/remark/toc/index.js.map +1 -1
- package/lib/remark/transformImage/index.d.ts +2 -1
- package/lib/remark/transformImage/index.d.ts.map +1 -1
- package/lib/remark/transformImage/index.js +42 -15
- package/lib/remark/transformImage/index.js.map +1 -1
- package/lib/remark/transformLinks/index.d.ts +2 -1
- package/lib/remark/transformLinks/index.d.ts.map +1 -1
- package/lib/remark/transformLinks/index.js +30 -11
- package/lib/remark/transformLinks/index.js.map +1 -1
- package/lib/remark/utils/index.d.ts +4 -2
- package/lib/remark/utils/index.d.ts.map +1 -1
- package/lib/remark/utils/index.js +82 -11
- package/lib/remark/utils/index.js.map +1 -1
- package/package.json +28 -20
- package/src/format.ts +50 -0
- package/src/frontMatter.ts +31 -0
- package/src/index.ts +10 -6
- package/src/loader.ts +72 -107
- package/src/preprocessor.ts +47 -0
- package/src/processor.ts +243 -0
- package/src/remark/admonitions/README.md +1 -1
- package/src/remark/admonitions/index.ts +92 -171
- package/src/remark/details/index.ts +25 -0
- package/src/remark/head/index.ts +25 -0
- package/src/remark/headings/index.ts +5 -3
- package/src/remark/mdx1Compat/codeCompatPlugin.ts +36 -0
- package/src/remark/mermaid/index.ts +2 -0
- package/src/remark/toc/index.ts +80 -26
- package/src/remark/transformImage/index.ts +54 -19
- package/src/remark/transformLinks/index.ts +44 -17
- package/src/remark/utils/index.ts +108 -9
- package/lib/remark/unwrapMdxCodeBlocks/index.d.ts.map +0 -1
- package/lib/remark/unwrapMdxCodeBlocks/index.js +0 -29
- package/lib/remark/unwrapMdxCodeBlocks/index.js.map +0 -1
- package/src/deps.d.ts +0 -31
- package/src/remark/unwrapMdxCodeBlocks/index.ts +0 -33
package/src/processor.ts
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
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 emoji from 'remark-emoji';
|
|
9
|
+
import headings from './remark/headings';
|
|
10
|
+
import toc from './remark/toc';
|
|
11
|
+
import transformImage from './remark/transformImage';
|
|
12
|
+
import transformLinks from './remark/transformLinks';
|
|
13
|
+
import details from './remark/details';
|
|
14
|
+
import head from './remark/head';
|
|
15
|
+
import mermaid from './remark/mermaid';
|
|
16
|
+
import transformAdmonitions from './remark/admonitions';
|
|
17
|
+
import codeCompatPlugin from './remark/mdx1Compat/codeCompatPlugin';
|
|
18
|
+
import {getFormat} from './format';
|
|
19
|
+
import type {MDXFrontMatter} from './frontMatter';
|
|
20
|
+
import type {Options} from './loader';
|
|
21
|
+
import type {AdmonitionOptions} from './remark/admonitions';
|
|
22
|
+
|
|
23
|
+
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
|
|
24
|
+
import type {ProcessorOptions} from '@mdx-js/mdx';
|
|
25
|
+
|
|
26
|
+
// TODO as of April 2023, no way to import/re-export this ESM type easily :/
|
|
27
|
+
// This might change soon, likely after TS 5.2
|
|
28
|
+
// See https://github.com/microsoft/TypeScript/issues/49721#issuecomment-1517839391
|
|
29
|
+
type Pluggable = any; // TODO fix this asap
|
|
30
|
+
|
|
31
|
+
// TODO alt interface because impossible to import type Processor (ESM + TS :/)
|
|
32
|
+
type SimpleProcessor = {
|
|
33
|
+
process: ({
|
|
34
|
+
content,
|
|
35
|
+
filePath,
|
|
36
|
+
}: {
|
|
37
|
+
content: string;
|
|
38
|
+
filePath: string;
|
|
39
|
+
}) => Promise<string>;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const DEFAULT_OPTIONS: MDXOptions = {
|
|
43
|
+
admonitions: true,
|
|
44
|
+
rehypePlugins: [],
|
|
45
|
+
remarkPlugins: [headings, emoji, toc],
|
|
46
|
+
beforeDefaultRemarkPlugins: [],
|
|
47
|
+
beforeDefaultRehypePlugins: [],
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export type MDXPlugin = Pluggable;
|
|
51
|
+
|
|
52
|
+
export type MDXOptions = {
|
|
53
|
+
admonitions: boolean | Partial<AdmonitionOptions>;
|
|
54
|
+
remarkPlugins: MDXPlugin[];
|
|
55
|
+
rehypePlugins: MDXPlugin[];
|
|
56
|
+
beforeDefaultRemarkPlugins: MDXPlugin[];
|
|
57
|
+
beforeDefaultRehypePlugins: MDXPlugin[];
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
function getAdmonitionsPlugins(
|
|
61
|
+
admonitionsOption: MDXOptions['admonitions'],
|
|
62
|
+
): MDXPlugin[] {
|
|
63
|
+
if (admonitionsOption) {
|
|
64
|
+
const plugin: MDXPlugin =
|
|
65
|
+
admonitionsOption === true
|
|
66
|
+
? transformAdmonitions
|
|
67
|
+
: [transformAdmonitions, admonitionsOption];
|
|
68
|
+
return [plugin];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Need to be async due to ESM dynamic imports...
|
|
75
|
+
async function createProcessorFactory() {
|
|
76
|
+
const {createProcessor: createMdxProcessor} = await import('@mdx-js/mdx');
|
|
77
|
+
const {default: rehypeRaw} = await import('rehype-raw');
|
|
78
|
+
const {default: gfm} = await import('remark-gfm');
|
|
79
|
+
// TODO using fork until PR merged: https://github.com/leebyron/remark-comment/pull/3
|
|
80
|
+
const {default: comment} = await import('@slorber/remark-comment');
|
|
81
|
+
const {default: directive} = await import('remark-directive');
|
|
82
|
+
|
|
83
|
+
// /!\ this method is synchronous on purpose
|
|
84
|
+
// Using async code here can create cache entry race conditions!
|
|
85
|
+
function createProcessorSync({
|
|
86
|
+
options,
|
|
87
|
+
format,
|
|
88
|
+
}: {
|
|
89
|
+
options: Options;
|
|
90
|
+
format: 'md' | 'mdx';
|
|
91
|
+
}): SimpleProcessor {
|
|
92
|
+
const remarkPlugins: MDXPlugin[] = [
|
|
93
|
+
...(options.beforeDefaultRemarkPlugins ?? []),
|
|
94
|
+
directive,
|
|
95
|
+
...getAdmonitionsPlugins(options.admonitions ?? false),
|
|
96
|
+
...DEFAULT_OPTIONS.remarkPlugins,
|
|
97
|
+
details,
|
|
98
|
+
head,
|
|
99
|
+
...(options.markdownConfig.mermaid ? [mermaid] : []),
|
|
100
|
+
[
|
|
101
|
+
transformImage,
|
|
102
|
+
{
|
|
103
|
+
staticDirs: options.staticDirs,
|
|
104
|
+
siteDir: options.siteDir,
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
[
|
|
108
|
+
transformLinks,
|
|
109
|
+
{
|
|
110
|
+
staticDirs: options.staticDirs,
|
|
111
|
+
siteDir: options.siteDir,
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
gfm,
|
|
115
|
+
options.markdownConfig.mdx1Compat.comments ? comment : null,
|
|
116
|
+
...(options.remarkPlugins ?? []),
|
|
117
|
+
].filter((plugin): plugin is MDXPlugin => Boolean(plugin));
|
|
118
|
+
|
|
119
|
+
// codeCompatPlugin needs to be applied last after user-provided plugins
|
|
120
|
+
// (after npm2yarn for example)
|
|
121
|
+
remarkPlugins.push(codeCompatPlugin);
|
|
122
|
+
|
|
123
|
+
const rehypePlugins: MDXPlugin[] = [
|
|
124
|
+
...(options.beforeDefaultRehypePlugins ?? []),
|
|
125
|
+
...DEFAULT_OPTIONS.rehypePlugins,
|
|
126
|
+
...(options.rehypePlugins ?? []),
|
|
127
|
+
];
|
|
128
|
+
|
|
129
|
+
if (format === 'md') {
|
|
130
|
+
// This is what permits to embed HTML elements with format 'md'
|
|
131
|
+
// See https://github.com/facebook/docusaurus/pull/8960
|
|
132
|
+
// See https://github.com/mdx-js/mdx/pull/2295#issuecomment-1540085960
|
|
133
|
+
const rehypeRawPlugin: MDXPlugin = [
|
|
134
|
+
rehypeRaw,
|
|
135
|
+
{
|
|
136
|
+
passThrough: [
|
|
137
|
+
'mdxFlowExpression',
|
|
138
|
+
'mdxJsxFlowElement',
|
|
139
|
+
'mdxJsxTextElement',
|
|
140
|
+
'mdxTextExpression',
|
|
141
|
+
'mdxjsEsm',
|
|
142
|
+
],
|
|
143
|
+
},
|
|
144
|
+
];
|
|
145
|
+
rehypePlugins.unshift(rehypeRawPlugin);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const processorOptions: ProcessorOptions & Options = {
|
|
149
|
+
...options,
|
|
150
|
+
remarkPlugins,
|
|
151
|
+
rehypePlugins,
|
|
152
|
+
providerImportSource: '@mdx-js/react',
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const mdxProcessor = createMdxProcessor({
|
|
156
|
+
...processorOptions,
|
|
157
|
+
format,
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
return {
|
|
161
|
+
process: async ({content, filePath}) =>
|
|
162
|
+
mdxProcessor
|
|
163
|
+
.process({
|
|
164
|
+
value: content,
|
|
165
|
+
path: filePath,
|
|
166
|
+
})
|
|
167
|
+
.then((res) => res.toString()),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return {createProcessorSync};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Will be useful for tests
|
|
175
|
+
export async function createProcessorUncached(parameters: {
|
|
176
|
+
options: Options;
|
|
177
|
+
format: 'md' | 'mdx';
|
|
178
|
+
}): Promise<SimpleProcessor> {
|
|
179
|
+
const {createProcessorSync} = await createProcessorFactory();
|
|
180
|
+
return createProcessorSync(parameters);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// We use different compilers depending on the file type (md vs mdx)
|
|
184
|
+
type ProcessorsCacheEntry = {
|
|
185
|
+
mdProcessor: SimpleProcessor;
|
|
186
|
+
mdxProcessor: SimpleProcessor;
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
// Compilers are cached so that Remark/Rehype plugins can run
|
|
190
|
+
// expensive code during initialization
|
|
191
|
+
const ProcessorsCache = new Map<string | Options, ProcessorsCacheEntry>();
|
|
192
|
+
|
|
193
|
+
async function createProcessorsCacheEntry({
|
|
194
|
+
query,
|
|
195
|
+
reqOptions,
|
|
196
|
+
}: {
|
|
197
|
+
query: string | Options;
|
|
198
|
+
reqOptions: Options;
|
|
199
|
+
}): Promise<ProcessorsCacheEntry> {
|
|
200
|
+
const {createProcessorSync} = await createProcessorFactory();
|
|
201
|
+
|
|
202
|
+
const compilers = ProcessorsCache.get(query);
|
|
203
|
+
if (compilers) {
|
|
204
|
+
return compilers;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const compilerCacheEntry: ProcessorsCacheEntry = {
|
|
208
|
+
mdProcessor: createProcessorSync({
|
|
209
|
+
options: reqOptions,
|
|
210
|
+
format: 'md',
|
|
211
|
+
}),
|
|
212
|
+
mdxProcessor: createProcessorSync({
|
|
213
|
+
options: reqOptions,
|
|
214
|
+
format: 'mdx',
|
|
215
|
+
}),
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
ProcessorsCache.set(query, compilerCacheEntry);
|
|
219
|
+
|
|
220
|
+
return compilerCacheEntry;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export async function createProcessorCached({
|
|
224
|
+
filePath,
|
|
225
|
+
mdxFrontMatter,
|
|
226
|
+
query,
|
|
227
|
+
reqOptions,
|
|
228
|
+
}: {
|
|
229
|
+
filePath: string;
|
|
230
|
+
mdxFrontMatter: MDXFrontMatter;
|
|
231
|
+
query: string | Options;
|
|
232
|
+
reqOptions: Options;
|
|
233
|
+
}): Promise<SimpleProcessor> {
|
|
234
|
+
const compilers = await createProcessorsCacheEntry({query, reqOptions});
|
|
235
|
+
|
|
236
|
+
const format = getFormat({
|
|
237
|
+
filePath,
|
|
238
|
+
frontMatterFormat: mdxFrontMatter.format,
|
|
239
|
+
markdownConfigFormat: reqOptions.markdownConfig.format,
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
return format === 'md' ? compilers.mdProcessor : compilers.mdxProcessor;
|
|
243
|
+
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
# Docusaurus admonitions
|
|
2
2
|
|
|
3
|
-
Code from [remark-admonitions](https://github.com/
|
|
3
|
+
Code from [remark-admonitions](https://github.com/elviswolcott/remark-admonitions) (MIT license) has been copied to this folder, and highly customized for Docusaurus needs.
|
|
@@ -4,20 +4,26 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
-
|
|
8
7
|
import visit from 'unist-util-visit';
|
|
9
|
-
|
|
10
|
-
import type {
|
|
8
|
+
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
|
|
9
|
+
import type {Transformer, Processor} from 'unified';
|
|
10
|
+
|
|
11
|
+
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
|
|
12
|
+
import type {ContainerDirective} from 'mdast-util-directive';
|
|
13
|
+
import type {Parent} from 'mdast';
|
|
11
14
|
|
|
12
|
-
|
|
15
|
+
// TODO as of April 2023, no way to import/re-export this ESM type easily :/
|
|
16
|
+
// This might change soon, likely after TS 5.2
|
|
17
|
+
// See https://github.com/microsoft/TypeScript/issues/49721#issuecomment-1517839391
|
|
18
|
+
// import type {Plugin} from 'unified';
|
|
19
|
+
type Plugin = any; // TODO fix this asap
|
|
13
20
|
|
|
14
21
|
export type AdmonitionOptions = {
|
|
15
|
-
tag: string;
|
|
16
22
|
keywords: string[];
|
|
23
|
+
extendDefaults: boolean;
|
|
17
24
|
};
|
|
18
25
|
|
|
19
26
|
export const DefaultAdmonitionOptions: AdmonitionOptions = {
|
|
20
|
-
tag: ':::',
|
|
21
27
|
keywords: [
|
|
22
28
|
'secondary',
|
|
23
29
|
'info',
|
|
@@ -29,193 +35,108 @@ export const DefaultAdmonitionOptions: AdmonitionOptions = {
|
|
|
29
35
|
'important',
|
|
30
36
|
'caution',
|
|
31
37
|
],
|
|
38
|
+
extendDefaults: true,
|
|
32
39
|
};
|
|
33
40
|
|
|
34
|
-
function
|
|
35
|
-
|
|
41
|
+
export function normalizeAdmonitionOptions(
|
|
42
|
+
providedOptions: Partial<AdmonitionOptions> | true,
|
|
43
|
+
): AdmonitionOptions {
|
|
44
|
+
if (providedOptions === true) {
|
|
45
|
+
return DefaultAdmonitionOptions;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const options = {...DefaultAdmonitionOptions, ...providedOptions};
|
|
49
|
+
|
|
50
|
+
// By default it makes more sense to append keywords to the default ones
|
|
51
|
+
// Adding custom keywords is more common than disabling existing ones
|
|
52
|
+
if (options.extendDefaults) {
|
|
53
|
+
options.keywords = [
|
|
54
|
+
...DefaultAdmonitionOptions.keywords,
|
|
55
|
+
...options.keywords,
|
|
56
|
+
];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return options;
|
|
36
60
|
}
|
|
37
61
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
62
|
+
type DirectiveLabel = Parent;
|
|
63
|
+
type DirectiveContent = ContainerDirective['children'];
|
|
64
|
+
|
|
65
|
+
function parseDirective(directive: ContainerDirective): {
|
|
66
|
+
directiveLabel: DirectiveLabel | undefined;
|
|
67
|
+
contentNodes: DirectiveContent;
|
|
68
|
+
} {
|
|
69
|
+
const hasDirectiveLabel =
|
|
70
|
+
directive.children?.[0]?.data?.directiveLabel === true;
|
|
71
|
+
if (hasDirectiveLabel) {
|
|
72
|
+
const [directiveLabel, ...contentNodes] = directive.children;
|
|
73
|
+
return {directiveLabel: directiveLabel as DirectiveLabel, contentNodes};
|
|
74
|
+
}
|
|
75
|
+
return {directiveLabel: undefined, contentNodes: directive.children};
|
|
42
76
|
}
|
|
43
77
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
78
|
+
function getTextOnlyTitle(directiveLabel: DirectiveLabel): string | undefined {
|
|
79
|
+
const isTextOnlyTitle =
|
|
80
|
+
directiveLabel?.children?.length === 1 &&
|
|
81
|
+
directiveLabel?.children?.[0]?.type === 'text';
|
|
82
|
+
return isTextOnlyTitle
|
|
83
|
+
? // @ts-expect-error: todo type
|
|
84
|
+
(directiveLabel?.children?.[0].value as string)
|
|
85
|
+
: undefined;
|
|
86
|
+
}
|
|
47
87
|
|
|
48
88
|
const plugin: Plugin = function plugin(
|
|
49
89
|
this: Processor,
|
|
50
90
|
optionsInput: Partial<AdmonitionOptions> = {},
|
|
51
91
|
): Transformer {
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
const keywords = Object.values(options.keywords).map(escapeRegExp).join('|');
|
|
55
|
-
const nestingChar = escapeRegExp(options.tag.slice(0, 1));
|
|
56
|
-
const tag = escapeRegExp(options.tag);
|
|
57
|
-
|
|
58
|
-
// resolve th nesting level of an opening tag
|
|
59
|
-
// ::: -> 0, :::: -> 1, ::::: -> 2 ...
|
|
60
|
-
const nestingLevelRegex = new RegExp(
|
|
61
|
-
`^${tag}(?<nestingLevel>${nestingChar}*)`,
|
|
62
|
-
);
|
|
63
|
-
|
|
64
|
-
const regex = new RegExp(`${tag}${nestingChar}*(${keywords})(?: *(.*))?\n`);
|
|
65
|
-
const escapeTag = new RegExp(
|
|
66
|
-
escapeRegExp(`\\${options.tag}${options.tag.slice(0, 1)}*`),
|
|
67
|
-
'g',
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
// The tokenizer is called on blocks to determine if there is an admonition
|
|
71
|
-
// present and create tags for it
|
|
72
|
-
function blockTokenizer(this: any, eat: any, value: string, silent: boolean) {
|
|
73
|
-
// Stop if no match or match does not start at beginning of line
|
|
74
|
-
const match = regex.exec(value);
|
|
75
|
-
if (!match || match.index !== 0) {
|
|
76
|
-
return false;
|
|
77
|
-
}
|
|
78
|
-
// If silent return the match
|
|
79
|
-
if (silent) {
|
|
80
|
-
return true;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const now = eat.now();
|
|
84
|
-
const [opening, keyword, title] = match as string[] as [
|
|
85
|
-
string,
|
|
86
|
-
string,
|
|
87
|
-
string,
|
|
88
|
-
];
|
|
89
|
-
const food = [];
|
|
90
|
-
const content = [];
|
|
91
|
-
// get the nesting level of the opening tag
|
|
92
|
-
const openingLevel =
|
|
93
|
-
nestingLevelRegex.exec(opening)!.groups!.nestingLevel!.length;
|
|
94
|
-
// used as a stack to keep track of nested admonitions
|
|
95
|
-
const nestingLevels: number[] = [openingLevel];
|
|
96
|
-
|
|
97
|
-
let newValue = value;
|
|
98
|
-
// consume lines until a closing tag
|
|
99
|
-
let idx = newValue.indexOf(NEWLINE);
|
|
100
|
-
while (idx !== -1) {
|
|
101
|
-
// grab this line and eat it
|
|
102
|
-
const next = newValue.indexOf(NEWLINE, idx + 1);
|
|
103
|
-
const line =
|
|
104
|
-
next !== -1 ? newValue.slice(idx + 1, next) : newValue.slice(idx + 1);
|
|
105
|
-
food.push(line);
|
|
106
|
-
newValue = newValue.slice(idx + 1);
|
|
107
|
-
const nesting = nestingLevelRegex.exec(line);
|
|
108
|
-
idx = newValue.indexOf(NEWLINE);
|
|
109
|
-
if (!nesting) {
|
|
110
|
-
content.push(line);
|
|
111
|
-
continue;
|
|
112
|
-
}
|
|
113
|
-
const tagLevel = nesting.groups!.nestingLevel!.length;
|
|
114
|
-
// first level
|
|
115
|
-
if (nestingLevels.length === 0) {
|
|
116
|
-
nestingLevels.push(tagLevel);
|
|
117
|
-
content.push(line);
|
|
118
|
-
continue;
|
|
119
|
-
}
|
|
120
|
-
const currentLevel = nestingLevels[nestingLevels.length - 1]!;
|
|
121
|
-
if (tagLevel < currentLevel) {
|
|
122
|
-
// entering a nested admonition block
|
|
123
|
-
nestingLevels.push(tagLevel);
|
|
124
|
-
} else if (tagLevel === currentLevel) {
|
|
125
|
-
// closing a nested admonition block
|
|
126
|
-
nestingLevels.pop();
|
|
127
|
-
// the closing tag is NOT part of the content
|
|
128
|
-
if (nestingLevels.length === 0) {
|
|
129
|
-
break;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
content.push(line);
|
|
133
|
-
}
|
|
92
|
+
const {keywords} = normalizeAdmonitionOptions(optionsInput);
|
|
134
93
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
94
|
+
return async (root) => {
|
|
95
|
+
visit(root, (node) => {
|
|
96
|
+
if (node.type === 'containerDirective') {
|
|
97
|
+
const directive = node as ContainerDirective;
|
|
98
|
+
const isAdmonition = keywords.includes(directive.name);
|
|
138
99
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
exit();
|
|
100
|
+
if (!isAdmonition) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
143
103
|
|
|
144
|
-
|
|
104
|
+
const {directiveLabel, contentNodes} = parseDirective(directive);
|
|
145
105
|
|
|
146
|
-
|
|
147
|
-
|
|
106
|
+
const textOnlyTitle =
|
|
107
|
+
directive.attributes?.title ??
|
|
108
|
+
(directiveLabel ? getTextOnlyTitle(directiveLabel) : undefined);
|
|
148
109
|
|
|
149
|
-
|
|
150
|
-
type: admonitionNodeType,
|
|
151
|
-
data: {
|
|
152
|
-
// hName/hProperties come from HAST
|
|
110
|
+
// Transform the mdast directive node to a hast admonition node
|
|
153
111
|
// See https://github.com/syntax-tree/mdast-util-to-hast#fields-on-nodes
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
//
|
|
166
|
-
//
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
112
|
+
// TODO in MDX v2 we should transform the whole directive to
|
|
113
|
+
// mdxJsxFlowElement instead of using hast
|
|
114
|
+
directive.data = {
|
|
115
|
+
hName: 'admonition',
|
|
116
|
+
hProperties: {
|
|
117
|
+
...(textOnlyTitle && {title: textOnlyTitle}),
|
|
118
|
+
type: directive.name,
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
directive.children = contentNodes;
|
|
122
|
+
|
|
123
|
+
// TODO legacy MDX v1 <mdxAdmonitionTitle> workaround
|
|
124
|
+
// v1: not possible to inject complex JSX elements as props
|
|
125
|
+
// v2: now possible: use a mdxJsxFlowElement element
|
|
126
|
+
if (directiveLabel && !textOnlyTitle) {
|
|
127
|
+
const complexTitleNode = {
|
|
128
|
+
type: 'mdxAdmonitionTitle',
|
|
170
129
|
data: {
|
|
171
130
|
hName: 'mdxAdmonitionTitle',
|
|
172
131
|
hProperties: {},
|
|
173
132
|
},
|
|
174
|
-
children:
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
return add(element);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// add tokenizer to parser after fenced code blocks
|
|
184
|
-
const Parser = this.Parser.prototype;
|
|
185
|
-
Parser.blockTokenizers.admonition = blockTokenizer;
|
|
186
|
-
Parser.blockMethods.splice(
|
|
187
|
-
Parser.blockMethods.indexOf('fencedCode') + 1,
|
|
188
|
-
0,
|
|
189
|
-
'admonition',
|
|
190
|
-
);
|
|
191
|
-
Parser.interruptParagraph.splice(
|
|
192
|
-
Parser.interruptParagraph.indexOf('fencedCode') + 1,
|
|
193
|
-
0,
|
|
194
|
-
['admonition'],
|
|
195
|
-
);
|
|
196
|
-
Parser.interruptList.splice(
|
|
197
|
-
Parser.interruptList.indexOf('fencedCode') + 1,
|
|
198
|
-
0,
|
|
199
|
-
['admonition'],
|
|
200
|
-
);
|
|
201
|
-
Parser.interruptBlockquote.splice(
|
|
202
|
-
Parser.interruptBlockquote.indexOf('fencedCode') + 1,
|
|
203
|
-
0,
|
|
204
|
-
['admonition'],
|
|
205
|
-
);
|
|
206
|
-
|
|
207
|
-
return (root) => {
|
|
208
|
-
// escape everything except admonitionHTML nodes
|
|
209
|
-
visit(
|
|
210
|
-
root,
|
|
211
|
-
(node: unknown): node is Literal =>
|
|
212
|
-
(node as Literal | undefined)?.type !== admonitionNodeType,
|
|
213
|
-
(node: Literal) => {
|
|
214
|
-
if (node.value) {
|
|
215
|
-
node.value = node.value.replace(escapeTag, options.tag);
|
|
133
|
+
children: directiveLabel.children,
|
|
134
|
+
};
|
|
135
|
+
// @ts-expect-error: invented node type
|
|
136
|
+
directive.children.unshift(complexTitleNode);
|
|
216
137
|
}
|
|
217
|
-
}
|
|
218
|
-
);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
219
140
|
};
|
|
220
141
|
};
|
|
221
142
|
|
|
@@ -0,0 +1,25 @@
|
|
|
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 visit from 'unist-util-visit';
|
|
9
|
+
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
|
|
10
|
+
import type {Transformer} from 'unified';
|
|
11
|
+
|
|
12
|
+
// @ts-expect-error: ES support...
|
|
13
|
+
import type {MdxJsxFlowElement} from 'mdast-util-mdx';
|
|
14
|
+
|
|
15
|
+
// Transform <details> to <Details>
|
|
16
|
+
// MDX 2 doesn't allow to substitute html elements with the provider anymore
|
|
17
|
+
export default function plugin(): Transformer {
|
|
18
|
+
return (root) => {
|
|
19
|
+
visit(root, 'mdxJsxFlowElement', (node: MdxJsxFlowElement) => {
|
|
20
|
+
if (node.name === 'details') {
|
|
21
|
+
node.name = 'Details';
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
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 visit from 'unist-util-visit';
|
|
9
|
+
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
|
|
10
|
+
import type {Transformer} from 'unified';
|
|
11
|
+
|
|
12
|
+
// @ts-expect-error: ES support...
|
|
13
|
+
import type {MdxJsxFlowElement} from 'mdast-util-mdx';
|
|
14
|
+
|
|
15
|
+
// Transform <head> to <Head>
|
|
16
|
+
// MDX 2 doesn't allow to substitute html elements with the provider anymore
|
|
17
|
+
export default function plugin(): Transformer {
|
|
18
|
+
return (root) => {
|
|
19
|
+
visit(root, 'mdxJsxFlowElement', (node: MdxJsxFlowElement) => {
|
|
20
|
+
if (node.name === 'head') {
|
|
21
|
+
node.name = 'Head';
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -9,12 +9,14 @@
|
|
|
9
9
|
|
|
10
10
|
import {parseMarkdownHeadingId, createSlugger} from '@docusaurus/utils';
|
|
11
11
|
import visit from 'unist-util-visit';
|
|
12
|
-
|
|
12
|
+
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
|
|
13
13
|
import type {Transformer} from 'unified';
|
|
14
14
|
import type {Heading, Text} from 'mdast';
|
|
15
15
|
|
|
16
16
|
export default function plugin(): Transformer {
|
|
17
|
-
return (root) => {
|
|
17
|
+
return async (root) => {
|
|
18
|
+
const {toString} = await import('mdast-util-to-string');
|
|
19
|
+
|
|
18
20
|
const slugs = createSlugger();
|
|
19
21
|
visit(root, 'heading', (headingNode: Heading) => {
|
|
20
22
|
const data = headingNode.data ?? (headingNode.data = {});
|
|
@@ -29,7 +31,7 @@ export default function plugin(): Transformer {
|
|
|
29
31
|
const headingTextNodes = headingNode.children.filter(
|
|
30
32
|
({type}) => !['html', 'jsx'].includes(type),
|
|
31
33
|
);
|
|
32
|
-
const heading =
|
|
34
|
+
const heading = toString(
|
|
33
35
|
headingTextNodes.length > 0 ? headingTextNodes : headingNode,
|
|
34
36
|
);
|
|
35
37
|
|
|
@@ -0,0 +1,36 @@
|
|
|
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 visit from 'unist-util-visit';
|
|
9
|
+
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
|
|
10
|
+
import type {Transformer, Processor} from 'unified';
|
|
11
|
+
import type {Code} from 'mdast';
|
|
12
|
+
|
|
13
|
+
// Solution inspired by https://github.com/pomber/docusaurus-mdx-2/blob/main/packages/mdx-loader/src/remark/codeCompat/index.ts
|
|
14
|
+
// TODO after MDX 2 we probably don't need this - remove soon?
|
|
15
|
+
// Only fenced code blocks are swapped by pre/code MDX components
|
|
16
|
+
// Using <pre><code> in JSX shouldn't use our MDX components anymore
|
|
17
|
+
|
|
18
|
+
// To make theme-classic/src/theme/MDXComponents/Pre work
|
|
19
|
+
// we need to fill two properties that mdx v2 doesn't provide anymore
|
|
20
|
+
export default function codeCompatPlugin(this: Processor): Transformer {
|
|
21
|
+
return (root) => {
|
|
22
|
+
visit(root, 'code', (node: Code) => {
|
|
23
|
+
node.data = node.data || {};
|
|
24
|
+
node.data.hProperties = node.data.hProperties || {};
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
26
|
+
(node.data.hProperties as any).metastring = node.meta;
|
|
27
|
+
|
|
28
|
+
// Retrocompatible support for live codeblock metastring
|
|
29
|
+
// Not really the appropriate place to handle that :s
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
31
|
+
(node.data.hProperties as any).live = node.meta
|
|
32
|
+
?.split(' ')
|
|
33
|
+
.includes('live');
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import visit from 'unist-util-visit';
|
|
9
|
+
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
|
|
9
10
|
import type {Transformer} from 'unified';
|
|
10
11
|
import type {Code} from 'mdast';
|
|
11
12
|
|
|
@@ -17,6 +18,7 @@ export default function plugin(): Transformer {
|
|
|
17
18
|
return (root) => {
|
|
18
19
|
visit(root, 'code', (node: Code, index, parent) => {
|
|
19
20
|
if (node.lang === 'mermaid') {
|
|
21
|
+
// TODO migrate to mdxJsxFlowElement? cf admonitions
|
|
20
22
|
parent!.children.splice(index, 1, {
|
|
21
23
|
type: 'mermaidCodeBlock',
|
|
22
24
|
data: {
|