@mdxeditor/editor 4.2.2 → 4.2.3
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/dist/importMarkdownToLexical.js +23 -10
- package/dist/index.d.ts +20 -0
- package/dist/index.js +2 -1
- package/dist/jsx-editors/GenericJsxEditor.js +1 -1
- package/dist/plugins/core/index.js +5 -1
- package/dist/plugins/jsx/MdastMdxJsxElementVisitor.js +6 -14
- package/dist/plugins/jsx/index.js +7 -3
- package/dist/plugins/jsx/reconcileJsxKind.js +179 -0
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { fromMarkdown } from "mdast-util-from-markdown";
|
|
2
2
|
import { toMarkdown } from "mdast-util-to-markdown";
|
|
3
|
+
import { reconcileJsxKindMismatches } from "./plugins/jsx/reconcileJsxKind.js";
|
|
3
4
|
function isParent(node) {
|
|
4
5
|
return node.children instanceof Array;
|
|
5
6
|
}
|
|
@@ -73,10 +74,30 @@ function importMarkdownToLexical({
|
|
|
73
74
|
importMdastTreeToLexical({ root, mdastRoot, visitors, ...descriptors });
|
|
74
75
|
}
|
|
75
76
|
function importMdastTreeToLexical({ root, mdastRoot, visitors, ...descriptors }) {
|
|
77
|
+
visitors = visitors.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
|
|
78
|
+
function findVisitor(mdastNode, skipVisitors = null) {
|
|
79
|
+
return visitors.find((visitor, index) => {
|
|
80
|
+
if (skipVisitors == null ? void 0 : skipVisitors.has(index)) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
if (typeof visitor.testNode === "string") {
|
|
84
|
+
return visitor.testNode === mdastNode.type;
|
|
85
|
+
}
|
|
86
|
+
return visitor.testNode(mdastNode, descriptors);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
mdastRoot = reconcileJsxKindMismatches(
|
|
90
|
+
mdastRoot,
|
|
91
|
+
descriptors.jsxComponentDescriptors,
|
|
92
|
+
descriptors.jsxKindMismatchPolicy ?? "source",
|
|
93
|
+
(node) => {
|
|
94
|
+
var _a;
|
|
95
|
+
return ((_a = findVisitor(node)) == null ? void 0 : _a.jsxKindReconciliationOwner) === true;
|
|
96
|
+
}
|
|
97
|
+
);
|
|
76
98
|
const formattingMap = /* @__PURE__ */ new WeakMap();
|
|
77
99
|
const styleMap = /* @__PURE__ */ new WeakMap();
|
|
78
100
|
const metaData = gatherMetadata(mdastRoot);
|
|
79
|
-
visitors = visitors.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
|
|
80
101
|
function visitChildren(mdastNode, lexicalParent) {
|
|
81
102
|
if (!isParent(mdastNode)) {
|
|
82
103
|
throw new Error("Attempting to visit children of a non-parent");
|
|
@@ -86,15 +107,7 @@ function importMdastTreeToLexical({ root, mdastRoot, visitors, ...descriptors })
|
|
|
86
107
|
});
|
|
87
108
|
}
|
|
88
109
|
function visit(mdastNode, lexicalParent, mdastParent, skipVisitors = null) {
|
|
89
|
-
const visitor =
|
|
90
|
-
if (skipVisitors == null ? void 0 : skipVisitors.has(index)) {
|
|
91
|
-
return false;
|
|
92
|
-
}
|
|
93
|
-
if (typeof visitor2.testNode === "string") {
|
|
94
|
-
return visitor2.testNode === mdastNode.type;
|
|
95
|
-
}
|
|
96
|
-
return visitor2.testNode(mdastNode, descriptors);
|
|
97
|
-
});
|
|
110
|
+
const visitor = findVisitor(mdastNode, skipVisitors);
|
|
98
111
|
if (!visitor) {
|
|
99
112
|
try {
|
|
100
113
|
throw new UnrecognizedMarkdownConstructError(`Unsupported markdown syntax: ${toMarkdown(mdastNode)}`);
|
package/dist/index.d.ts
CHANGED
|
@@ -904,6 +904,8 @@ export declare const defaultSvgIcons: {
|
|
|
904
904
|
*/
|
|
905
905
|
export declare interface Descriptors {
|
|
906
906
|
jsxComponentDescriptors: JsxComponentDescriptor[];
|
|
907
|
+
/** How parsed JSX node kinds are reconciled with their component descriptors. */
|
|
908
|
+
jsxKindMismatchPolicy?: JsxKindMismatchPolicy;
|
|
907
909
|
directiveDescriptors: DirectiveDescriptor[];
|
|
908
910
|
codeBlockEditorDescriptors: CodeBlockEditorDescriptor[];
|
|
909
911
|
/**
|
|
@@ -1869,6 +1871,18 @@ export declare interface JsxEditorProps {
|
|
|
1869
1871
|
*/
|
|
1870
1872
|
export declare const jsxIsAvailable$: NodeRef<boolean>;
|
|
1871
1873
|
|
|
1874
|
+
/**
|
|
1875
|
+
* Controls how parsed JSX node kinds are reconciled with component descriptors.
|
|
1876
|
+
* @group JSX
|
|
1877
|
+
*/
|
|
1878
|
+
export declare const jsxKindMismatchPolicy$: NodeRef<JsxKindMismatchPolicy>;
|
|
1879
|
+
|
|
1880
|
+
/**
|
|
1881
|
+
* Controls how parsed JSX node kinds are reconciled with component descriptors.
|
|
1882
|
+
* @group JSX
|
|
1883
|
+
*/
|
|
1884
|
+
export declare type JsxKindMismatchPolicy = 'source' | 'normalize' | 'error';
|
|
1885
|
+
|
|
1872
1886
|
/**
|
|
1873
1887
|
* a plugin that adds support for JSX elements (MDX).
|
|
1874
1888
|
* @group JSX
|
|
@@ -1887,6 +1901,11 @@ export declare interface JsxPluginParams {
|
|
|
1887
1901
|
* Whether or not to allow default React fragments <></> processing in MDX.
|
|
1888
1902
|
*/
|
|
1889
1903
|
allowFragment?: boolean;
|
|
1904
|
+
/**
|
|
1905
|
+
* Controls whether the parsed JSX kind or the component descriptor is authoritative when they disagree.
|
|
1906
|
+
* @defaultValue 'source'
|
|
1907
|
+
*/
|
|
1908
|
+
kindMismatchPolicy?: JsxKindMismatchPolicy;
|
|
1890
1909
|
}
|
|
1891
1910
|
|
|
1892
1911
|
export declare type JsxProperties = Record<string, string | ExpressionValue>;
|
|
@@ -2252,6 +2271,7 @@ export declare interface MdastImportVisitor<UN extends Mdast.Nodes> {
|
|
|
2252
2271
|
* Default 0, optional, sets the priority of the visitor. The higher the number, the earlier it will be called.
|
|
2253
2272
|
*/
|
|
2254
2273
|
priority?: number;
|
|
2274
|
+
/* Excluded from this release type: jsxKindReconciliationOwner */
|
|
2255
2275
|
}
|
|
2256
2276
|
|
|
2257
2277
|
/**
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { MDXEditor } from "./MDXEditor.js";
|
|
|
4
4
|
import { defaultSvgIcons } from "./defaultSvgIcons.js";
|
|
5
5
|
import { MarkdownParseError, UnrecognizedMarkdownConstructError, importMarkdownToLexical, importMdastTreeToLexical } from "./importMarkdownToLexical.js";
|
|
6
6
|
import { exportLexicalTreeToMdast, exportMarkdownFromLexical } from "./exportMarkdownFromLexical.js";
|
|
7
|
-
import { Appender, NESTED_EDITOR_UPDATED_COMMAND, activeEditor$, activeEditorSubscriptions$, activePlugins$, addActivePlugin$, addBottomAreaChild$, addComposerChild$, addEditorWrapper$, addExportVisitor$, addImportVisitor$, addLexicalNode$, addMdastExtension$, addNestedEditorChild$, addSyntaxExtension$, addTableCellEditorChild$, addToMarkdownExtension$, addTopAreaChild$, applyBlockType$, applyFormat$, autoFocus$, bottomAreaChildren$, codeBlockEditorDescriptors$, composerChildren$, contentEditableClassName$, contentEditableRef$, contentEditableWrapperElement$, convertSelectionToNode$, corePlugin, createActiveEditorSubscription$, createRootEditorSubscription$, currentBlockType$, currentFormat$, currentSelection$, defaultCodeBlockLanguage$, directiveDescriptors$, editorInFocus$, editorInTable$, editorRootElementRef$, editorWrapperElementRef$, editorWrappers$, exportVisitors$, historyState$, iconComponentFor$, importVisitors$, inFocus$, initialMarkdown$, initialMarkdownNormalize$, insertDecoratorNode$, insertMarkdown$, jsxComponentDescriptors$, jsxIsAvailable$, lexicalTheme$, markdown$, markdownErrorSignal$, markdownProcessingError$, markdownSourceEditorValue$, mdastExtensions$, muteChange$, nestedEditorChildren$, onBlur$, placeholder$, readOnly$, rootEditor$, rootEditorSubscriptions$, setMarkdown$, spellCheck$, syntaxExtensions$, tableCellEditorChildren$, toMarkdownExtensions$, toMarkdownOptions$, topAreaChildren$, translation$, useTranslation, usedLexicalNodes$, viewMode$ } from "./plugins/core/index.js";
|
|
7
|
+
import { Appender, NESTED_EDITOR_UPDATED_COMMAND, activeEditor$, activeEditorSubscriptions$, activePlugins$, addActivePlugin$, addBottomAreaChild$, addComposerChild$, addEditorWrapper$, addExportVisitor$, addImportVisitor$, addLexicalNode$, addMdastExtension$, addNestedEditorChild$, addSyntaxExtension$, addTableCellEditorChild$, addToMarkdownExtension$, addTopAreaChild$, applyBlockType$, applyFormat$, autoFocus$, bottomAreaChildren$, codeBlockEditorDescriptors$, composerChildren$, contentEditableClassName$, contentEditableRef$, contentEditableWrapperElement$, convertSelectionToNode$, corePlugin, createActiveEditorSubscription$, createRootEditorSubscription$, currentBlockType$, currentFormat$, currentSelection$, defaultCodeBlockLanguage$, directiveDescriptors$, editorInFocus$, editorInTable$, editorRootElementRef$, editorWrapperElementRef$, editorWrappers$, exportVisitors$, historyState$, iconComponentFor$, importVisitors$, inFocus$, initialMarkdown$, initialMarkdownNormalize$, insertDecoratorNode$, insertMarkdown$, jsxComponentDescriptors$, jsxIsAvailable$, jsxKindMismatchPolicy$, lexicalTheme$, markdown$, markdownErrorSignal$, markdownProcessingError$, markdownSourceEditorValue$, mdastExtensions$, muteChange$, nestedEditorChildren$, onBlur$, placeholder$, readOnly$, rootEditor$, rootEditorSubscriptions$, setMarkdown$, spellCheck$, syntaxExtensions$, tableCellEditorChildren$, toMarkdownExtensions$, toMarkdownOptions$, topAreaChildren$, translation$, useTranslation, usedLexicalNodes$, viewMode$ } from "./plugins/core/index.js";
|
|
8
8
|
import { ALL_HEADING_LEVELS, allowedHeadingLevels$, headingsPlugin } from "./plugins/headings/index.js";
|
|
9
9
|
import { insertThematicBreak$, thematicBreakPlugin } from "./plugins/thematic-break/index.js";
|
|
10
10
|
import { applyListType$, currentListType$, listsPlugin } from "./plugins/lists/index.js";
|
|
@@ -280,6 +280,7 @@ export {
|
|
|
280
280
|
joinProc,
|
|
281
281
|
jsxComponentDescriptors$,
|
|
282
282
|
jsxIsAvailable$,
|
|
283
|
+
jsxKindMismatchPolicy$,
|
|
283
284
|
jsxPlugin,
|
|
284
285
|
lexical,
|
|
285
286
|
lexicalTheme,
|
|
@@ -66,7 +66,7 @@ const GenericJsxEditor = ({ mdastNode, descriptor, PropertyEditor }) => {
|
|
|
66
66
|
return /* @__PURE__ */ React__default.createElement("div", { className: descriptor.kind === "text" ? styles.inlineEditor : styles.blockEditor }, shouldRenderComponentName ? /* @__PURE__ */ React__default.createElement("span", { className: styles.genericComponentName }, mdastNode.name ?? "Fragment") : null, descriptor.props.length > 0 ? /* @__PURE__ */ React__default.createElement(PropertyEditorComponent, { properties, title: mdastNode.name ?? "", onChange }) : null, descriptor.hasChildren ? /* @__PURE__ */ React__default.createElement(
|
|
67
67
|
NestedLexicalEditor,
|
|
68
68
|
{
|
|
69
|
-
block:
|
|
69
|
+
block: mdastNode.type === "mdxJsxFlowElement",
|
|
70
70
|
getContent: (node) => node.children,
|
|
71
71
|
getUpdatedMdastNode: (mdastNode2, children) => {
|
|
72
72
|
return { ...mdastNode2, children };
|
|
@@ -14,6 +14,7 @@ import { mdxJsx } from "micromark-extension-mdx-jsx";
|
|
|
14
14
|
import { mdxMd } from "micromark-extension-mdx-md";
|
|
15
15
|
import { exportMarkdownFromLexical } from "../../exportMarkdownFromLexical.js";
|
|
16
16
|
import { importMarkdownToLexical, MarkdownParseError, UnrecognizedMarkdownConstructError } from "../../importMarkdownToLexical.js";
|
|
17
|
+
import { JsxKindMismatchError } from "../jsx/reconcileJsxKind.js";
|
|
17
18
|
import { noop } from "../../utils/fp.js";
|
|
18
19
|
import { GenericHTMLNode } from "./GenericHTMLNode.js";
|
|
19
20
|
import { $createGenericHTMLNode, $isGenericHTMLNode, TYPE_NAME } from "./GenericHTMLNode.js";
|
|
@@ -112,6 +113,7 @@ const toMarkdownExtensions$ = Cell([]);
|
|
|
112
113
|
const toMarkdownOptions$ = Cell({});
|
|
113
114
|
const jsxIsAvailable$ = Cell(false);
|
|
114
115
|
const jsxComponentDescriptors$ = Cell([]);
|
|
116
|
+
const jsxKindMismatchPolicy$ = Cell("source");
|
|
115
117
|
const directiveDescriptors$ = Cell([]);
|
|
116
118
|
const codeBlockEditorDescriptors$ = Cell([]);
|
|
117
119
|
const defaultCodeBlockLanguage$ = Cell("");
|
|
@@ -376,13 +378,14 @@ function tryImportingMarkdown(r, node, markdownValue) {
|
|
|
376
378
|
markdown: markdownValue,
|
|
377
379
|
syntaxExtensions: r.getValue(syntaxExtensions$),
|
|
378
380
|
jsxComponentDescriptors: r.getValue(jsxComponentDescriptors$),
|
|
381
|
+
jsxKindMismatchPolicy: r.getValue(jsxKindMismatchPolicy$),
|
|
379
382
|
directiveDescriptors: r.getValue(directiveDescriptors$),
|
|
380
383
|
codeBlockEditorDescriptors: r.getValue(codeBlockEditorDescriptors$),
|
|
381
384
|
defaultCodeBlockLanguage: r.getValue(defaultCodeBlockLanguage$)
|
|
382
385
|
});
|
|
383
386
|
r.pub(markdownProcessingError$, null);
|
|
384
387
|
} catch (e) {
|
|
385
|
-
if (e instanceof MarkdownParseError || e instanceof UnrecognizedMarkdownConstructError) {
|
|
388
|
+
if (e instanceof MarkdownParseError || e instanceof UnrecognizedMarkdownConstructError || e instanceof JsxKindMismatchError) {
|
|
386
389
|
r.pubIn({
|
|
387
390
|
[markdown$]: markdownValue,
|
|
388
391
|
[markdownProcessingError$]: {
|
|
@@ -663,6 +666,7 @@ export {
|
|
|
663
666
|
insertMarkdown$,
|
|
664
667
|
jsxComponentDescriptors$,
|
|
665
668
|
jsxIsAvailable$,
|
|
669
|
+
jsxKindMismatchPolicy$,
|
|
666
670
|
lexicalTheme$,
|
|
667
671
|
markdown$,
|
|
668
672
|
markdownErrorSignal$,
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { $createParagraphNode } from "lexical";
|
|
2
1
|
import { $createLexicalJsxNode } from "./LexicalJsxNode.js";
|
|
3
2
|
const MdastMdxJsxElementVisitor = {
|
|
4
3
|
testNode: (node, { jsxComponentDescriptors }) => {
|
|
@@ -8,20 +7,13 @@ const MdastMdxJsxElementVisitor = {
|
|
|
8
7
|
}
|
|
9
8
|
return false;
|
|
10
9
|
},
|
|
11
|
-
visitNode({ lexicalParent, mdastNode,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const paragraph = $createParagraphNode();
|
|
16
|
-
paragraph.append($createLexicalJsxNode(patchedNode, mdastNode.name ? metaData.importDeclarations[mdastNode.name] : void 0));
|
|
17
|
-
lexicalParent.append(paragraph);
|
|
18
|
-
} else {
|
|
19
|
-
lexicalParent.append(
|
|
20
|
-
$createLexicalJsxNode(mdastNode, mdastNode.name ? metaData.importDeclarations[mdastNode.name] : void 0)
|
|
21
|
-
);
|
|
22
|
-
}
|
|
10
|
+
visitNode({ lexicalParent, mdastNode, metaData }) {
|
|
11
|
+
lexicalParent.append(
|
|
12
|
+
$createLexicalJsxNode(mdastNode, mdastNode.name ? metaData.importDeclarations[mdastNode.name] : void 0)
|
|
13
|
+
);
|
|
23
14
|
},
|
|
24
|
-
priority: -200
|
|
15
|
+
priority: -200,
|
|
16
|
+
jsxKindReconciliationOwner: true
|
|
25
17
|
};
|
|
26
18
|
export {
|
|
27
19
|
MdastMdxJsxElementVisitor
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { mdxToMarkdown, mdxFromMarkdown } from "mdast-util-mdx";
|
|
2
2
|
import { mdxjs } from "micromark-extension-mdxjs";
|
|
3
|
-
import { insertDecoratorNode$, jsxComponentDescriptors$, addToMarkdownExtension$, addExportVisitor$, addLexicalNode$, addImportVisitor$, addSyntaxExtension$, addMdastExtension$, jsxIsAvailable$ } from "../core/index.js";
|
|
3
|
+
import { insertDecoratorNode$, jsxKindMismatchPolicy$, jsxComponentDescriptors$, addToMarkdownExtension$, addExportVisitor$, addLexicalNode$, addImportVisitor$, addSyntaxExtension$, addMdastExtension$, jsxIsAvailable$ } from "../core/index.js";
|
|
4
4
|
import { $createLexicalJsxNode, LexicalJsxNode } from "./LexicalJsxNode.js";
|
|
5
5
|
import { LexicalJsxVisitor } from "./LexicalJsxVisitor.js";
|
|
6
6
|
import { MdastMdxJsEsmVisitor } from "./MdastMdxJsEsmVisitor.js";
|
|
@@ -83,11 +83,15 @@ const jsxPlugin = realmPlugin({
|
|
|
83
83
|
[addLexicalNode$]: [LexicalJsxNode, LexicalMdxExpressionNode],
|
|
84
84
|
[addExportVisitor$]: [LexicalJsxVisitor, LexicalMdxExpressionVisitor],
|
|
85
85
|
[addToMarkdownExtension$]: mdxToMarkdown(),
|
|
86
|
-
[jsxComponentDescriptors$]: getDescriptors(params)
|
|
86
|
+
[jsxComponentDescriptors$]: getDescriptors(params),
|
|
87
|
+
[jsxKindMismatchPolicy$]: (params == null ? void 0 : params.kindMismatchPolicy) ?? "source"
|
|
87
88
|
});
|
|
88
89
|
},
|
|
89
90
|
update(realm, params) {
|
|
90
|
-
realm.
|
|
91
|
+
realm.pubIn({
|
|
92
|
+
[jsxComponentDescriptors$]: getDescriptors(params),
|
|
93
|
+
[jsxKindMismatchPolicy$]: (params == null ? void 0 : params.kindMismatchPolicy) ?? "source"
|
|
94
|
+
});
|
|
91
95
|
}
|
|
92
96
|
});
|
|
93
97
|
export {
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
class JsxKindMismatchError extends Error {
|
|
2
|
+
constructor(node, descriptor, policy, reason) {
|
|
3
|
+
const name = node.name ?? "Fragment";
|
|
4
|
+
const parsedKind = node.type === "mdxJsxFlowElement" ? "flow" : "text";
|
|
5
|
+
const detail = reason ? ` ${reason}` : "";
|
|
6
|
+
super(
|
|
7
|
+
`JSX component "${name}" was parsed as ${parsedKind} but is declared as ${descriptor.kind} (kindMismatchPolicy: "${policy}").${detail}`
|
|
8
|
+
);
|
|
9
|
+
this.name = "JsxKindMismatchError";
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
const phrasingParentTypes = /* @__PURE__ */ new Set([
|
|
13
|
+
"paragraph",
|
|
14
|
+
"heading",
|
|
15
|
+
"emphasis",
|
|
16
|
+
"strong",
|
|
17
|
+
"delete",
|
|
18
|
+
"link",
|
|
19
|
+
"linkReference",
|
|
20
|
+
"tableCell",
|
|
21
|
+
"footnote",
|
|
22
|
+
"mdxJsxTextElement",
|
|
23
|
+
"textDirective",
|
|
24
|
+
"leafDirective"
|
|
25
|
+
]);
|
|
26
|
+
const flowParentTypes = /* @__PURE__ */ new Set(["root", "blockquote", "listItem", "footnoteDefinition", "mdxJsxFlowElement", "containerDirective"]);
|
|
27
|
+
function isJsxNode(node) {
|
|
28
|
+
return node.type === "mdxJsxFlowElement" || node.type === "mdxJsxTextElement";
|
|
29
|
+
}
|
|
30
|
+
function findDescriptor(node, descriptors) {
|
|
31
|
+
return descriptors.find((descriptor) => descriptor.name === node.name) ?? descriptors.find((descriptor) => descriptor.name === "*");
|
|
32
|
+
}
|
|
33
|
+
function isMismatch(node, descriptor) {
|
|
34
|
+
return (node.type === "mdxJsxFlowElement" ? "flow" : "text") !== descriptor.kind;
|
|
35
|
+
}
|
|
36
|
+
function assertNoMismatches(node, descriptors, shouldReconcile) {
|
|
37
|
+
if (isJsxNode(node)) {
|
|
38
|
+
const descriptor = findDescriptor(node, descriptors);
|
|
39
|
+
if (descriptor && shouldReconcile(node) && isMismatch(node, descriptor)) {
|
|
40
|
+
throw new JsxKindMismatchError(node, descriptor, "error");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if ("children" in node) {
|
|
44
|
+
node.children.forEach((child) => {
|
|
45
|
+
assertNoMismatches(child, descriptors, shouldReconcile);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function normalizeTree(root, descriptors, shouldReconcile) {
|
|
50
|
+
const findOwnedDescriptor = (node) => shouldReconcile(node) ? findDescriptor(node, descriptors) : void 0;
|
|
51
|
+
function normalizeParent(node) {
|
|
52
|
+
const context = phrasingParentTypes.has(node.type) ? "phrasing" : flowParentTypes.has(node.type) ? "flow" : "structural";
|
|
53
|
+
if (context === "phrasing") {
|
|
54
|
+
node.children = node.children.flatMap((child) => normalizePhrasingChild(child, node.type));
|
|
55
|
+
} else if (context === "flow") {
|
|
56
|
+
node.children = node.children.flatMap((child) => normalizeFlowChild(child));
|
|
57
|
+
} else {
|
|
58
|
+
node.children = node.children.map((child) => normalizeStructuralChild(child, node.type));
|
|
59
|
+
}
|
|
60
|
+
return node;
|
|
61
|
+
}
|
|
62
|
+
function normalizeDescendants(node) {
|
|
63
|
+
if ("children" in node) {
|
|
64
|
+
normalizeParent(node);
|
|
65
|
+
}
|
|
66
|
+
return node;
|
|
67
|
+
}
|
|
68
|
+
function normalizeStructuralChild(node, parentType) {
|
|
69
|
+
if (isJsxNode(node)) {
|
|
70
|
+
const descriptor = findOwnedDescriptor(node);
|
|
71
|
+
if (descriptor && isMismatch(node, descriptor)) {
|
|
72
|
+
throw new JsxKindMismatchError(
|
|
73
|
+
node,
|
|
74
|
+
descriptor,
|
|
75
|
+
"normalize",
|
|
76
|
+
`The ${parentType} parent does not declare whether its children are flow or phrasing content.`
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return normalizeDescendants(node);
|
|
81
|
+
}
|
|
82
|
+
function normalizePhrasingChild(node, parentType) {
|
|
83
|
+
if (!isJsxNode(node)) {
|
|
84
|
+
return [normalizeDescendants(node)];
|
|
85
|
+
}
|
|
86
|
+
const descriptor = findOwnedDescriptor(node);
|
|
87
|
+
if (!descriptor || !isMismatch(node, descriptor)) {
|
|
88
|
+
return [normalizeDescendants(node)];
|
|
89
|
+
}
|
|
90
|
+
if (node.type === "mdxJsxTextElement") {
|
|
91
|
+
throw new JsxKindMismatchError(
|
|
92
|
+
node,
|
|
93
|
+
descriptor,
|
|
94
|
+
"normalize",
|
|
95
|
+
`It cannot be lifted from ${parentType} without changing surrounding phrasing content.`
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
const textNode = convertFlowToText(node, descriptor);
|
|
99
|
+
return [normalizeDescendants(textNode)];
|
|
100
|
+
}
|
|
101
|
+
function normalizeParagraph(node) {
|
|
102
|
+
const flowMismatch = node.children.find((child) => {
|
|
103
|
+
if (child.type !== "mdxJsxTextElement") {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
const descriptor2 = findOwnedDescriptor(child);
|
|
107
|
+
return (descriptor2 == null ? void 0 : descriptor2.kind) === "flow";
|
|
108
|
+
});
|
|
109
|
+
if (!flowMismatch) {
|
|
110
|
+
return [normalizeParent(node)];
|
|
111
|
+
}
|
|
112
|
+
const descriptor = findOwnedDescriptor(flowMismatch);
|
|
113
|
+
if (node.children.length !== 1) {
|
|
114
|
+
throw new JsxKindMismatchError(
|
|
115
|
+
flowMismatch,
|
|
116
|
+
descriptor,
|
|
117
|
+
"normalize",
|
|
118
|
+
"It has surrounding phrasing content, and normalization would need to split the paragraph."
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
const flowNode = {
|
|
122
|
+
...flowMismatch,
|
|
123
|
+
type: "mdxJsxFlowElement",
|
|
124
|
+
children: flowMismatch.children.length === 0 ? [] : [{ type: "paragraph", children: flowMismatch.children }]
|
|
125
|
+
};
|
|
126
|
+
return [normalizeDescendants(flowNode)];
|
|
127
|
+
}
|
|
128
|
+
function normalizeFlowChild(node) {
|
|
129
|
+
if (node.type === "paragraph") {
|
|
130
|
+
return normalizeParagraph(node);
|
|
131
|
+
}
|
|
132
|
+
if (!isJsxNode(node)) {
|
|
133
|
+
return [normalizeDescendants(node)];
|
|
134
|
+
}
|
|
135
|
+
const descriptor = findOwnedDescriptor(node);
|
|
136
|
+
if (!descriptor || !isMismatch(node, descriptor)) {
|
|
137
|
+
return [normalizeDescendants(node)];
|
|
138
|
+
}
|
|
139
|
+
if (node.type === "mdxJsxTextElement") {
|
|
140
|
+
throw new JsxKindMismatchError(
|
|
141
|
+
node,
|
|
142
|
+
descriptor,
|
|
143
|
+
"normalize",
|
|
144
|
+
"A text JSX node can be normalized to flow only when it is the sole child of a paragraph."
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
const textNode = normalizeDescendants(convertFlowToText(node, descriptor));
|
|
148
|
+
return [{ type: "paragraph", children: [textNode] }];
|
|
149
|
+
}
|
|
150
|
+
function convertFlowToText(node, descriptor) {
|
|
151
|
+
if (node.children.length === 0) {
|
|
152
|
+
return { ...node, type: "mdxJsxTextElement", children: [] };
|
|
153
|
+
}
|
|
154
|
+
if (node.children.length !== 1 || node.children[0].type !== "paragraph") {
|
|
155
|
+
throw new JsxKindMismatchError(
|
|
156
|
+
node,
|
|
157
|
+
descriptor,
|
|
158
|
+
"normalize",
|
|
159
|
+
"Its block children cannot be represented as one phrasing-content sequence without data loss."
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
return { ...node, type: "mdxJsxTextElement", children: node.children[0].children };
|
|
163
|
+
}
|
|
164
|
+
return normalizeParent(root);
|
|
165
|
+
}
|
|
166
|
+
function reconcileJsxKindMismatches(root, descriptors, policy, shouldReconcile = () => true) {
|
|
167
|
+
if (policy === "source") {
|
|
168
|
+
return root;
|
|
169
|
+
}
|
|
170
|
+
if (policy === "error") {
|
|
171
|
+
assertNoMismatches(root, descriptors, shouldReconcile);
|
|
172
|
+
return root;
|
|
173
|
+
}
|
|
174
|
+
return normalizeTree(structuredClone(root), descriptors, shouldReconcile);
|
|
175
|
+
}
|
|
176
|
+
export {
|
|
177
|
+
JsxKindMismatchError,
|
|
178
|
+
reconcileJsxKindMismatches
|
|
179
|
+
};
|