@azerion/bunosaurus-mdx-loader 0.0.0-stage → 4.0.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.
Files changed (130) hide show
  1. package/README.md +57 -2
  2. package/lib/createMDXLoader.d.ts +14 -0
  3. package/lib/createMDXLoader.d.ts.map +1 -0
  4. package/lib/createMDXLoader.js +52 -0
  5. package/lib/createMDXLoader.js.map +1 -0
  6. package/lib/format.d.ts +14 -0
  7. package/lib/format.d.ts.map +1 -0
  8. package/lib/format.js +41 -0
  9. package/lib/format.js.map +1 -0
  10. package/lib/frontMatter.d.ts +13 -0
  11. package/lib/frontMatter.d.ts.map +1 -0
  12. package/lib/frontMatter.js +23 -0
  13. package/lib/frontMatter.js.map +1 -0
  14. package/lib/index.d.ts +35 -0
  15. package/lib/index.d.ts.map +1 -0
  16. package/lib/index.js +15 -0
  17. package/lib/index.js.map +1 -0
  18. package/lib/loader.d.ts +11 -0
  19. package/lib/loader.d.ts.map +1 -0
  20. package/lib/loader.js +170 -0
  21. package/lib/loader.js.map +1 -0
  22. package/lib/options.d.ts +35 -0
  23. package/lib/options.d.ts.map +1 -0
  24. package/lib/options.js +9 -0
  25. package/lib/options.js.map +1 -0
  26. package/lib/preprocessor.d.ts +18 -0
  27. package/lib/preprocessor.d.ts.map +1 -0
  28. package/lib/preprocessor.js +34 -0
  29. package/lib/preprocessor.js.map +1 -0
  30. package/lib/processor.d.ts +49 -0
  31. package/lib/processor.d.ts.map +1 -0
  32. package/lib/processor.js +209 -0
  33. package/lib/processor.js.map +1 -0
  34. package/lib/remark/admonitions/index.d.ts +11 -0
  35. package/lib/remark/admonitions/index.d.ts.map +1 -0
  36. package/lib/remark/admonitions/index.js +107 -0
  37. package/lib/remark/admonitions/index.js.map +1 -0
  38. package/lib/remark/contentTitle/index.d.ts +13 -0
  39. package/lib/remark/contentTitle/index.d.ts.map +1 -0
  40. package/lib/remark/contentTitle/index.js +62 -0
  41. package/lib/remark/contentTitle/index.js.map +1 -0
  42. package/lib/remark/details/index.d.ts +10 -0
  43. package/lib/remark/details/index.d.ts.map +1 -0
  44. package/lib/remark/details/index.js +22 -0
  45. package/lib/remark/details/index.js.map +1 -0
  46. package/lib/remark/head/index.d.ts +10 -0
  47. package/lib/remark/head/index.d.ts.map +1 -0
  48. package/lib/remark/head/index.js +22 -0
  49. package/lib/remark/head/index.js.map +1 -0
  50. package/lib/remark/headings/index.d.ts +14 -0
  51. package/lib/remark/headings/index.d.ts.map +1 -0
  52. package/lib/remark/headings/index.js +126 -0
  53. package/lib/remark/headings/index.js.map +1 -0
  54. package/lib/remark/mdx1Compat/codeCompatPlugin.d.ts +11 -0
  55. package/lib/remark/mdx1Compat/codeCompatPlugin.d.ts.map +1 -0
  56. package/lib/remark/mdx1Compat/codeCompatPlugin.js +30 -0
  57. package/lib/remark/mdx1Compat/codeCompatPlugin.js.map +1 -0
  58. package/lib/remark/mermaid/index.d.ts +10 -0
  59. package/lib/remark/mermaid/index.d.ts.map +1 -0
  60. package/lib/remark/mermaid/index.js +34 -0
  61. package/lib/remark/mermaid/index.js.map +1 -0
  62. package/lib/remark/resolveMarkdownLinks/index.d.ts +33 -0
  63. package/lib/remark/resolveMarkdownLinks/index.d.ts.map +1 -0
  64. package/lib/remark/resolveMarkdownLinks/index.js +87 -0
  65. package/lib/remark/resolveMarkdownLinks/index.js.map +1 -0
  66. package/lib/remark/toc/index.d.ts +14 -0
  67. package/lib/remark/toc/index.d.ts.map +1 -0
  68. package/lib/remark/toc/index.js +115 -0
  69. package/lib/remark/toc/index.js.map +1 -0
  70. package/lib/remark/toc/types.d.ts +22 -0
  71. package/lib/remark/toc/types.d.ts.map +1 -0
  72. package/lib/remark/toc/types.js +9 -0
  73. package/lib/remark/toc/types.js.map +1 -0
  74. package/lib/remark/toc/utils.d.ts +26 -0
  75. package/lib/remark/toc/utils.d.ts.map +1 -0
  76. package/lib/remark/toc/utils.js +184 -0
  77. package/lib/remark/toc/utils.js.map +1 -0
  78. package/lib/remark/transformImage/index.d.ts +17 -0
  79. package/lib/remark/transformImage/index.d.ts.map +1 -0
  80. package/lib/remark/transformImage/index.js +187 -0
  81. package/lib/remark/transformImage/index.js.map +1 -0
  82. package/lib/remark/transformLinks/index.d.ts +17 -0
  83. package/lib/remark/transformLinks/index.d.ts.map +1 -0
  84. package/lib/remark/transformLinks/index.js +205 -0
  85. package/lib/remark/transformLinks/index.js.map +1 -0
  86. package/lib/remark/unusedDirectives/index.d.ts +9 -0
  87. package/lib/remark/unusedDirectives/index.d.ts.map +1 -0
  88. package/lib/remark/unusedDirectives/index.js +125 -0
  89. package/lib/remark/unusedDirectives/index.js.map +1 -0
  90. package/lib/remark/utils/index.d.ts +18 -0
  91. package/lib/remark/utils/index.d.ts.map +1 -0
  92. package/lib/remark/utils/index.js +93 -0
  93. package/lib/remark/utils/index.js.map +1 -0
  94. package/lib/serializeJS.d.ts +17 -0
  95. package/lib/serializeJS.d.ts.map +1 -0
  96. package/lib/serializeJS.js +24 -0
  97. package/lib/serializeJS.js.map +1 -0
  98. package/lib/utils.d.ts +35 -0
  99. package/lib/utils.d.ts.map +1 -0
  100. package/lib/utils.js +97 -0
  101. package/lib/utils.js.map +1 -0
  102. package/package.json +65 -4
  103. package/src/createMDXLoader.ts +65 -0
  104. package/src/format.ts +50 -0
  105. package/src/frontMatter.ts +31 -0
  106. package/src/index.ts +44 -0
  107. package/src/loader.ts +227 -0
  108. package/src/options.ts +37 -0
  109. package/src/preprocessor.ts +47 -0
  110. package/src/processor.ts +306 -0
  111. package/src/remark/admonitions/LICENSE +45 -0
  112. package/src/remark/admonitions/README.md +3 -0
  113. package/src/remark/admonitions/index.ts +138 -0
  114. package/src/remark/contentTitle/index.ts +76 -0
  115. package/src/remark/details/index.ts +23 -0
  116. package/src/remark/head/index.ts +23 -0
  117. package/src/remark/headings/index.ts +158 -0
  118. package/src/remark/mdx1Compat/codeCompatPlugin.ts +35 -0
  119. package/src/remark/mermaid/index.ts +35 -0
  120. package/src/remark/resolveMarkdownLinks/index.ts +137 -0
  121. package/src/remark/toc/index.ts +183 -0
  122. package/src/remark/toc/types.ts +29 -0
  123. package/src/remark/toc/utils.ts +243 -0
  124. package/src/remark/transformImage/index.ts +268 -0
  125. package/src/remark/transformLinks/index.ts +291 -0
  126. package/src/remark/unusedDirectives/index.ts +171 -0
  127. package/src/remark/utils/index.ts +99 -0
  128. package/src/serializeJS.ts +22 -0
  129. package/src/types.d.mts +40 -0
  130. package/src/utils.ts +134 -0
@@ -0,0 +1,183 @@
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
+ import {toString} from 'mdast-util-to-string';
10
+ import {
11
+ addTocSliceImportIfNeeded,
12
+ createTOCExportNodeAST,
13
+ findDefaultImportName,
14
+ getImportDeclarations,
15
+ isMarkdownImport,
16
+ isNamedExport,
17
+ } from './utils';
18
+ import type {Heading, Root} from 'mdast';
19
+ import type {Plugin, Transformer} from 'unified';
20
+ import type {MdxjsEsm, MdxJsxFlowElement} from 'mdast-util-mdx';
21
+ import type {TOCItems} from './types';
22
+ import type {ImportDeclaration} from 'estree';
23
+
24
+ interface PluginOptions {
25
+ name?: string;
26
+ }
27
+
28
+ // ComponentName (default export) => ImportDeclaration mapping
29
+ type MarkdownImports = Map<string, {declaration: ImportDeclaration}>;
30
+
31
+ // MdxjsEsm node representing an already existing "export const toc" declaration
32
+ type ExistingTOCExport = MdxjsEsm | null;
33
+
34
+ function createTocSliceImportName({
35
+ tocExportName,
36
+ componentName,
37
+ }: {
38
+ tocExportName: string;
39
+ componentName: string;
40
+ }) {
41
+ // The name of the toc slice import alias doesn't matter much
42
+ // We just need to ensure it's valid and won't conflict with other names
43
+ return `__${tocExportName}${componentName}`;
44
+ }
45
+
46
+ function collectImportsExports({
47
+ root,
48
+ tocExportName,
49
+ }: {
50
+ root: Root;
51
+ tocExportName: string;
52
+ }): {
53
+ markdownImports: MarkdownImports;
54
+ existingTocExport: ExistingTOCExport;
55
+ } {
56
+ const markdownImports = new Map<string, {declaration: ImportDeclaration}>();
57
+ let existingTocExport: MdxjsEsm | null = null;
58
+
59
+ visit(root, 'mdxjsEsm', (node) => {
60
+ if (!node.data?.estree) {
61
+ return;
62
+ }
63
+ if (isNamedExport(node, tocExportName)) {
64
+ existingTocExport = node;
65
+ }
66
+
67
+ getImportDeclarations(node.data.estree).forEach((declaration) => {
68
+ if (!isMarkdownImport(declaration)) {
69
+ return;
70
+ }
71
+ const componentName = findDefaultImportName(declaration);
72
+ if (!componentName) {
73
+ return;
74
+ }
75
+ markdownImports.set(componentName, {
76
+ declaration,
77
+ });
78
+ });
79
+ });
80
+
81
+ return {markdownImports, existingTocExport};
82
+ }
83
+
84
+ function collectTOCItems({
85
+ root,
86
+ tocExportName,
87
+ markdownImports,
88
+ }: {
89
+ root: Root;
90
+ tocExportName: string;
91
+ markdownImports: MarkdownImports;
92
+ }): {
93
+ // The toc items we collected in the tree
94
+ tocItems: TOCItems;
95
+ } {
96
+ const tocItems: TOCItems = [];
97
+
98
+ visit(root, (child) => {
99
+ if (child.type === 'heading') {
100
+ visitHeading(child);
101
+ } else if (child.type === 'mdxJsxFlowElement') {
102
+ visitJSXElement(child);
103
+ }
104
+ });
105
+
106
+ return {tocItems};
107
+
108
+ // Visit Markdown headings
109
+ function visitHeading(node: Heading) {
110
+ const value = toString(node);
111
+ // depth:1 headings are titles and not included in the TOC
112
+ if (!value || node.depth < 2) {
113
+ return;
114
+ }
115
+ tocItems.push({
116
+ type: 'heading',
117
+ heading: node,
118
+ });
119
+ }
120
+
121
+ // Visit JSX elements, such as <Partial/>
122
+ function visitJSXElement(node: MdxJsxFlowElement) {
123
+ const componentName = node.name;
124
+ if (!componentName) {
125
+ return;
126
+ }
127
+ const importDeclaration = markdownImports.get(componentName)?.declaration;
128
+ if (!importDeclaration) {
129
+ return;
130
+ }
131
+
132
+ const tocSliceImportName = createTocSliceImportName({
133
+ tocExportName,
134
+ componentName,
135
+ });
136
+
137
+ tocItems.push({
138
+ type: 'slice',
139
+ importName: tocSliceImportName,
140
+ });
141
+
142
+ addTocSliceImportIfNeeded({
143
+ importDeclaration,
144
+ tocExportName,
145
+ tocSliceImportName,
146
+ });
147
+ }
148
+ }
149
+
150
+ const plugin: Plugin<PluginOptions[], Root> = function plugin(
151
+ options = {},
152
+ ): Transformer<Root> {
153
+ const tocExportName = options.name || 'toc';
154
+
155
+ return (root) => {
156
+ const {markdownImports, existingTocExport} = collectImportsExports({
157
+ root,
158
+ tocExportName,
159
+ });
160
+
161
+ // If user explicitly writes "export const toc" in his mdx file
162
+ // We keep it as is do not override their explicit toc structure
163
+ // See https://github.com/facebook/docusaurus/pull/7530#discussion_r1458087876
164
+ if (existingTocExport) {
165
+ return;
166
+ }
167
+
168
+ const {tocItems} = collectTOCItems({
169
+ root,
170
+ tocExportName,
171
+ markdownImports,
172
+ });
173
+
174
+ root.children.push(
175
+ createTOCExportNodeAST({
176
+ tocExportName,
177
+ tocItems,
178
+ }),
179
+ );
180
+ };
181
+ };
182
+
183
+ export default plugin;
@@ -0,0 +1,29 @@
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 type {Heading} from 'mdast';
9
+
10
+ // Note: this type is exported from mdx-loader and used in theme
11
+ // Need to keep it retro compatible
12
+ export type TOCItem = {
13
+ readonly value: string;
14
+ readonly id: string;
15
+ readonly level: number;
16
+ };
17
+
18
+ export type TOCHeading = {
19
+ readonly type: 'heading';
20
+ readonly heading: Heading;
21
+ };
22
+
23
+ // A TOC slice represents a TOCItem[] imported from a partial
24
+ export type TOCSlice = {
25
+ readonly type: 'slice';
26
+ readonly importName: string;
27
+ };
28
+
29
+ export type TOCItems = (TOCHeading | TOCSlice)[];
@@ -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 {toString} from 'mdast-util-to-string';
9
+ import {valueToEstree} from 'estree-util-value-to-estree';
10
+ import escapeHtml from 'escape-html';
11
+ import type {Node, Parent} from 'unist';
12
+ import type {
13
+ MdxjsEsm,
14
+ MdxJsxAttribute,
15
+ MdxJsxTextElement,
16
+ } from 'mdast-util-mdx';
17
+ import type {TOCHeading, TOCItem, TOCItems, TOCSlice} from './types';
18
+ import type {
19
+ Program,
20
+ SpreadElement,
21
+ ImportDeclaration,
22
+ ImportSpecifier,
23
+ } from 'estree';
24
+ import type {Heading, PhrasingContent} from 'mdast';
25
+
26
+ export function getImportDeclarations(program: Program): ImportDeclaration[] {
27
+ return program.body.filter(
28
+ (item): item is ImportDeclaration => item.type === 'ImportDeclaration',
29
+ );
30
+ }
31
+
32
+ export function isMarkdownImport(node: Node): node is ImportDeclaration {
33
+ if (node.type !== 'ImportDeclaration') {
34
+ return false;
35
+ }
36
+ const importPath = (node as ImportDeclaration).source.value;
37
+ return typeof importPath === 'string' && /\.mdx?$/.test(importPath);
38
+ }
39
+
40
+ export function findDefaultImportName(
41
+ importDeclaration: ImportDeclaration,
42
+ ): string | undefined {
43
+ return importDeclaration.specifiers.find(
44
+ (o: Node) => o.type === 'ImportDefaultSpecifier',
45
+ )?.local.name;
46
+ }
47
+
48
+ function findNamedImportSpecifier(
49
+ importDeclaration: ImportDeclaration,
50
+ localName: string,
51
+ ): ImportSpecifier | undefined {
52
+ return importDeclaration?.specifiers.find(
53
+ (specifier): specifier is ImportSpecifier =>
54
+ specifier.type === 'ImportSpecifier' &&
55
+ specifier.local.name === localName,
56
+ );
57
+ }
58
+
59
+ // Before: import Partial from "partial"
60
+ // After: import Partial, {toc as __tocPartial} from "partial"
61
+ export function addTocSliceImportIfNeeded({
62
+ importDeclaration,
63
+ tocExportName,
64
+ tocSliceImportName,
65
+ }: {
66
+ importDeclaration: ImportDeclaration;
67
+ tocExportName: string;
68
+ tocSliceImportName: string;
69
+ }): void {
70
+ // We only add the toc slice named import if it doesn't exist already
71
+ if (!findNamedImportSpecifier(importDeclaration, tocSliceImportName)) {
72
+ importDeclaration.specifiers.push({
73
+ type: 'ImportSpecifier',
74
+ imported: {type: 'Identifier', name: tocExportName},
75
+ local: {type: 'Identifier', name: tocSliceImportName},
76
+ });
77
+ }
78
+ }
79
+
80
+ export function isNamedExport(
81
+ node: Node,
82
+ exportName: string,
83
+ ): node is MdxjsEsm {
84
+ if (node.type !== 'mdxjsEsm') {
85
+ return false;
86
+ }
87
+ const program = (node as MdxjsEsm).data?.estree;
88
+ if (!program) {
89
+ return false;
90
+ }
91
+ if (program.body.length !== 1) {
92
+ return false;
93
+ }
94
+ const exportDeclaration = program.body[0]!;
95
+ if (exportDeclaration.type !== 'ExportNamedDeclaration') {
96
+ return false;
97
+ }
98
+ const variableDeclaration = exportDeclaration.declaration;
99
+ if (variableDeclaration?.type !== 'VariableDeclaration') {
100
+ return false;
101
+ }
102
+ const {id} = variableDeclaration.declarations[0]!;
103
+ if (id.type !== 'Identifier') {
104
+ return false;
105
+ }
106
+
107
+ return id.name === exportName;
108
+ }
109
+
110
+ export function createTOCExportNodeAST({
111
+ tocExportName,
112
+ tocItems,
113
+ }: {
114
+ tocExportName: string;
115
+ tocItems: TOCItems;
116
+ }): MdxjsEsm {
117
+ function createTOCSliceAST(tocSlice: TOCSlice): SpreadElement {
118
+ return {
119
+ type: 'SpreadElement',
120
+ argument: {type: 'Identifier', name: tocSlice.importName},
121
+ };
122
+ }
123
+
124
+ function createTOCHeadingAST({heading}: TOCHeading) {
125
+ const value: TOCItem = {
126
+ value: toHeadingHTMLValue(heading),
127
+ id: heading.data!.id!,
128
+ level: heading.depth,
129
+ };
130
+ return valueToEstree(value);
131
+ }
132
+
133
+ function createTOCItemAST(tocItem: TOCItems[number]) {
134
+ switch (tocItem.type) {
135
+ case 'slice':
136
+ return createTOCSliceAST(tocItem);
137
+ case 'heading':
138
+ return createTOCHeadingAST(tocItem);
139
+ default: {
140
+ throw new Error(`unexpected toc item type`);
141
+ }
142
+ }
143
+ }
144
+
145
+ return {
146
+ type: 'mdxjsEsm',
147
+ value: '', // See https://github.com/facebook/docusaurus/pull/9684#discussion_r1457595181
148
+ data: {
149
+ estree: {
150
+ type: 'Program',
151
+ body: [
152
+ {
153
+ type: 'ExportNamedDeclaration',
154
+ attributes: [],
155
+ declaration: {
156
+ type: 'VariableDeclaration',
157
+ declarations: [
158
+ {
159
+ type: 'VariableDeclarator',
160
+ id: {
161
+ type: 'Identifier',
162
+ name: tocExportName,
163
+ },
164
+ init: {
165
+ type: 'ArrayExpression',
166
+ elements: tocItems.map(createTOCItemAST),
167
+ },
168
+ },
169
+ ],
170
+ kind: 'const',
171
+ },
172
+ specifiers: [],
173
+ source: null,
174
+ },
175
+ ],
176
+ sourceType: 'module',
177
+ },
178
+ },
179
+ };
180
+ }
181
+
182
+ function stringifyChildren(node: Parent): string {
183
+ return (node.children as PhrasingContent[])
184
+ .map(toHeadingHTMLValue)
185
+ .join('')
186
+ .trim();
187
+ }
188
+
189
+ // TODO This is really a workaround, and not super reliable
190
+ // For now we only support serializing tagName, className and content
191
+ // Can we implement the TOC with real JSX nodes instead of html strings later?
192
+ function mdxJsxTextElementToHtml(element: MdxJsxTextElement): string {
193
+ const tag = element.name;
194
+
195
+ // See https://github.com/facebook/docusaurus/issues/11003#issuecomment-2733925363
196
+ if (tag === 'img') {
197
+ return '';
198
+ }
199
+
200
+ const attributes = element.attributes.filter(
201
+ (child): child is MdxJsxAttribute => child.type === 'mdxJsxAttribute',
202
+ );
203
+
204
+ const classAttribute =
205
+ attributes.find((attr) => attr.name === 'className') ??
206
+ attributes.find((attr) => attr.name === 'class');
207
+
208
+ const classAttributeString = classAttribute
209
+ ? `class="${escapeHtml(String(classAttribute.value))}"`
210
+ : ``;
211
+
212
+ const allAttributes = classAttributeString ? ` ${classAttributeString}` : '';
213
+
214
+ const content = stringifyChildren(element);
215
+
216
+ return `<${tag}${allAttributes}>${content}</${tag}>`;
217
+ }
218
+
219
+ export function toHeadingHTMLValue(
220
+ node: PhrasingContent | Heading | MdxJsxTextElement,
221
+ ): string {
222
+ switch (node.type) {
223
+ case 'mdxJsxTextElement': {
224
+ return mdxJsxTextElementToHtml(node as MdxJsxTextElement);
225
+ }
226
+ case 'text':
227
+ return escapeHtml(node.value);
228
+ case 'heading':
229
+ return stringifyChildren(node);
230
+ case 'inlineCode':
231
+ return `<code>${escapeHtml(node.value)}</code>`;
232
+ case 'emphasis':
233
+ return `<em>${stringifyChildren(node)}</em>`;
234
+ case 'strong':
235
+ return `<strong>${stringifyChildren(node)}</strong>`;
236
+ case 'delete':
237
+ return `<del>${stringifyChildren(node)}</del>`;
238
+ case 'link':
239
+ return stringifyChildren(node);
240
+ default:
241
+ return toString(node);
242
+ }
243
+ }