UNPKG

@mdxeditor/editor

Version:

React component for rich text markdown editing

175 lines (174 loc) 5.39 kB
import { fromMarkdown } from "mdast-util-from-markdown"; import { toMarkdown } from "mdast-util-to-markdown"; function isParent(node) { return node.children instanceof Array; } class MarkdownParseError extends Error { constructor(message, cause) { super(message); this.name = "MarkdownParseError"; this.cause = cause; } } class UnrecognizedMarkdownConstructError extends Error { constructor(message) { super(message); this.name = "UnrecognizedMarkdownConstructError"; } } function gatherMetadata(mdastNode) { const importsMap = /* @__PURE__ */ new Map(); if (mdastNode.type !== "root") { return { importDeclarations: {} }; } const importStatements = mdastNode.children.filter((n) => n.type === "mdxjsEsm").filter((n) => n.value.startsWith("import ")); importStatements.forEach((imp) => { var _a, _b; (((_b = (_a = imp.data) == null ? void 0 : _a.estree) == null ? void 0 : _b.body) ?? []).forEach((declaration) => { if (declaration.type !== "ImportDeclaration") { return; } declaration.specifiers.forEach((specifier) => { importsMap.set(specifier.local.name, { source: `${declaration.source.value}`, defaultExport: specifier.type === "ImportDefaultSpecifier" }); }); }); }); return { importDeclarations: Object.fromEntries(importsMap.entries()) }; } function importMarkdownToLexical({ root, markdown, visitors, syntaxExtensions, mdastExtensions, ...descriptors }) { var _a; let mdastRoot; try { mdastRoot = fromMarkdown(markdown, { extensions: syntaxExtensions, mdastExtensions }); } catch (e) { if (e instanceof Error) { throw new MarkdownParseError(`Error parsing markdown: ${e.message}`, e); } else { throw new MarkdownParseError(`Error parsing markdown: ${e}`, e); } } if (mdastRoot.children.length === 0) { mdastRoot.children.push({ type: "paragraph", children: [] }); } if (((_a = mdastRoot.children.at(-1)) == null ? void 0 : _a.type) !== "paragraph") { mdastRoot.children.push({ type: "paragraph", children: [] }); } importMdastTreeToLexical({ root, mdastRoot, visitors, ...descriptors }); } function importMdastTreeToLexical({ root, mdastRoot, visitors, ...descriptors }) { const formattingMap = /* @__PURE__ */ new WeakMap(); const styleMap = /* @__PURE__ */ new WeakMap(); const metaData = gatherMetadata(mdastRoot); visitors = visitors.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0)); function visitChildren(mdastNode, lexicalParent) { if (!isParent(mdastNode)) { throw new Error("Attempting to visit children of a non-parent"); } mdastNode.children.forEach((child) => { visit(child, lexicalParent, mdastNode); }); } function visit(mdastNode, lexicalParent, mdastParent, skipVisitors = null) { const visitor = visitors.find((visitor2, index) => { if (skipVisitors == null ? void 0 : skipVisitors.has(index)) { return false; } if (typeof visitor2.testNode === "string") { return visitor2.testNode === mdastNode.type; } return visitor2.testNode(mdastNode, descriptors); }); if (!visitor) { try { throw new UnrecognizedMarkdownConstructError(`Unsupported markdown syntax: ${toMarkdown(mdastNode)}`); } catch (e) { throw new UnrecognizedMarkdownConstructError( `Parsing of the following markdown structure failed: ${JSON.stringify({ type: mdastNode.type, name: "name" in mdastNode ? mdastNode.name : "N/A" })}` ); } } visitor.visitNode({ //@ts-expect-error root type is glitching mdastNode, lexicalParent, mdastParent, descriptors, metaData, actions: { visitChildren, nextVisitor() { visit(mdastNode, lexicalParent, mdastParent, (skipVisitors ?? /* @__PURE__ */ new Set()).add(visitors.indexOf(visitor))); }, addAndStepInto(lexicalNode) { lexicalParent.append(lexicalNode); if (isParent(mdastNode)) { visitChildren(mdastNode, lexicalNode); } }, addFormatting(format, node) { if (!node) { if (isParent(mdastNode)) { node = mdastNode; } } if (node) { formattingMap.set(node, format | (formattingMap.get(mdastParent) ?? 0)); } }, removeFormatting(format, node) { if (!node) { if (isParent(mdastNode)) { node = mdastNode; } } if (node) { formattingMap.set(node, format ^ (formattingMap.get(mdastParent) ?? 0)); } }, getParentFormatting() { return formattingMap.get(mdastParent) ?? 0; }, addStyle(style, node) { if (!node) { if (isParent(mdastNode)) { node = mdastNode; } } if (node) { styleMap.set(node, style); } }, getParentStyle() { return styleMap.get(mdastParent) ?? ""; } } }); } visit(mdastRoot, root, null); } export { MarkdownParseError, UnrecognizedMarkdownConstructError, importMarkdownToLexical, importMdastTreeToLexical };