@mx-space/cli 0.1.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/LICENSE +33 -0
- package/README.md +375 -0
- package/ROADMAP.md +42 -0
- package/bin/mxs.cjs +40 -0
- package/dist/Lexical.dev-DpU35QTu.mjs +10992 -0
- package/dist/Lexical.dev-DpU35QTu.mjs.map +1 -0
- package/dist/Lexical.node-gYNDt_p9.mjs +247 -0
- package/dist/Lexical.node-gYNDt_p9.mjs.map +1 -0
- package/dist/Lexical.prod-t4c3bHV3.mjs +5579 -0
- package/dist/Lexical.prod-t4c3bHV3.mjs.map +1 -0
- package/dist/LexicalClipboard.dev-CdeeWCIq.mjs +496 -0
- package/dist/LexicalClipboard.dev-CdeeWCIq.mjs.map +1 -0
- package/dist/LexicalClipboard.node-0e9GBL1g.mjs +26 -0
- package/dist/LexicalClipboard.node-0e9GBL1g.mjs.map +1 -0
- package/dist/LexicalClipboard.prod-CsCWYmV7.mjs +293 -0
- package/dist/LexicalClipboard.prod-CsCWYmV7.mjs.map +1 -0
- package/dist/LexicalCodeCore.dev-haI2cqH8.mjs +539 -0
- package/dist/LexicalCodeCore.dev-haI2cqH8.mjs.map +1 -0
- package/dist/LexicalCodeCore.prod-D_k7zuE5.mjs +383 -0
- package/dist/LexicalCodeCore.prod-D_k7zuE5.mjs.map +1 -0
- package/dist/LexicalDragon.dev-CAggdFh_.mjs +90 -0
- package/dist/LexicalDragon.dev-CAggdFh_.mjs.map +1 -0
- package/dist/LexicalDragon.node-QMR_wqJg.mjs +15 -0
- package/dist/LexicalDragon.node-QMR_wqJg.mjs.map +1 -0
- package/dist/LexicalDragon.prod-OssQhwS-.mjs +61 -0
- package/dist/LexicalDragon.prod-OssQhwS-.mjs.map +1 -0
- package/dist/LexicalExtension.dev-CtDZiMCU.mjs +1665 -0
- package/dist/LexicalExtension.dev-CtDZiMCU.mjs.map +1 -0
- package/dist/LexicalExtension.node-BM0gh8zu.mjs +51 -0
- package/dist/LexicalExtension.node-BM0gh8zu.mjs.map +1 -0
- package/dist/LexicalExtension.prod-Ug6emhEO.mjs +971 -0
- package/dist/LexicalExtension.prod-Ug6emhEO.mjs.map +1 -0
- package/dist/LexicalHeadless.dev-D4yQpl_s.mjs +45 -0
- package/dist/LexicalHeadless.dev-D4yQpl_s.mjs.map +1 -0
- package/dist/LexicalHeadless.prod-jeN65B3k.mjs +31 -0
- package/dist/LexicalHeadless.prod-jeN65B3k.mjs.map +1 -0
- package/dist/LexicalHtml.dev-BdU1_ITQ.mjs +686 -0
- package/dist/LexicalHtml.dev-BdU1_ITQ.mjs.map +1 -0
- package/dist/LexicalHtml.node-DLtAh00E.mjs +26 -0
- package/dist/LexicalHtml.node-DLtAh00E.mjs.map +1 -0
- package/dist/LexicalHtml.prod-DdLE1HHT.mjs +432 -0
- package/dist/LexicalHtml.prod-DdLE1HHT.mjs.map +1 -0
- package/dist/LexicalLink.dev-DK87Biuy.mjs +1084 -0
- package/dist/LexicalLink.dev-DK87Biuy.mjs.map +1 -0
- package/dist/LexicalLink.prod-fssuv6Sf.mjs +717 -0
- package/dist/LexicalLink.prod-fssuv6Sf.mjs.map +1 -0
- package/dist/LexicalList.dev-BJ4dr_rk.mjs +1352 -0
- package/dist/LexicalList.dev-BJ4dr_rk.mjs.map +1 -0
- package/dist/LexicalList.prod-jWBbaWfi.mjs +841 -0
- package/dist/LexicalList.prod-jWBbaWfi.mjs.map +1 -0
- package/dist/LexicalMarkdown.dev-C8e-eh6y.mjs +1207 -0
- package/dist/LexicalMarkdown.dev-C8e-eh6y.mjs.map +1 -0
- package/dist/LexicalMarkdown.prod-k73tZVb2.mjs +756 -0
- package/dist/LexicalMarkdown.prod-k73tZVb2.mjs.map +1 -0
- package/dist/LexicalRichText.dev-CrSqq3K-.mjs +645 -0
- package/dist/LexicalRichText.dev-CrSqq3K-.mjs.map +1 -0
- package/dist/LexicalRichText.node-B7k7wlQz.mjs +106 -0
- package/dist/LexicalRichText.node-B7k7wlQz.mjs.map +1 -0
- package/dist/LexicalRichText.prod-CqvyxQ9m.mjs +429 -0
- package/dist/LexicalRichText.prod-CqvyxQ9m.mjs.map +1 -0
- package/dist/LexicalSelection.dev-sNOHKHe_.mjs +725 -0
- package/dist/LexicalSelection.dev-sNOHKHe_.mjs.map +1 -0
- package/dist/LexicalSelection.node-Di7GwBCZ.mjs +38 -0
- package/dist/LexicalSelection.node-Di7GwBCZ.mjs.map +1 -0
- package/dist/LexicalSelection.prod-SWllPJop.mjs +388 -0
- package/dist/LexicalSelection.prod-SWllPJop.mjs.map +1 -0
- package/dist/LexicalTable.dev-CQkLHXJx.mjs +3262 -0
- package/dist/LexicalTable.dev-CQkLHXJx.mjs.map +1 -0
- package/dist/LexicalTable.prod-BtqCwKSi.mjs +2218 -0
- package/dist/LexicalTable.prod-BtqCwKSi.mjs.map +1 -0
- package/dist/LexicalUtils.dev-DiUpsXE8.mjs +850 -0
- package/dist/LexicalUtils.dev-DiUpsXE8.mjs.map +1 -0
- package/dist/LexicalUtils.node-CmK462d1.mjs +66 -0
- package/dist/LexicalUtils.node-CmK462d1.mjs.map +1 -0
- package/dist/LexicalUtils.prod-bWwV4GAF.mjs +377 -0
- package/dist/LexicalUtils.prod-bWwV4GAF.mjs.map +1 -0
- package/dist/auth-DIFZzoMm.mjs +211 -0
- package/dist/auth-DIFZzoMm.mjs.map +1 -0
- package/dist/bin/mxs.d.mts +927 -0
- package/dist/bin/mxs.mjs +3249 -0
- package/dist/bin/mxs.mjs.map +1 -0
- package/dist/chunk-hT5z_Zn9.mjs +35 -0
- package/dist/config-store-DIu7x0ao.mjs +121 -0
- package/dist/config-store-DIu7x0ao.mjs.map +1 -0
- package/dist/create-B2AOQL1e.mjs +24 -0
- package/dist/create-B2AOQL1e.mjs.map +1 -0
- package/dist/create-CwjGcv2n.mjs +23 -0
- package/dist/create-CwjGcv2n.mjs.map +1 -0
- package/dist/create-DT1l2hue.mjs +23 -0
- package/dist/create-DT1l2hue.mjs.map +1 -0
- package/dist/create-DjlRHPXy.mjs +23 -0
- package/dist/create-DjlRHPXy.mjs.map +1 -0
- package/dist/create-Dz6rJJSS.mjs +19 -0
- package/dist/create-Dz6rJJSS.mjs.map +1 -0
- package/dist/delete-B4dGrrus.mjs +22 -0
- package/dist/delete-B4dGrrus.mjs.map +1 -0
- package/dist/delete-BH6ZngTz.mjs +22 -0
- package/dist/delete-BH6ZngTz.mjs.map +1 -0
- package/dist/delete-BrY5zJ6S.mjs +22 -0
- package/dist/delete-BrY5zJ6S.mjs.map +1 -0
- package/dist/delete-CaG2d_xt.mjs +31 -0
- package/dist/delete-CaG2d_xt.mjs.map +1 -0
- package/dist/delete-YzRliRn8.mjs +31 -0
- package/dist/delete-YzRliRn8.mjs.map +1 -0
- package/dist/document-output-BVB8emLt.mjs +145 -0
- package/dist/document-output-BVB8emLt.mjs.map +1 -0
- package/dist/edit-Bb0Ze4w6.mjs +79 -0
- package/dist/edit-Bb0Ze4w6.mjs.map +1 -0
- package/dist/edit-BeFmC3XD.mjs +80 -0
- package/dist/edit-BeFmC3XD.mjs.map +1 -0
- package/dist/edit-DLDw_ZWX.mjs +86 -0
- package/dist/edit-DLDw_ZWX.mjs.map +1 -0
- package/dist/edit-z55ofr1S.mjs +40 -0
- package/dist/edit-z55ofr1S.mjs.map +1 -0
- package/dist/editor-xrF-j3UE.mjs +42 -0
- package/dist/editor-xrF-j3UE.mjs.map +1 -0
- package/dist/envelope-overlays-DPAlMNW1.mjs +26 -0
- package/dist/envelope-overlays-DPAlMNW1.mjs.map +1 -0
- package/dist/get-2qjq0wgG.mjs +28 -0
- package/dist/get-2qjq0wgG.mjs.map +1 -0
- package/dist/get-BGAk1Zmv.mjs +14 -0
- package/dist/get-BGAk1Zmv.mjs.map +1 -0
- package/dist/get-CRR13lgj.mjs +10 -0
- package/dist/get-CRR13lgj.mjs.map +1 -0
- package/dist/get-ClkpDBTL.mjs +13 -0
- package/dist/get-ClkpDBTL.mjs.map +1 -0
- package/dist/get-DJfUJ3sP.mjs +10 -0
- package/dist/get-DJfUJ3sP.mjs.map +1 -0
- package/dist/get-DiqaQvoS.mjs +14 -0
- package/dist/get-DiqaQvoS.mjs.map +1 -0
- package/dist/index.d.mts +338 -0
- package/dist/index.mjs +10 -0
- package/dist/list-BYzhflDg.mjs +14 -0
- package/dist/list-BYzhflDg.mjs.map +1 -0
- package/dist/list-DY-tPNG-.mjs +10 -0
- package/dist/list-DY-tPNG-.mjs.map +1 -0
- package/dist/list-DlQSkbqx.mjs +10 -0
- package/dist/list-DlQSkbqx.mjs.map +1 -0
- package/dist/list-DsrA5wIz.mjs +15 -0
- package/dist/list-DsrA5wIz.mjs.map +1 -0
- package/dist/list-Fp4nKfQb.mjs +10 -0
- package/dist/list-Fp4nKfQb.mjs.map +1 -0
- package/dist/list-s_tloiEX.mjs +10 -0
- package/dist/list-s_tloiEX.mjs.map +1 -0
- package/dist/litexml-codec-CDoRloiR.mjs +13451 -0
- package/dist/litexml-codec-CDoRloiR.mjs.map +1 -0
- package/dist/login-CLOJ-fTJ.mjs +579 -0
- package/dist/login-CLOJ-fTJ.mjs.map +1 -0
- package/dist/logout-v8ihxsim.mjs +11 -0
- package/dist/logout-v8ihxsim.mjs.map +1 -0
- package/dist/onboarding-640IldLz.mjs +888 -0
- package/dist/onboarding-640IldLz.mjs.map +1 -0
- package/dist/output-BM7aBFwt.mjs +120 -0
- package/dist/output-BM7aBFwt.mjs.map +1 -0
- package/dist/output-CTnO1lYt.d.mts +16 -0
- package/dist/payload-CN11pUto.mjs +547 -0
- package/dist/payload-CN11pUto.mjs.map +1 -0
- package/dist/publish-DkTYB-eK.mjs +23 -0
- package/dist/publish-DkTYB-eK.mjs.map +1 -0
- package/dist/publish-pRBfTJfe.mjs +23 -0
- package/dist/publish-pRBfTJfe.mjs.map +1 -0
- package/dist/resolve-BogJOR7R.mjs +119 -0
- package/dist/resolve-BogJOR7R.mjs.map +1 -0
- package/dist/resolve-Bp1AfBmM.mjs +26 -0
- package/dist/resolve-Bp1AfBmM.mjs.map +1 -0
- package/dist/resolve-Bw5Po9yK.mjs +16 -0
- package/dist/resolve-Bw5Po9yK.mjs.map +1 -0
- package/dist/resolve-CyjMlaoJ.mjs +23 -0
- package/dist/resolve-CyjMlaoJ.mjs.map +1 -0
- package/dist/resolve-helpers-CahPoJ0Y.mjs +30 -0
- package/dist/resolve-helpers-CahPoJ0Y.mjs.map +1 -0
- package/dist/set-BEGQz2si.mjs +43 -0
- package/dist/set-BEGQz2si.mjs.map +1 -0
- package/dist/shared-D0HVBDHI.mjs +39 -0
- package/dist/shared-D0HVBDHI.mjs.map +1 -0
- package/dist/status-LXrN9fI-.mjs +22 -0
- package/dist/status-LXrN9fI-.mjs.map +1 -0
- package/dist/update-B9ynFCdZ.mjs +30 -0
- package/dist/update-B9ynFCdZ.mjs.map +1 -0
- package/dist/update-BMZQPOvR.mjs +28 -0
- package/dist/update-BMZQPOvR.mjs.map +1 -0
- package/dist/update-BXz0l7Lz.mjs +36 -0
- package/dist/update-BXz0l7Lz.mjs.map +1 -0
- package/dist/update-Dx6AF8tf.mjs +30 -0
- package/dist/update-Dx6AF8tf.mjs.map +1 -0
- package/dist/update-q66TLS38.mjs +37 -0
- package/dist/update-q66TLS38.mjs.map +1 -0
- package/dist/whoami-CTkctOEd.mjs +22 -0
- package/dist/whoami-CTkctOEd.mjs.map +1 -0
- package/package.json +77 -0
|
@@ -0,0 +1,1207 @@
|
|
|
1
|
+
import { _ as LinkNode, a as HeadingNode, c as $createListNode, d as ListItemNode, f as ListNode, h as $isLinkNode, i as $isQuoteNode, l as $isListItemNode, m as $isAutoLinkNode, n as $createQuoteNode, o as QuoteNode, p as $createLinkNode, r as $isHeadingNode, s as $createListItemNode, t as $createHeadingNode, u as $isListNode, v as $createCodeNode, x as CodeNode, y as $isCodeNode } from "./LexicalRichText.node-B7k7wlQz.mjs";
|
|
2
|
+
import { An as createState, At as COMMAND_PRIORITY_LOW, Et as COLLABORATION_TAG, Jt as HISTORY_PUSH_TAG, Kt as HISTORIC_TAG, R as $getRoot, V as $getState, Xn as mergeRegister, Y as $isElementNode, _ as $createTextNode, at as $isRootOrShadowRoot, bt as $setState, ct as $isTextNode, et as $isLineBreakNode, f as $createParagraphNode, g as $createTabNode, m as $createRangeSelection, nt as $isParagraphNode, on as KEY_ENTER_COMMAND, q as $isDecoratorNode, rt as $isRangeSelection, t as $addUpdateTag, u as $createLineBreakNode, vt as $setSelection, y as $findMatchingParent, z as $getSelection } from "./Lexical.node-gYNDt_p9.mjs";
|
|
3
|
+
import { r as $findMatchingParent$1 } from "./LexicalUtils.node-CmK462d1.mjs";
|
|
4
|
+
//#region ../../node_modules/.pnpm/@lexical+markdown@0.44.0/node_modules/@lexical/markdown/LexicalMarkdown.dev.mjs
|
|
5
|
+
/**
|
|
6
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
7
|
+
*
|
|
8
|
+
* This source code is licensed under the MIT license found in the
|
|
9
|
+
* LICENSE file in the root directory of this source tree.
|
|
10
|
+
*
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
14
|
+
*
|
|
15
|
+
* This source code is licensed under the MIT license found in the
|
|
16
|
+
* LICENSE file in the root directory of this source tree.
|
|
17
|
+
*
|
|
18
|
+
*/
|
|
19
|
+
function indexBy(list, callback) {
|
|
20
|
+
const index = {};
|
|
21
|
+
for (const item of list) {
|
|
22
|
+
const key = callback(item);
|
|
23
|
+
if (!key) continue;
|
|
24
|
+
if (index[key]) index[key].push(item);
|
|
25
|
+
else index[key] = [item];
|
|
26
|
+
}
|
|
27
|
+
return index;
|
|
28
|
+
}
|
|
29
|
+
function transformersByType(transformers) {
|
|
30
|
+
const byType = indexBy(transformers, (t) => t.type);
|
|
31
|
+
return {
|
|
32
|
+
element: byType.element || [],
|
|
33
|
+
multilineElement: byType["multiline-element"] || [],
|
|
34
|
+
textFormat: byType["text-format"] || [],
|
|
35
|
+
textMatch: byType["text-match"] || []
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
const PUNCTUATION_OR_SPACE = /[!-/:-@[-`{-~\s]/;
|
|
39
|
+
const WHITESPACE = /[ \t\n\r\f]/;
|
|
40
|
+
const PUNCTUATION = /[!"#$%&'()*+,\-./:;<=>?@[\]^_`{|}~]/;
|
|
41
|
+
const MARKDOWN_EMPTY_LINE_REG_EXP = /^\s{0,3}$/;
|
|
42
|
+
function isEmptyParagraph(node) {
|
|
43
|
+
if (!$isParagraphNode(node)) return false;
|
|
44
|
+
const firstChild = node.getFirstChild();
|
|
45
|
+
return firstChild == null || node.getChildrenSize() === 1 && $isTextNode(firstChild) && MARKDOWN_EMPTY_LINE_REG_EXP.test(firstChild.getTextContent());
|
|
46
|
+
}
|
|
47
|
+
function unescapeText(value) {
|
|
48
|
+
return value.replace(/\\([!-/:-@[-`{-~])/g, "$1").replace(/&#(\d+);/g, (_, codePoint) => String.fromCodePoint(Number(codePoint)));
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
52
|
+
*
|
|
53
|
+
* This source code is licensed under the MIT license found in the
|
|
54
|
+
* LICENSE file in the root directory of this source tree.
|
|
55
|
+
*
|
|
56
|
+
*/
|
|
57
|
+
/**
|
|
58
|
+
* Renders string from markdown. The selection is moved to the start after the operation.
|
|
59
|
+
*/
|
|
60
|
+
function createMarkdownExport(transformers, shouldPreserveNewLines = false) {
|
|
61
|
+
const byType = transformersByType(transformers);
|
|
62
|
+
const elementTransformers = [...byType.multilineElement, ...byType.element];
|
|
63
|
+
const isNewlineDelimited = !shouldPreserveNewLines;
|
|
64
|
+
const textFormatTransformers = byType.textFormat.filter((transformer) => transformer.format.length === 1).sort((a, b) => {
|
|
65
|
+
return Number(a.format.includes("code")) - Number(b.format.includes("code"));
|
|
66
|
+
});
|
|
67
|
+
return (node) => {
|
|
68
|
+
const output = [];
|
|
69
|
+
const children = (node || $getRoot()).getChildren();
|
|
70
|
+
for (let i = 0; i < children.length; i++) {
|
|
71
|
+
const child = children[i];
|
|
72
|
+
const result = exportTopLevelElements(child, elementTransformers, textFormatTransformers, byType.textMatch, shouldPreserveNewLines);
|
|
73
|
+
if (result != null) output.push(isNewlineDelimited && i > 0 && !isEmptyParagraph(child) && !isEmptyParagraph(children[i - 1]) ? "\n".concat(result) : result);
|
|
74
|
+
}
|
|
75
|
+
return output.join("\n");
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function exportTopLevelElements(node, elementTransformers, textTransformersIndex, textMatchTransformers, shouldPreserveNewLines) {
|
|
79
|
+
for (const transformer of elementTransformers) {
|
|
80
|
+
if (!transformer.export) continue;
|
|
81
|
+
const result = transformer.export(node, (_node) => exportChildren(_node, textTransformersIndex, textMatchTransformers, void 0, void 0, shouldPreserveNewLines));
|
|
82
|
+
if (result != null) return result;
|
|
83
|
+
}
|
|
84
|
+
if ($isElementNode(node)) return exportChildren(node, textTransformersIndex, textMatchTransformers, void 0, void 0, shouldPreserveNewLines);
|
|
85
|
+
else if ($isDecoratorNode(node)) return node.getTextContent();
|
|
86
|
+
else return null;
|
|
87
|
+
}
|
|
88
|
+
function exportChildren(node, textTransformersIndex, textMatchTransformers, unclosedTags, unclosableTags, shouldPreserveNewLines = false) {
|
|
89
|
+
const output = [];
|
|
90
|
+
const children = node.getChildren();
|
|
91
|
+
if (!unclosedTags) unclosedTags = [];
|
|
92
|
+
if (!unclosableTags) unclosableTags = [];
|
|
93
|
+
mainLoop: for (const child of children) {
|
|
94
|
+
for (const transformer of textMatchTransformers) {
|
|
95
|
+
if (!transformer.export) continue;
|
|
96
|
+
const result = transformer.export(child, (parentNode) => exportChildren(parentNode, textTransformersIndex, textMatchTransformers, unclosedTags, [...unclosableTags, ...unclosedTags], shouldPreserveNewLines), (textNode, textContent) => exportTextFormat(textNode, textContent, textTransformersIndex, unclosedTags, unclosableTags, shouldPreserveNewLines));
|
|
97
|
+
if (result != null) {
|
|
98
|
+
output.push(result);
|
|
99
|
+
continue mainLoop;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if ($isLineBreakNode(child)) output.push("\n");
|
|
103
|
+
else if ($isTextNode(child)) output.push(exportTextFormat(child, child.getTextContent(), textTransformersIndex, unclosedTags, unclosableTags, shouldPreserveNewLines));
|
|
104
|
+
else if ($isElementNode(child)) output.push(exportChildren(child, textTransformersIndex, textMatchTransformers, unclosedTags, unclosableTags, shouldPreserveNewLines));
|
|
105
|
+
else if ($isDecoratorNode(child)) output.push(child.getTextContent());
|
|
106
|
+
}
|
|
107
|
+
return output.join("");
|
|
108
|
+
}
|
|
109
|
+
function exportTextFormat(node, textContent, textTransformers, unclosedTags, unclosableTags, shouldPreserveNewLines = false) {
|
|
110
|
+
let output = textContent;
|
|
111
|
+
if (!node.hasFormat("code")) output = shouldPreserveNewLines ? output.replace(/([*_`~])/g, "\\$1") : output.replace(/([*_`~\\])/g, "\\$1");
|
|
112
|
+
const match = output.match(/^(\s*)(.*?)(\s*)$/s) || [
|
|
113
|
+
"",
|
|
114
|
+
"",
|
|
115
|
+
output,
|
|
116
|
+
""
|
|
117
|
+
];
|
|
118
|
+
const leadingSpace = match[1];
|
|
119
|
+
const trimmedOutput = match[2];
|
|
120
|
+
const trailingSpace = match[3];
|
|
121
|
+
const isWhitespaceOnly = trimmedOutput === "";
|
|
122
|
+
let openingTags = "";
|
|
123
|
+
let closingTagsBefore = "";
|
|
124
|
+
let closingTagsAfter = "";
|
|
125
|
+
const prevNode = getTextSibling(node, true);
|
|
126
|
+
const nextNode = getTextSibling(node, false);
|
|
127
|
+
const applied = /* @__PURE__ */ new Set();
|
|
128
|
+
for (const transformer of textTransformers) {
|
|
129
|
+
const format = transformer.format[0];
|
|
130
|
+
const tag = transformer.tag;
|
|
131
|
+
if (checkHasFormat(node, format) && !applied.has(format)) {
|
|
132
|
+
applied.add(format);
|
|
133
|
+
if (!checkHasFormat(prevNode, format) || !unclosedTags.find((element) => element.tag === tag)) {
|
|
134
|
+
unclosedTags.push({
|
|
135
|
+
format,
|
|
136
|
+
tag
|
|
137
|
+
});
|
|
138
|
+
openingTags += tag;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
for (let i = 0; i < unclosedTags.length; i++) {
|
|
143
|
+
const nodeHasFormat = hasFormat(node, unclosedTags[i].format);
|
|
144
|
+
const nextNodeHasFormat = hasFormat(nextNode, unclosedTags[i].format);
|
|
145
|
+
if (nodeHasFormat && nextNodeHasFormat) continue;
|
|
146
|
+
const unhandledUnclosedTags = [...unclosedTags];
|
|
147
|
+
while (unhandledUnclosedTags.length > i) {
|
|
148
|
+
const unclosedTag = unhandledUnclosedTags.pop();
|
|
149
|
+
if (unclosableTags && unclosedTag && unclosableTags.find((element) => element.tag === unclosedTag.tag)) continue;
|
|
150
|
+
if (unclosedTag && typeof unclosedTag.tag === "string") {
|
|
151
|
+
if (!nodeHasFormat) closingTagsBefore += unclosedTag.tag;
|
|
152
|
+
else if (!nextNodeHasFormat) closingTagsAfter += unclosedTag.tag;
|
|
153
|
+
}
|
|
154
|
+
unclosedTags.pop();
|
|
155
|
+
}
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
if (isWhitespaceOnly && !node.hasFormat("code")) return closingTagsBefore + output;
|
|
159
|
+
return closingTagsBefore + leadingSpace + openingTags + trimmedOutput + closingTagsAfter + trailingSpace;
|
|
160
|
+
}
|
|
161
|
+
function getTextSibling(node, backward) {
|
|
162
|
+
const sibling = backward ? node.getPreviousSibling() : node.getNextSibling();
|
|
163
|
+
if ($isTextNode(sibling)) return sibling;
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
function hasFormat(node, format) {
|
|
167
|
+
return $isTextNode(node) && node.hasFormat(format);
|
|
168
|
+
}
|
|
169
|
+
function checkHasFormat(n, f) {
|
|
170
|
+
if (!hasFormat(n, f)) return false;
|
|
171
|
+
if (f === "code") return true;
|
|
172
|
+
if (n && /^\s*$/.test(n.getTextContent())) return false;
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
177
|
+
*
|
|
178
|
+
* This source code is licensed under the MIT license found in the
|
|
179
|
+
* LICENSE file in the root directory of this source tree.
|
|
180
|
+
*
|
|
181
|
+
*/
|
|
182
|
+
function findOutermostTextFormatTransformer(textNode, textFormatTransformersIndex) {
|
|
183
|
+
const textContent = textNode.getTextContent();
|
|
184
|
+
const codeRegex = textFormatTransformersIndex.fullMatchRegExpByTag["`"];
|
|
185
|
+
const codeTransformer = textFormatTransformersIndex.transformersByTag["`"];
|
|
186
|
+
const excludeRanges = [];
|
|
187
|
+
let codeMatch = null;
|
|
188
|
+
if (codeRegex && codeTransformer) {
|
|
189
|
+
const globalRegex = new RegExp(codeRegex.source, "g");
|
|
190
|
+
const matches = Array.from(textContent.matchAll(globalRegex));
|
|
191
|
+
for (const match of matches) {
|
|
192
|
+
const startIndex = match.index + match[1].length;
|
|
193
|
+
const endIndex = match.index + match[0].length;
|
|
194
|
+
if (!codeMatch) codeMatch = {
|
|
195
|
+
content: match[3],
|
|
196
|
+
endIndex,
|
|
197
|
+
startIndex,
|
|
198
|
+
tag: "`"
|
|
199
|
+
};
|
|
200
|
+
excludeRanges.push({
|
|
201
|
+
end: endIndex,
|
|
202
|
+
start: startIndex
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
const delimiters = scanDelimiters(textContent, textFormatTransformersIndex, excludeRanges);
|
|
207
|
+
const emphasisMatch = delimiters.length > 0 ? processEmphasis(textContent, delimiters, textFormatTransformersIndex) : null;
|
|
208
|
+
let resultMatch = null;
|
|
209
|
+
let resultTransformer = null;
|
|
210
|
+
if (codeMatch && emphasisMatch) if (emphasisMatch.startIndex <= codeMatch.startIndex && emphasisMatch.endIndex >= codeMatch.endIndex) {
|
|
211
|
+
resultMatch = emphasisMatch;
|
|
212
|
+
resultTransformer = textFormatTransformersIndex.transformersByTag[emphasisMatch.tag];
|
|
213
|
+
} else {
|
|
214
|
+
resultMatch = codeMatch;
|
|
215
|
+
resultTransformer = codeTransformer;
|
|
216
|
+
}
|
|
217
|
+
else if (codeMatch) {
|
|
218
|
+
resultMatch = codeMatch;
|
|
219
|
+
resultTransformer = codeTransformer;
|
|
220
|
+
} else if (emphasisMatch) {
|
|
221
|
+
resultMatch = emphasisMatch;
|
|
222
|
+
resultTransformer = textFormatTransformersIndex.transformersByTag[emphasisMatch.tag];
|
|
223
|
+
}
|
|
224
|
+
if (!resultMatch || !resultTransformer) return null;
|
|
225
|
+
const regexMatch = [
|
|
226
|
+
textContent.slice(resultMatch.startIndex, resultMatch.endIndex),
|
|
227
|
+
resultMatch.tag,
|
|
228
|
+
resultMatch.content
|
|
229
|
+
];
|
|
230
|
+
regexMatch.index = resultMatch.startIndex;
|
|
231
|
+
regexMatch.input = textContent;
|
|
232
|
+
return {
|
|
233
|
+
endIndex: resultMatch.endIndex,
|
|
234
|
+
match: regexMatch,
|
|
235
|
+
startIndex: resultMatch.startIndex,
|
|
236
|
+
transformer: resultTransformer
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
function scanDelimiters(text, transformersIndex, excludeRanges = []) {
|
|
240
|
+
const delimiters = [];
|
|
241
|
+
const delimiterChars = new Set(Object.keys(transformersIndex.transformersByTag).filter((tag) => tag[0] !== "`").map((tag) => tag[0]));
|
|
242
|
+
const isEscaped = (index) => {
|
|
243
|
+
let count = 0;
|
|
244
|
+
for (let i = index - 1; i >= 0 && text[i] === "\\"; i--) count++;
|
|
245
|
+
return count % 2 === 1;
|
|
246
|
+
};
|
|
247
|
+
const isInExcludedRange = (index) => {
|
|
248
|
+
return excludeRanges.some((range) => index >= range.start && index < range.end);
|
|
249
|
+
};
|
|
250
|
+
let i = 0;
|
|
251
|
+
while (i < text.length) {
|
|
252
|
+
const char = text[i];
|
|
253
|
+
if (!delimiterChars.has(char) || isEscaped(i) || isInExcludedRange(i)) {
|
|
254
|
+
i++;
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
let len = 1;
|
|
258
|
+
while (i + len < text.length && text[i + len] === char) len++;
|
|
259
|
+
const canOpen = canEmphasis(char, text, i, len, true);
|
|
260
|
+
const canClose = canEmphasis(char, text, i, len, false);
|
|
261
|
+
if (canOpen || canClose) delimiters.push({
|
|
262
|
+
active: true,
|
|
263
|
+
canClose,
|
|
264
|
+
canOpen,
|
|
265
|
+
char,
|
|
266
|
+
index: i,
|
|
267
|
+
length: len,
|
|
268
|
+
originalLength: len
|
|
269
|
+
});
|
|
270
|
+
i += len;
|
|
271
|
+
}
|
|
272
|
+
return delimiters;
|
|
273
|
+
}
|
|
274
|
+
function processEmphasis(text, delimiters, transformersIndex) {
|
|
275
|
+
const openersBottom = {};
|
|
276
|
+
let currentPos = 0;
|
|
277
|
+
let result = null;
|
|
278
|
+
while (currentPos < delimiters.length) {
|
|
279
|
+
const closer = delimiters[currentPos];
|
|
280
|
+
if (!closer.active || !closer.canClose || closer.length === 0) {
|
|
281
|
+
currentPos++;
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
const bottomKey = `${closer.char}${closer.canOpen}`;
|
|
285
|
+
const bottom = openersBottom[bottomKey] ?? -1;
|
|
286
|
+
let foundOpener = false;
|
|
287
|
+
for (let openIdx = currentPos - 1; openIdx > bottom; openIdx--) {
|
|
288
|
+
const opener = delimiters[openIdx];
|
|
289
|
+
if (!opener.active || !opener.canOpen || opener.length === 0 || opener.char !== closer.char) continue;
|
|
290
|
+
if (opener.canClose || closer.canOpen) {
|
|
291
|
+
if ((opener.originalLength + closer.originalLength) % 3 === 0 && opener.originalLength % 3 !== 0 && closer.originalLength % 3 !== 0) continue;
|
|
292
|
+
}
|
|
293
|
+
const maxLen = Math.min(opener.length, closer.length);
|
|
294
|
+
const matchedTag = Object.keys(transformersIndex.transformersByTag).filter((t) => t[0] === opener.char && t.length <= maxLen).sort((a, b) => b.length - a.length)[0];
|
|
295
|
+
if (!matchedTag) continue;
|
|
296
|
+
foundOpener = true;
|
|
297
|
+
const matchLen = matchedTag.length;
|
|
298
|
+
const match = {
|
|
299
|
+
content: text.slice(opener.index + opener.length, closer.index),
|
|
300
|
+
endIndex: closer.index + matchLen,
|
|
301
|
+
startIndex: opener.index + (opener.length - matchLen),
|
|
302
|
+
tag: matchedTag
|
|
303
|
+
};
|
|
304
|
+
if (!result || match.startIndex < result.startIndex || match.startIndex === result.startIndex && match.endIndex > result.endIndex) result = match;
|
|
305
|
+
for (let j = openIdx + 1; j < currentPos; j++) delimiters[j].active = false;
|
|
306
|
+
opener.length -= matchLen;
|
|
307
|
+
closer.length -= matchLen;
|
|
308
|
+
opener.active = opener.length > 0;
|
|
309
|
+
if (closer.length > 0) closer.index += matchLen;
|
|
310
|
+
else {
|
|
311
|
+
closer.active = false;
|
|
312
|
+
currentPos++;
|
|
313
|
+
}
|
|
314
|
+
break;
|
|
315
|
+
}
|
|
316
|
+
if (!foundOpener) {
|
|
317
|
+
openersBottom[bottomKey] = currentPos - 1;
|
|
318
|
+
if (!closer.canOpen) closer.active = false;
|
|
319
|
+
currentPos++;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return result;
|
|
323
|
+
}
|
|
324
|
+
function canEmphasis(char, text, index, length, isOpen) {
|
|
325
|
+
if (!isFlanking(text, index, length, isOpen)) return false;
|
|
326
|
+
if (char === "*") return true;
|
|
327
|
+
if (char === "_") {
|
|
328
|
+
if (!isFlanking(text, index, length, !isOpen)) return true;
|
|
329
|
+
const adjacentChar = isOpen ? text[index - 1] : text[index + length];
|
|
330
|
+
return adjacentChar !== void 0 && PUNCTUATION.test(adjacentChar);
|
|
331
|
+
}
|
|
332
|
+
return true;
|
|
333
|
+
}
|
|
334
|
+
function isFlanking(text, index, length, isLeft) {
|
|
335
|
+
const charBefore = text[index - 1];
|
|
336
|
+
const charAfter = text[index + length];
|
|
337
|
+
const [primary, secondary] = isLeft ? [charAfter, charBefore] : [charBefore, charAfter];
|
|
338
|
+
if (primary === void 0 || WHITESPACE.test(primary)) return false;
|
|
339
|
+
if (!PUNCTUATION.test(primary)) return true;
|
|
340
|
+
return secondary === void 0 || WHITESPACE.test(secondary) || PUNCTUATION.test(secondary);
|
|
341
|
+
}
|
|
342
|
+
function importTextFormatTransformer(textNode, startIndex, endIndex, transformer, match) {
|
|
343
|
+
const textContent = textNode.getTextContent();
|
|
344
|
+
let transformedNode, nodeAfter, nodeBefore;
|
|
345
|
+
if (match[0] === textContent) transformedNode = textNode;
|
|
346
|
+
else if (startIndex === 0) [transformedNode, nodeAfter] = textNode.splitText(endIndex);
|
|
347
|
+
else [nodeBefore, transformedNode, nodeAfter] = textNode.splitText(startIndex, endIndex);
|
|
348
|
+
transformedNode.setTextContent(match[2]);
|
|
349
|
+
if (transformer) {
|
|
350
|
+
for (const format of transformer.format) if (!transformedNode.hasFormat(format)) transformedNode.toggleFormat(format);
|
|
351
|
+
}
|
|
352
|
+
return {
|
|
353
|
+
nodeAfter,
|
|
354
|
+
nodeBefore,
|
|
355
|
+
transformedNode
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
360
|
+
*
|
|
361
|
+
* This source code is licensed under the MIT license found in the
|
|
362
|
+
* LICENSE file in the root directory of this source tree.
|
|
363
|
+
*
|
|
364
|
+
*/
|
|
365
|
+
function findOutermostTextMatchTransformer(textNode_, textMatchTransformers) {
|
|
366
|
+
const textNode = textNode_;
|
|
367
|
+
let foundMatchStartIndex = void 0;
|
|
368
|
+
let foundMatchEndIndex = void 0;
|
|
369
|
+
let foundMatchTransformer = void 0;
|
|
370
|
+
let foundMatch = void 0;
|
|
371
|
+
for (const transformer of textMatchTransformers) {
|
|
372
|
+
if (!transformer.replace || !transformer.importRegExp) continue;
|
|
373
|
+
const match = textNode.getTextContent().match(transformer.importRegExp);
|
|
374
|
+
if (!match) continue;
|
|
375
|
+
const startIndex = match.index || 0;
|
|
376
|
+
const endIndex = transformer.getEndIndex ? transformer.getEndIndex(textNode, match) : startIndex + match[0].length;
|
|
377
|
+
if (endIndex === false) continue;
|
|
378
|
+
if (foundMatchStartIndex === void 0 || foundMatchEndIndex === void 0 || startIndex < foundMatchStartIndex && (endIndex > foundMatchEndIndex || endIndex <= foundMatchStartIndex)) {
|
|
379
|
+
foundMatchStartIndex = startIndex;
|
|
380
|
+
foundMatchEndIndex = endIndex;
|
|
381
|
+
foundMatchTransformer = transformer;
|
|
382
|
+
foundMatch = match;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
if (foundMatchStartIndex === void 0 || foundMatchEndIndex === void 0 || foundMatchTransformer === void 0 || foundMatch === void 0) return null;
|
|
386
|
+
return {
|
|
387
|
+
endIndex: foundMatchEndIndex,
|
|
388
|
+
match: foundMatch,
|
|
389
|
+
startIndex: foundMatchStartIndex,
|
|
390
|
+
transformer: foundMatchTransformer
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
function importFoundTextMatchTransformer(textNode, startIndex, endIndex, transformer, match) {
|
|
394
|
+
let transformedNode, nodeAfter, nodeBefore;
|
|
395
|
+
if (startIndex === 0) [transformedNode, nodeAfter] = textNode.splitText(endIndex);
|
|
396
|
+
else [nodeBefore, transformedNode, nodeAfter] = textNode.splitText(startIndex, endIndex);
|
|
397
|
+
if (!transformer.replace) return null;
|
|
398
|
+
const potentialTransformedNode = transformer.replace(transformedNode, match);
|
|
399
|
+
return {
|
|
400
|
+
nodeAfter,
|
|
401
|
+
nodeBefore,
|
|
402
|
+
transformedNode: potentialTransformedNode || void 0
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
407
|
+
*
|
|
408
|
+
* This source code is licensed under the MIT license found in the
|
|
409
|
+
* LICENSE file in the root directory of this source tree.
|
|
410
|
+
*
|
|
411
|
+
*/
|
|
412
|
+
/**
|
|
413
|
+
* Returns true if the node can contain transformable markdown.
|
|
414
|
+
* Code nodes cannot contain transformable markdown.
|
|
415
|
+
* For example, `code **bold**` should not be transformed to
|
|
416
|
+
* <code>code <strong>bold</strong></code>.
|
|
417
|
+
*/
|
|
418
|
+
function canContainTransformableMarkdown(node) {
|
|
419
|
+
return $isTextNode(node) && !node.hasFormat("code");
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Handles applying both text format and text match transformers.
|
|
423
|
+
* It finds the outermost text format or text match and applies it,
|
|
424
|
+
* then recursively calls itself to apply the next outermost transformer,
|
|
425
|
+
* until there are no more transformers to apply.
|
|
426
|
+
*/
|
|
427
|
+
function importTextTransformers(textNode, textFormatTransformersIndex, textMatchTransformers) {
|
|
428
|
+
let foundTextFormat = findOutermostTextFormatTransformer(textNode, textFormatTransformersIndex);
|
|
429
|
+
let foundTextMatch = findOutermostTextMatchTransformer(textNode, textMatchTransformers);
|
|
430
|
+
if (foundTextFormat && foundTextMatch) if (foundTextFormat.startIndex <= foundTextMatch.startIndex && foundTextFormat.endIndex >= foundTextMatch.endIndex || foundTextMatch.startIndex > foundTextFormat.endIndex) foundTextMatch = null;
|
|
431
|
+
else foundTextFormat = null;
|
|
432
|
+
if (foundTextFormat) {
|
|
433
|
+
const result = importTextFormatTransformer(textNode, foundTextFormat.startIndex, foundTextFormat.endIndex, foundTextFormat.transformer, foundTextFormat.match);
|
|
434
|
+
if (canContainTransformableMarkdown(result.nodeAfter)) importTextTransformers(result.nodeAfter, textFormatTransformersIndex, textMatchTransformers);
|
|
435
|
+
if (canContainTransformableMarkdown(result.nodeBefore)) importTextTransformers(result.nodeBefore, textFormatTransformersIndex, textMatchTransformers);
|
|
436
|
+
if (canContainTransformableMarkdown(result.transformedNode)) importTextTransformers(result.transformedNode, textFormatTransformersIndex, textMatchTransformers);
|
|
437
|
+
} else if (foundTextMatch) {
|
|
438
|
+
const result = importFoundTextMatchTransformer(textNode, foundTextMatch.startIndex, foundTextMatch.endIndex, foundTextMatch.transformer, foundTextMatch.match);
|
|
439
|
+
if (!result) return;
|
|
440
|
+
if (canContainTransformableMarkdown(result.nodeAfter)) importTextTransformers(result.nodeAfter, textFormatTransformersIndex, textMatchTransformers);
|
|
441
|
+
if (canContainTransformableMarkdown(result.nodeBefore)) importTextTransformers(result.nodeBefore, textFormatTransformersIndex, textMatchTransformers);
|
|
442
|
+
if (canContainTransformableMarkdown(result.transformedNode)) importTextTransformers(result.transformedNode, textFormatTransformersIndex, textMatchTransformers);
|
|
443
|
+
}
|
|
444
|
+
const unescapedText = unescapeText(textNode.getTextContent());
|
|
445
|
+
textNode.setTextContent(unescapedText);
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
449
|
+
*
|
|
450
|
+
* This source code is licensed under the MIT license found in the
|
|
451
|
+
* LICENSE file in the root directory of this source tree.
|
|
452
|
+
*
|
|
453
|
+
*/
|
|
454
|
+
/**
|
|
455
|
+
* Renders markdown from a string. The selection is moved to the start after the operation.
|
|
456
|
+
*/
|
|
457
|
+
function createMarkdownImport(transformers, shouldPreserveNewLines = false) {
|
|
458
|
+
const byType = transformersByType(transformers);
|
|
459
|
+
const textFormatTransformersIndex = createTextFormatTransformersIndex(byType.textFormat);
|
|
460
|
+
return (markdownString, node) => {
|
|
461
|
+
const lines = markdownString.split("\n");
|
|
462
|
+
const linesLength = lines.length;
|
|
463
|
+
const root = node || $getRoot();
|
|
464
|
+
root.clear();
|
|
465
|
+
for (let i = 0; i < linesLength; i++) {
|
|
466
|
+
const lineText = lines[i];
|
|
467
|
+
const [imported, shiftedIndex] = $importMultiline(lines, i, byType.multilineElement, root);
|
|
468
|
+
if (imported) {
|
|
469
|
+
i = shiftedIndex;
|
|
470
|
+
continue;
|
|
471
|
+
}
|
|
472
|
+
$importBlocks(lineText, root, byType.element, textFormatTransformersIndex, byType.textMatch, shouldPreserveNewLines);
|
|
473
|
+
}
|
|
474
|
+
const children = root.getChildren();
|
|
475
|
+
for (const child of children) {
|
|
476
|
+
if (!shouldPreserveNewLines && isEmptyParagraph(child) && root.getChildrenSize() > 1) {
|
|
477
|
+
child.remove();
|
|
478
|
+
continue;
|
|
479
|
+
}
|
|
480
|
+
if ($isElementNode(child)) for (const textNode of child.getAllTextNodes()) $normalizeMarkdownTextNode(textNode);
|
|
481
|
+
}
|
|
482
|
+
if ($getSelection() !== null) root.selectStart();
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
*
|
|
487
|
+
* @returns first element of the returned tuple is a boolean indicating if a multiline element was imported. The second element is the index of the last line that was processed.
|
|
488
|
+
*/
|
|
489
|
+
function $importMultiline(lines, startLineIndex, multilineElementTransformers, rootNode) {
|
|
490
|
+
for (const transformer of multilineElementTransformers) {
|
|
491
|
+
const { handleImportAfterStartMatch, regExpEnd, regExpStart, replace } = transformer;
|
|
492
|
+
const startMatch = lines[startLineIndex].match(regExpStart);
|
|
493
|
+
if (!startMatch) continue;
|
|
494
|
+
if (handleImportAfterStartMatch) {
|
|
495
|
+
const result = handleImportAfterStartMatch({
|
|
496
|
+
lines,
|
|
497
|
+
rootNode,
|
|
498
|
+
startLineIndex,
|
|
499
|
+
startMatch,
|
|
500
|
+
transformer
|
|
501
|
+
});
|
|
502
|
+
if (result === null) continue;
|
|
503
|
+
else if (result) return result;
|
|
504
|
+
}
|
|
505
|
+
const regexpEndRegex = typeof regExpEnd === "object" && "regExp" in regExpEnd ? regExpEnd.regExp : regExpEnd;
|
|
506
|
+
const isEndOptional = regExpEnd && typeof regExpEnd === "object" && "optional" in regExpEnd ? regExpEnd.optional : !regExpEnd;
|
|
507
|
+
let endLineIndex = startLineIndex;
|
|
508
|
+
const linesLength = lines.length;
|
|
509
|
+
while (endLineIndex < linesLength) {
|
|
510
|
+
const endMatch = regexpEndRegex ? lines[endLineIndex].match(regexpEndRegex) : null;
|
|
511
|
+
if (!endMatch) {
|
|
512
|
+
if (!isEndOptional || isEndOptional && endLineIndex < linesLength - 1) {
|
|
513
|
+
endLineIndex++;
|
|
514
|
+
continue;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
if (endMatch && startLineIndex === endLineIndex && endMatch.index === startMatch.index) {
|
|
518
|
+
endLineIndex++;
|
|
519
|
+
continue;
|
|
520
|
+
}
|
|
521
|
+
const linesInBetween = [];
|
|
522
|
+
if (endMatch && startLineIndex === endLineIndex) linesInBetween.push(lines[startLineIndex].slice(startMatch[0].length, -endMatch[0].length));
|
|
523
|
+
else for (let i = startLineIndex; i <= endLineIndex; i++) if (i === startLineIndex) {
|
|
524
|
+
const text = lines[i].slice(startMatch[0].length);
|
|
525
|
+
linesInBetween.push(text);
|
|
526
|
+
} else if (i === endLineIndex && endMatch) {
|
|
527
|
+
const text = lines[i].slice(0, -endMatch[0].length);
|
|
528
|
+
linesInBetween.push(text);
|
|
529
|
+
} else linesInBetween.push(lines[i]);
|
|
530
|
+
if (replace(rootNode, null, startMatch, endMatch, linesInBetween, true) !== false) return [true, endLineIndex];
|
|
531
|
+
break;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
return [false, startLineIndex];
|
|
535
|
+
}
|
|
536
|
+
function $importBlocks(lineText, rootNode, elementTransformers, textFormatTransformersIndex, textMatchTransformers, shouldPreserveNewLines) {
|
|
537
|
+
const textNode = $createTextNode(lineText);
|
|
538
|
+
const elementNode = $createParagraphNode();
|
|
539
|
+
elementNode.append(textNode);
|
|
540
|
+
rootNode.append(elementNode);
|
|
541
|
+
for (const { regExp, replace } of elementTransformers) {
|
|
542
|
+
const match = lineText.match(regExp);
|
|
543
|
+
if (match) {
|
|
544
|
+
textNode.setTextContent(lineText.slice(match[0].length));
|
|
545
|
+
if (replace(elementNode, [textNode], match, true) !== false) break;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
importTextTransformers(textNode, textFormatTransformersIndex, textMatchTransformers);
|
|
549
|
+
if (elementNode.isAttached() && lineText.length > 0) {
|
|
550
|
+
const previousNode = elementNode.getPreviousSibling();
|
|
551
|
+
if (!shouldPreserveNewLines && ($isParagraphNode(previousNode) || $isQuoteNode(previousNode) || $isListNode(previousNode))) {
|
|
552
|
+
let targetNode = previousNode;
|
|
553
|
+
if ($isListNode(previousNode)) {
|
|
554
|
+
const lastDescendant = previousNode.getLastDescendant();
|
|
555
|
+
if (lastDescendant == null) targetNode = null;
|
|
556
|
+
else targetNode = $findMatchingParent$1(lastDescendant, $isListItemNode);
|
|
557
|
+
}
|
|
558
|
+
if (targetNode != null && targetNode.getTextContentSize() > 0) {
|
|
559
|
+
const lastChild = targetNode.getLastChild();
|
|
560
|
+
if ($isTextNode(lastChild)) {
|
|
561
|
+
const lastText = lastChild.getTextContent();
|
|
562
|
+
if (lastText.endsWith("\\")) lastChild.setTextContent(lastText.slice(0, -1));
|
|
563
|
+
else if (/ {2,}$/.test(lastText)) lastChild.setTextContent(lastText.replace(/ {2,}$/, ""));
|
|
564
|
+
}
|
|
565
|
+
targetNode.splice(targetNode.getChildrenSize(), 0, [$createLineBreakNode(), ...elementNode.getChildren()]);
|
|
566
|
+
elementNode.remove();
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
function $normalizeMarkdownTextNode(textNode) {
|
|
572
|
+
const tabOffsets = /* @__PURE__ */ new Set();
|
|
573
|
+
const text = textNode.getTextContent();
|
|
574
|
+
let index = text.indexOf(" ");
|
|
575
|
+
while (index !== -1) {
|
|
576
|
+
tabOffsets.add(index);
|
|
577
|
+
tabOffsets.add(index + 1);
|
|
578
|
+
index = text.indexOf(" ", index + 1);
|
|
579
|
+
}
|
|
580
|
+
textNode.splitText(...tabOffsets).forEach((node) => {
|
|
581
|
+
if (node.getTextContent() === " ") node.replace($createTabNode());
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
function createTextFormatTransformersIndex(textTransformers) {
|
|
585
|
+
const transformersByTag = {};
|
|
586
|
+
const fullMatchRegExpByTag = {};
|
|
587
|
+
const openTagsRegExp = [];
|
|
588
|
+
for (const transformer of textTransformers) {
|
|
589
|
+
const { tag } = transformer;
|
|
590
|
+
transformersByTag[tag] = transformer;
|
|
591
|
+
const tagRegExp = tag.replace(/(\*|\^|\+)/g, "\\$1");
|
|
592
|
+
openTagsRegExp.push(tagRegExp);
|
|
593
|
+
if (tag.length === 1) if (tag === "`") fullMatchRegExpByTag[tag] = new RegExp(`(^|[^\\\\\`])(\`)((?:\\\\\`|[^\`])+?)(\`)(?!\`)`);
|
|
594
|
+
else fullMatchRegExpByTag[tag] = new RegExp(`(^|[^\\\\${tagRegExp}])(${tagRegExp})((\\\\${tagRegExp})?.*?[^${tagRegExp}\\s](\\\\${tagRegExp})?)(${tagRegExp})(?![\\\\${tagRegExp}])`);
|
|
595
|
+
else fullMatchRegExpByTag[tag] = new RegExp(`(^|[^\\\\])(${tagRegExp})((\\\\${tagRegExp})?.*?[^\\s](\\\\${tagRegExp})?)(${tagRegExp})(?!\\\\)`);
|
|
596
|
+
}
|
|
597
|
+
return {
|
|
598
|
+
fullMatchRegExpByTag,
|
|
599
|
+
openTagsRegExp: new RegExp(`(${openTagsRegExp.join("|")})`, "g"),
|
|
600
|
+
transformersByTag
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
605
|
+
*
|
|
606
|
+
* This source code is licensed under the MIT license found in the
|
|
607
|
+
* LICENSE file in the root directory of this source tree.
|
|
608
|
+
*
|
|
609
|
+
*/
|
|
610
|
+
function formatDevErrorMessage(message) {
|
|
611
|
+
throw new Error(message);
|
|
612
|
+
}
|
|
613
|
+
/**
|
|
614
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
615
|
+
*
|
|
616
|
+
* This source code is licensed under the MIT license found in the
|
|
617
|
+
* LICENSE file in the root directory of this source tree.
|
|
618
|
+
*
|
|
619
|
+
*/
|
|
620
|
+
const ORDERED_LIST_REGEX = /^(\s*)(\d{1,})\.\s/;
|
|
621
|
+
const UNORDERED_LIST_REGEX = /^(\s*)[-*+]\s/;
|
|
622
|
+
const CHECK_LIST_REGEX = /^(\s*)(?:[-*+]\s)?\s?(\[(\s|x)?\])\s/i;
|
|
623
|
+
const HEADING_REGEX = /^(#{1,6})\s/;
|
|
624
|
+
const QUOTE_REGEX = /^>\s/;
|
|
625
|
+
const CODE_START_REGEX = /^([ \t]*`{3,})([\w-]+)?[ \t]?/;
|
|
626
|
+
const CODE_END_REGEX = /^[ \t]*`{3,}$/;
|
|
627
|
+
const CODE_SINGLE_LINE_REGEX = /^[ \t]*```[^`]+(?:(?:`{1,2}|`{4,})[^`]+)*```(?:[^`]|$)/;
|
|
628
|
+
const TABLE_ROW_REG_EXP = /^(?:\|)(.+)(?:\|)\s?$/;
|
|
629
|
+
const TABLE_ROW_DIVIDER_REG_EXP = /^(\| ?:?-*:? ?)+\|\s?$/;
|
|
630
|
+
const TAG_START_REGEX = /^<[a-z_][\w-]*(?:\s[^<>]*)?\/?>/i;
|
|
631
|
+
const TAG_END_REGEX = /^<\/[a-z_][\w-]*\s*>/i;
|
|
632
|
+
const ENDS_WITH = (regex) => new RegExp(`(?:${regex.source})$`, regex.flags);
|
|
633
|
+
const listMarkerState = createState("mdListMarker", {
|
|
634
|
+
parse: (v) => typeof v === "string" && /^[-*+]$/.test(v) ? v : "-",
|
|
635
|
+
resetOnCopyNode: true
|
|
636
|
+
});
|
|
637
|
+
const codeFenceState = createState("mdCodeFence", {
|
|
638
|
+
parse: (val) => {
|
|
639
|
+
if (typeof val === "string" && /^`{3,}$/.test(val)) return val;
|
|
640
|
+
return "```";
|
|
641
|
+
},
|
|
642
|
+
resetOnCopyNode: true
|
|
643
|
+
});
|
|
644
|
+
const createBlockNode = (createNode) => {
|
|
645
|
+
return (parentNode, children, match, isImport) => {
|
|
646
|
+
const node = createNode(match);
|
|
647
|
+
node.append(...children);
|
|
648
|
+
parentNode.replace(node);
|
|
649
|
+
if (!isImport) node.select(0, 0);
|
|
650
|
+
};
|
|
651
|
+
};
|
|
652
|
+
const LIST_INDENT_SIZE = 4;
|
|
653
|
+
function getIndent(whitespaces) {
|
|
654
|
+
const tabs = whitespaces.match(/\t/g);
|
|
655
|
+
const spaces = whitespaces.match(/ /g);
|
|
656
|
+
let indent = 0;
|
|
657
|
+
if (tabs) indent += tabs.length;
|
|
658
|
+
if (spaces) indent += Math.floor(spaces.length / LIST_INDENT_SIZE);
|
|
659
|
+
return indent;
|
|
660
|
+
}
|
|
661
|
+
const listReplace = (listType) => {
|
|
662
|
+
return (parentNode, children, match, isImport) => {
|
|
663
|
+
const previousNode = parentNode.getPreviousSibling();
|
|
664
|
+
const nextNode = parentNode.getNextSibling();
|
|
665
|
+
const listItem = $createListItemNode(listType === "check" ? match[3] === "x" : void 0);
|
|
666
|
+
const firstMatchChar = match[0].trim()[0];
|
|
667
|
+
const listMarker = (listType === "bullet" || listType === "check") && firstMatchChar === listMarkerState.parse(firstMatchChar) ? firstMatchChar : void 0;
|
|
668
|
+
if ($isListNode(nextNode) && nextNode.getListType() === listType) {
|
|
669
|
+
if (listMarker) $setState(nextNode, listMarkerState, listMarker);
|
|
670
|
+
const firstChild = nextNode.getFirstChild();
|
|
671
|
+
if (firstChild !== null) firstChild.insertBefore(listItem);
|
|
672
|
+
else nextNode.append(listItem);
|
|
673
|
+
parentNode.remove();
|
|
674
|
+
} else if ($isListNode(previousNode) && previousNode.getListType() === listType) {
|
|
675
|
+
if (listMarker) $setState(previousNode, listMarkerState, listMarker);
|
|
676
|
+
previousNode.append(listItem);
|
|
677
|
+
parentNode.remove();
|
|
678
|
+
} else {
|
|
679
|
+
const list = $createListNode(listType, listType === "number" ? Number(match[2]) : void 0);
|
|
680
|
+
if (listMarker) $setState(list, listMarkerState, listMarker);
|
|
681
|
+
list.append(listItem);
|
|
682
|
+
parentNode.replace(list);
|
|
683
|
+
}
|
|
684
|
+
listItem.append(...children);
|
|
685
|
+
if (!isImport) listItem.select(0, 0);
|
|
686
|
+
const indent = getIndent(match[1]);
|
|
687
|
+
if (indent) listItem.setIndent(indent);
|
|
688
|
+
};
|
|
689
|
+
};
|
|
690
|
+
const $listExport = (listNode, exportChildren, depth) => {
|
|
691
|
+
const output = [];
|
|
692
|
+
const children = listNode.getChildren();
|
|
693
|
+
let index = 0;
|
|
694
|
+
for (const listItemNode of children) if ($isListItemNode(listItemNode)) {
|
|
695
|
+
if (listItemNode.getChildrenSize() === 1) {
|
|
696
|
+
const firstChild = listItemNode.getFirstChild();
|
|
697
|
+
if ($isListNode(firstChild)) {
|
|
698
|
+
output.push($listExport(firstChild, exportChildren, depth + 1));
|
|
699
|
+
continue;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
const indent = " ".repeat(depth * LIST_INDENT_SIZE);
|
|
703
|
+
const listType = listNode.getListType();
|
|
704
|
+
const listMarker = $getState(listNode, listMarkerState);
|
|
705
|
+
const prefix = listType === "number" ? `${listNode.getStart() + index}. ` : listType === "check" ? `${listMarker} [${listItemNode.getChecked() ? "x" : " "}] ` : listMarker + " ";
|
|
706
|
+
let childrenText = exportChildren(listItemNode);
|
|
707
|
+
if (listType !== "number") childrenText = childrenText.replace(/^(\s{0,3}\d+)(\.\s)/, "$1\\$2");
|
|
708
|
+
output.push(indent + prefix + childrenText);
|
|
709
|
+
index++;
|
|
710
|
+
}
|
|
711
|
+
return output.join("\n");
|
|
712
|
+
};
|
|
713
|
+
const HEADING = {
|
|
714
|
+
dependencies: [HeadingNode],
|
|
715
|
+
export: (node, exportChildren) => {
|
|
716
|
+
if (!$isHeadingNode(node)) return null;
|
|
717
|
+
const level = Number(node.getTag().slice(1));
|
|
718
|
+
return "#".repeat(level) + " " + exportChildren(node);
|
|
719
|
+
},
|
|
720
|
+
regExp: HEADING_REGEX,
|
|
721
|
+
replace: createBlockNode((match) => {
|
|
722
|
+
return $createHeadingNode("h" + match[1].length);
|
|
723
|
+
}),
|
|
724
|
+
type: "element"
|
|
725
|
+
};
|
|
726
|
+
const QUOTE = {
|
|
727
|
+
dependencies: [QuoteNode],
|
|
728
|
+
export: (node, exportChildren) => {
|
|
729
|
+
if (!$isQuoteNode(node)) return null;
|
|
730
|
+
const lines = exportChildren(node).split("\n");
|
|
731
|
+
const output = [];
|
|
732
|
+
for (const line of lines) output.push("> " + line);
|
|
733
|
+
return output.join("\n");
|
|
734
|
+
},
|
|
735
|
+
regExp: QUOTE_REGEX,
|
|
736
|
+
replace: (parentNode, children, _match, isImport) => {
|
|
737
|
+
if (isImport) {
|
|
738
|
+
const previousNode = parentNode.getPreviousSibling();
|
|
739
|
+
if ($isQuoteNode(previousNode)) {
|
|
740
|
+
previousNode.splice(previousNode.getChildrenSize(), 0, [$createLineBreakNode(), ...children]);
|
|
741
|
+
parentNode.remove();
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
const node = $createQuoteNode();
|
|
746
|
+
node.append(...children);
|
|
747
|
+
parentNode.replace(node);
|
|
748
|
+
if (!isImport) node.select(0, 0);
|
|
749
|
+
},
|
|
750
|
+
type: "element"
|
|
751
|
+
};
|
|
752
|
+
const CODE = {
|
|
753
|
+
dependencies: [CodeNode],
|
|
754
|
+
export: (node) => {
|
|
755
|
+
if (!$isCodeNode(node)) return null;
|
|
756
|
+
const textContent = node.getTextContent();
|
|
757
|
+
let fence = $getState(node, codeFenceState);
|
|
758
|
+
if (textContent.indexOf(fence) > -1) {
|
|
759
|
+
const backticks = textContent.match(/`{3,}/g);
|
|
760
|
+
if (backticks) {
|
|
761
|
+
const maxLength = Math.max(...backticks.map((b) => b.length));
|
|
762
|
+
fence = "`".repeat(maxLength + 1);
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
return fence + (node.getLanguage() || "") + (textContent ? "\n" + textContent : "") + "\n" + fence;
|
|
766
|
+
},
|
|
767
|
+
handleImportAfterStartMatch: ({ lines, rootNode, startLineIndex, startMatch }) => {
|
|
768
|
+
const fence = startMatch[1];
|
|
769
|
+
const fenceLength = fence.trim().length;
|
|
770
|
+
const currentLine = lines[startLineIndex];
|
|
771
|
+
const afterFenceIndex = startMatch.index + fence.length;
|
|
772
|
+
const afterFence = currentLine.slice(afterFenceIndex);
|
|
773
|
+
const singleLineEndRegex = new RegExp(`\`{${fenceLength},}$`);
|
|
774
|
+
if (singleLineEndRegex.test(afterFence)) {
|
|
775
|
+
const endMatch = afterFence.match(singleLineEndRegex);
|
|
776
|
+
const content = afterFence.slice(0, afterFence.lastIndexOf(endMatch[0]));
|
|
777
|
+
const fakeStartMatch = [...startMatch];
|
|
778
|
+
fakeStartMatch[2] = "";
|
|
779
|
+
CODE.replace(rootNode, null, fakeStartMatch, endMatch, [content], true);
|
|
780
|
+
return [true, startLineIndex];
|
|
781
|
+
}
|
|
782
|
+
const multilineEndRegex = new RegExp(`^[ \\t]*\`{${fenceLength},}$`);
|
|
783
|
+
for (let i = startLineIndex + 1; i < lines.length; i++) {
|
|
784
|
+
const line = lines[i];
|
|
785
|
+
if (multilineEndRegex.test(line)) {
|
|
786
|
+
const endMatch = line.match(multilineEndRegex);
|
|
787
|
+
const linesInBetween = lines.slice(startLineIndex + 1, i);
|
|
788
|
+
const afterFullMatch = currentLine.slice(startMatch[0].length);
|
|
789
|
+
if (afterFullMatch.length > 0) linesInBetween.unshift(afterFullMatch);
|
|
790
|
+
CODE.replace(rootNode, null, startMatch, endMatch, linesInBetween, true);
|
|
791
|
+
return [true, i];
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
const linesInBetween = lines.slice(startLineIndex + 1);
|
|
795
|
+
const afterFullMatch = currentLine.slice(startMatch[0].length);
|
|
796
|
+
if (afterFullMatch.length > 0) linesInBetween.unshift(afterFullMatch);
|
|
797
|
+
CODE.replace(rootNode, null, startMatch, null, linesInBetween, true);
|
|
798
|
+
return [true, lines.length - 1];
|
|
799
|
+
},
|
|
800
|
+
regExpEnd: {
|
|
801
|
+
optional: true,
|
|
802
|
+
regExp: CODE_END_REGEX
|
|
803
|
+
},
|
|
804
|
+
regExpStart: CODE_START_REGEX,
|
|
805
|
+
replace: (rootNode, children, startMatch, endMatch, linesInBetween, isImport) => {
|
|
806
|
+
let codeBlockNode;
|
|
807
|
+
let code;
|
|
808
|
+
const fence = startMatch[1] ? startMatch[1].trim() : "```";
|
|
809
|
+
const language = startMatch[2] || void 0;
|
|
810
|
+
if (!children && linesInBetween) {
|
|
811
|
+
if (linesInBetween.length === 1) if (endMatch) {
|
|
812
|
+
codeBlockNode = $createCodeNode(language);
|
|
813
|
+
code = linesInBetween[0];
|
|
814
|
+
} else {
|
|
815
|
+
codeBlockNode = $createCodeNode(language);
|
|
816
|
+
code = linesInBetween[0].startsWith(" ") ? linesInBetween[0].slice(1) : linesInBetween[0];
|
|
817
|
+
}
|
|
818
|
+
else {
|
|
819
|
+
codeBlockNode = $createCodeNode(language);
|
|
820
|
+
if (linesInBetween.length > 0) {
|
|
821
|
+
if (linesInBetween[0].trim().length === 0) linesInBetween.shift();
|
|
822
|
+
else if (linesInBetween[0].startsWith(" ")) linesInBetween[0] = linesInBetween[0].slice(1);
|
|
823
|
+
}
|
|
824
|
+
while (linesInBetween.length > 0 && !linesInBetween[linesInBetween.length - 1].length) linesInBetween.pop();
|
|
825
|
+
code = linesInBetween.join("\n");
|
|
826
|
+
}
|
|
827
|
+
$setState(codeBlockNode, codeFenceState, fence);
|
|
828
|
+
const textNode = $createTextNode(code);
|
|
829
|
+
codeBlockNode.append(textNode);
|
|
830
|
+
rootNode.append(codeBlockNode);
|
|
831
|
+
} else if (children) createBlockNode((match) => {
|
|
832
|
+
return $createCodeNode(match ? match[2] : void 0);
|
|
833
|
+
})(rootNode, children, startMatch, isImport);
|
|
834
|
+
},
|
|
835
|
+
type: "multiline-element"
|
|
836
|
+
};
|
|
837
|
+
const UNORDERED_LIST = {
|
|
838
|
+
dependencies: [ListNode, ListItemNode],
|
|
839
|
+
export: (node, exportChildren) => {
|
|
840
|
+
return $isListNode(node) ? $listExport(node, exportChildren, 0) : null;
|
|
841
|
+
},
|
|
842
|
+
regExp: UNORDERED_LIST_REGEX,
|
|
843
|
+
replace: listReplace("bullet"),
|
|
844
|
+
type: "element"
|
|
845
|
+
};
|
|
846
|
+
const CHECK_LIST = {
|
|
847
|
+
dependencies: [ListNode, ListItemNode],
|
|
848
|
+
export: (node, exportChildren) => {
|
|
849
|
+
return $isListNode(node) ? $listExport(node, exportChildren, 0) : null;
|
|
850
|
+
},
|
|
851
|
+
regExp: CHECK_LIST_REGEX,
|
|
852
|
+
replace: listReplace("check"),
|
|
853
|
+
type: "element"
|
|
854
|
+
};
|
|
855
|
+
const ORDERED_LIST = {
|
|
856
|
+
dependencies: [ListNode, ListItemNode],
|
|
857
|
+
export: (node, exportChildren) => {
|
|
858
|
+
return $isListNode(node) ? $listExport(node, exportChildren, 0) : null;
|
|
859
|
+
},
|
|
860
|
+
regExp: ORDERED_LIST_REGEX,
|
|
861
|
+
replace: listReplace("number"),
|
|
862
|
+
type: "element"
|
|
863
|
+
};
|
|
864
|
+
const INLINE_CODE = {
|
|
865
|
+
format: ["code"],
|
|
866
|
+
tag: "`",
|
|
867
|
+
type: "text-format"
|
|
868
|
+
};
|
|
869
|
+
const HIGHLIGHT = {
|
|
870
|
+
format: ["highlight"],
|
|
871
|
+
tag: "==",
|
|
872
|
+
type: "text-format"
|
|
873
|
+
};
|
|
874
|
+
const BOLD_ITALIC_STAR = {
|
|
875
|
+
format: ["bold", "italic"],
|
|
876
|
+
tag: "***",
|
|
877
|
+
type: "text-format"
|
|
878
|
+
};
|
|
879
|
+
const BOLD_ITALIC_UNDERSCORE = {
|
|
880
|
+
format: ["bold", "italic"],
|
|
881
|
+
intraword: false,
|
|
882
|
+
tag: "___",
|
|
883
|
+
type: "text-format"
|
|
884
|
+
};
|
|
885
|
+
const BOLD_STAR = {
|
|
886
|
+
format: ["bold"],
|
|
887
|
+
tag: "**",
|
|
888
|
+
type: "text-format"
|
|
889
|
+
};
|
|
890
|
+
const BOLD_UNDERSCORE = {
|
|
891
|
+
format: ["bold"],
|
|
892
|
+
intraword: false,
|
|
893
|
+
tag: "__",
|
|
894
|
+
type: "text-format"
|
|
895
|
+
};
|
|
896
|
+
const STRIKETHROUGH = {
|
|
897
|
+
format: ["strikethrough"],
|
|
898
|
+
tag: "~~",
|
|
899
|
+
type: "text-format"
|
|
900
|
+
};
|
|
901
|
+
const ITALIC_STAR = {
|
|
902
|
+
format: ["italic"],
|
|
903
|
+
tag: "*",
|
|
904
|
+
type: "text-format"
|
|
905
|
+
};
|
|
906
|
+
const ITALIC_UNDERSCORE = {
|
|
907
|
+
format: ["italic"],
|
|
908
|
+
intraword: false,
|
|
909
|
+
tag: "_",
|
|
910
|
+
type: "text-format"
|
|
911
|
+
};
|
|
912
|
+
const LINK = {
|
|
913
|
+
dependencies: [LinkNode],
|
|
914
|
+
export: (node, exportChildren, exportFormat) => {
|
|
915
|
+
if (!$isLinkNode(node) || $isAutoLinkNode(node)) return null;
|
|
916
|
+
const textContent = exportChildren(node);
|
|
917
|
+
let title = node.getTitle();
|
|
918
|
+
if (title != null) title = title.replace(/([\\"])/g, "\\$1");
|
|
919
|
+
return title ? `[${textContent}](${node.getURL()} "${title}")` : `[${textContent}](${node.getURL()})`;
|
|
920
|
+
},
|
|
921
|
+
importRegExp: /(?:\[(.+?)\])(?:\((?:([^()\s]+)(?:\s"((?:[^"]*\\")*[^"]*)"\s*)?)\))/,
|
|
922
|
+
regExp: /(?:\[([^[\]]*(?:\[[^[\]]*\][^[\]]*)*)\])(?:\((?:([^()\s]+)(?:\s"((?:[^"]*\\")*[^"]*)"\s*)?)\))$/,
|
|
923
|
+
replace: (textNode, match) => {
|
|
924
|
+
if ($findMatchingParent(textNode, $isLinkNode)) return;
|
|
925
|
+
const [, linkText, rawLinkUrl, rawLinkTitle] = match;
|
|
926
|
+
const linkNode = $createLinkNode(rawLinkUrl != null ? unescapeText(rawLinkUrl) : void 0, { title: rawLinkTitle != null ? unescapeText(rawLinkTitle) : void 0 });
|
|
927
|
+
const openBracketAmount = linkText.split("[").length - 1;
|
|
928
|
+
const closeBracketAmount = linkText.split("]").length - 1;
|
|
929
|
+
let parsedLinkText = linkText;
|
|
930
|
+
let outsideLinkText = "";
|
|
931
|
+
if (openBracketAmount < closeBracketAmount) return;
|
|
932
|
+
else if (openBracketAmount > closeBracketAmount) {
|
|
933
|
+
const linkTextParts = linkText.split("[");
|
|
934
|
+
outsideLinkText = "[" + linkTextParts[0];
|
|
935
|
+
parsedLinkText = linkTextParts.slice(1).join("[");
|
|
936
|
+
}
|
|
937
|
+
const linkTextNode = $createTextNode(parsedLinkText);
|
|
938
|
+
linkTextNode.setFormat(textNode.getFormat());
|
|
939
|
+
linkNode.append(linkTextNode);
|
|
940
|
+
textNode.replace(linkNode);
|
|
941
|
+
if (outsideLinkText) linkNode.insertBefore($createTextNode(outsideLinkText));
|
|
942
|
+
return linkTextNode;
|
|
943
|
+
},
|
|
944
|
+
trigger: ")",
|
|
945
|
+
type: "text-match"
|
|
946
|
+
};
|
|
947
|
+
const ELEMENT_TRANSFORMERS = [
|
|
948
|
+
HEADING,
|
|
949
|
+
QUOTE,
|
|
950
|
+
UNORDERED_LIST,
|
|
951
|
+
ORDERED_LIST
|
|
952
|
+
];
|
|
953
|
+
const MULTILINE_ELEMENT_TRANSFORMERS = [CODE];
|
|
954
|
+
const TEXT_FORMAT_TRANSFORMERS = [
|
|
955
|
+
INLINE_CODE,
|
|
956
|
+
BOLD_ITALIC_STAR,
|
|
957
|
+
BOLD_ITALIC_UNDERSCORE,
|
|
958
|
+
BOLD_STAR,
|
|
959
|
+
BOLD_UNDERSCORE,
|
|
960
|
+
HIGHLIGHT,
|
|
961
|
+
ITALIC_STAR,
|
|
962
|
+
ITALIC_UNDERSCORE,
|
|
963
|
+
STRIKETHROUGH
|
|
964
|
+
];
|
|
965
|
+
const TEXT_MATCH_TRANSFORMERS = [LINK];
|
|
966
|
+
const TRANSFORMERS = [
|
|
967
|
+
...ELEMENT_TRANSFORMERS,
|
|
968
|
+
...MULTILINE_ELEMENT_TRANSFORMERS,
|
|
969
|
+
...TEXT_FORMAT_TRANSFORMERS,
|
|
970
|
+
...TEXT_MATCH_TRANSFORMERS
|
|
971
|
+
];
|
|
972
|
+
function normalizeMarkdown(input, shouldMergeAdjacentLines = false) {
|
|
973
|
+
const lines = input.split("\n");
|
|
974
|
+
let inCodeBlock = false;
|
|
975
|
+
const sanitizedLines = [];
|
|
976
|
+
for (let i = 0; i < lines.length; i++) {
|
|
977
|
+
const rawLine = lines[i];
|
|
978
|
+
const line = rawLine.trimEnd();
|
|
979
|
+
const lastLine = sanitizedLines[sanitizedLines.length - 1];
|
|
980
|
+
if (CODE_SINGLE_LINE_REGEX.test(line)) {
|
|
981
|
+
sanitizedLines.push(line);
|
|
982
|
+
continue;
|
|
983
|
+
}
|
|
984
|
+
if (CODE_START_REGEX.test(line) || CODE_END_REGEX.test(line)) {
|
|
985
|
+
inCodeBlock = !inCodeBlock;
|
|
986
|
+
sanitizedLines.push(line);
|
|
987
|
+
continue;
|
|
988
|
+
}
|
|
989
|
+
if (inCodeBlock) {
|
|
990
|
+
sanitizedLines.push(rawLine);
|
|
991
|
+
continue;
|
|
992
|
+
}
|
|
993
|
+
if (line === "" || lastLine === "" || !lastLine || HEADING_REGEX.test(lastLine) || HEADING_REGEX.test(line) || QUOTE_REGEX.test(line) || ORDERED_LIST_REGEX.test(line) || UNORDERED_LIST_REGEX.test(line) || CHECK_LIST_REGEX.test(line) || TABLE_ROW_REG_EXP.test(line) || TABLE_ROW_DIVIDER_REG_EXP.test(line) || !shouldMergeAdjacentLines || TAG_START_REGEX.test(line) || TAG_END_REGEX.test(line) || ENDS_WITH(TAG_END_REGEX).test(lastLine) || ENDS_WITH(TAG_START_REGEX).test(lastLine) || CODE_END_REGEX.test(lastLine)) sanitizedLines.push(!shouldMergeAdjacentLines && line !== "" ? rawLine : line);
|
|
994
|
+
else sanitizedLines[sanitizedLines.length - 1] = lastLine + " " + line.trimStart();
|
|
995
|
+
}
|
|
996
|
+
return sanitizedLines.join("\n");
|
|
997
|
+
}
|
|
998
|
+
function runElementTransformers(parentNode, anchorNode, anchorOffset, elementTransformers) {
|
|
999
|
+
if (!$isRootOrShadowRoot(parentNode.getParent()) || parentNode.getFirstChild() !== anchorNode) return false;
|
|
1000
|
+
const textContent = anchorNode.getTextContent();
|
|
1001
|
+
if (textContent[anchorOffset - 1] !== " ") return false;
|
|
1002
|
+
for (const { regExp, replace } of elementTransformers) {
|
|
1003
|
+
const match = textContent.match(regExp);
|
|
1004
|
+
if (match && match[0].length === (match[0].endsWith(" ") ? anchorOffset : anchorOffset - 1)) {
|
|
1005
|
+
const nextSiblings = anchorNode.getNextSiblings();
|
|
1006
|
+
const [leadingNode, remainderNode] = anchorNode.splitText(anchorOffset);
|
|
1007
|
+
if (replace(parentNode, remainderNode ? [remainderNode, ...nextSiblings] : nextSiblings, match, false) !== false) {
|
|
1008
|
+
leadingNode.remove();
|
|
1009
|
+
return true;
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
return false;
|
|
1014
|
+
}
|
|
1015
|
+
function runMultilineElementTransformers(parentNode, anchorNode, anchorOffset, elementTransformers, triggerOnEnter) {
|
|
1016
|
+
if (!$isRootOrShadowRoot(parentNode.getParent()) || parentNode.getFirstChild() !== anchorNode) return false;
|
|
1017
|
+
const textContent = anchorNode.getTextContent();
|
|
1018
|
+
if (!triggerOnEnter) {
|
|
1019
|
+
if (textContent[anchorOffset - 1] !== " ") return false;
|
|
1020
|
+
}
|
|
1021
|
+
for (const { regExpStart, replace, regExpEnd } of elementTransformers) {
|
|
1022
|
+
if (regExpEnd && !("optional" in regExpEnd) || regExpEnd && "optional" in regExpEnd && !regExpEnd.optional) continue;
|
|
1023
|
+
const match = textContent.match(regExpStart);
|
|
1024
|
+
if (match) {
|
|
1025
|
+
const matchLength = triggerOnEnter || match[0].endsWith(" ") ? anchorOffset : anchorOffset - 1;
|
|
1026
|
+
if (match[0].length !== matchLength) continue;
|
|
1027
|
+
const nextSiblings = anchorNode.getNextSiblings();
|
|
1028
|
+
const [leadingNode, remainderNode] = anchorNode.splitText(anchorOffset);
|
|
1029
|
+
if (replace(parentNode, remainderNode ? [remainderNode, ...nextSiblings] : nextSiblings, match, null, null, false) !== false) {
|
|
1030
|
+
leadingNode.remove();
|
|
1031
|
+
return true;
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
return false;
|
|
1036
|
+
}
|
|
1037
|
+
function runTextMatchTransformers(anchorNode, anchorOffset, transformersByTrigger) {
|
|
1038
|
+
let textContent = anchorNode.getTextContent();
|
|
1039
|
+
const transformers = transformersByTrigger[textContent[anchorOffset - 1]];
|
|
1040
|
+
if (transformers == null) return false;
|
|
1041
|
+
if (anchorOffset < textContent.length) textContent = textContent.slice(0, anchorOffset);
|
|
1042
|
+
for (const transformer of transformers) {
|
|
1043
|
+
if (!transformer.replace || !transformer.regExp) continue;
|
|
1044
|
+
const match = textContent.match(transformer.regExp);
|
|
1045
|
+
if (match === null) continue;
|
|
1046
|
+
const startIndex = match.index || 0;
|
|
1047
|
+
const endIndex = startIndex + match[0].length;
|
|
1048
|
+
let replaceNode;
|
|
1049
|
+
if (startIndex === 0) [replaceNode] = anchorNode.splitText(endIndex);
|
|
1050
|
+
else [, replaceNode] = anchorNode.splitText(startIndex, endIndex);
|
|
1051
|
+
replaceNode.selectNext(0, 0);
|
|
1052
|
+
transformer.replace(replaceNode, match);
|
|
1053
|
+
return true;
|
|
1054
|
+
}
|
|
1055
|
+
return false;
|
|
1056
|
+
}
|
|
1057
|
+
function $runTextFormatTransformers(anchorNode, anchorOffset, textFormatTransformers) {
|
|
1058
|
+
const textContent = anchorNode.getTextContent();
|
|
1059
|
+
const closeTagEndIndex = anchorOffset - 1;
|
|
1060
|
+
const closeChar = textContent[closeTagEndIndex];
|
|
1061
|
+
const matchers = textFormatTransformers[closeChar];
|
|
1062
|
+
if (!matchers) return false;
|
|
1063
|
+
for (const matcher of matchers) {
|
|
1064
|
+
const { tag } = matcher;
|
|
1065
|
+
const tagLength = tag.length;
|
|
1066
|
+
const closeTagStartIndex = closeTagEndIndex - tagLength + 1;
|
|
1067
|
+
if (tagLength > 1) {
|
|
1068
|
+
if (!isEqualSubString(textContent, closeTagStartIndex, tag, 0, tagLength)) continue;
|
|
1069
|
+
}
|
|
1070
|
+
if (textContent[closeTagStartIndex - 1] === " ") continue;
|
|
1071
|
+
const afterCloseTagChar = textContent[closeTagEndIndex + 1];
|
|
1072
|
+
if (matcher.intraword === false && afterCloseTagChar && !PUNCTUATION_OR_SPACE.test(afterCloseTagChar)) continue;
|
|
1073
|
+
const closeNode = anchorNode;
|
|
1074
|
+
let openNode = closeNode;
|
|
1075
|
+
let openTagStartIndex = getOpenTagStartIndex(textContent, closeTagStartIndex, tag);
|
|
1076
|
+
let sibling = openNode;
|
|
1077
|
+
while (openTagStartIndex < 0 && (sibling = sibling.getPreviousSibling())) {
|
|
1078
|
+
if ($isLineBreakNode(sibling)) break;
|
|
1079
|
+
if ($isTextNode(sibling)) {
|
|
1080
|
+
if (sibling.hasFormat("code")) continue;
|
|
1081
|
+
const siblingTextContent = sibling.getTextContent();
|
|
1082
|
+
openNode = sibling;
|
|
1083
|
+
openTagStartIndex = getOpenTagStartIndex(siblingTextContent, siblingTextContent.length, tag);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
if (openTagStartIndex < 0) continue;
|
|
1087
|
+
if (openNode === closeNode && openTagStartIndex + tagLength === closeTagStartIndex) continue;
|
|
1088
|
+
const prevOpenNodeText = openNode.getTextContent();
|
|
1089
|
+
if (openTagStartIndex > 0 && prevOpenNodeText[openTagStartIndex - 1] === closeChar) continue;
|
|
1090
|
+
const beforeOpenTagChar = prevOpenNodeText[openTagStartIndex - 1];
|
|
1091
|
+
if (matcher.intraword === false && beforeOpenTagChar && !PUNCTUATION_OR_SPACE.test(beforeOpenTagChar)) continue;
|
|
1092
|
+
if (!matcher.format.includes("code") && $isInsideUnclosedCodeSpan(openNode, openTagStartIndex)) continue;
|
|
1093
|
+
const prevCloseNodeText = closeNode.getTextContent();
|
|
1094
|
+
const closeNodeText = prevCloseNodeText.slice(0, closeTagStartIndex) + prevCloseNodeText.slice(closeTagEndIndex + 1);
|
|
1095
|
+
closeNode.setTextContent(closeNodeText);
|
|
1096
|
+
const openNodeText = openNode === closeNode ? closeNodeText : prevOpenNodeText;
|
|
1097
|
+
openNode.setTextContent(openNodeText.slice(0, openTagStartIndex) + openNodeText.slice(openTagStartIndex + tagLength));
|
|
1098
|
+
const selection = $getSelection();
|
|
1099
|
+
const nextSelection = $createRangeSelection();
|
|
1100
|
+
$setSelection(nextSelection);
|
|
1101
|
+
const newOffset = closeTagEndIndex - tagLength * (openNode === closeNode ? 2 : 1) + 1;
|
|
1102
|
+
nextSelection.anchor.set(openNode.__key, openTagStartIndex, "text");
|
|
1103
|
+
nextSelection.focus.set(closeNode.__key, newOffset, "text");
|
|
1104
|
+
for (const format of matcher.format) if (!nextSelection.hasFormat(format)) nextSelection.formatText(format);
|
|
1105
|
+
nextSelection.anchor.set(nextSelection.focus.key, nextSelection.focus.offset, nextSelection.focus.type);
|
|
1106
|
+
for (const format of matcher.format) if (nextSelection.hasFormat(format)) nextSelection.toggleFormat(format);
|
|
1107
|
+
if ($isRangeSelection(selection)) nextSelection.format = selection.format;
|
|
1108
|
+
return true;
|
|
1109
|
+
}
|
|
1110
|
+
return false;
|
|
1111
|
+
}
|
|
1112
|
+
function $isInsideUnclosedCodeSpan(node, offset) {
|
|
1113
|
+
let backtickCount = 0;
|
|
1114
|
+
const text = node.getTextContent();
|
|
1115
|
+
for (let i = 0; i < offset; i++) if (text[i] === "`") backtickCount++;
|
|
1116
|
+
return backtickCount % 2 !== 0;
|
|
1117
|
+
}
|
|
1118
|
+
function getOpenTagStartIndex(string, maxIndex, tag) {
|
|
1119
|
+
const tagLength = tag.length;
|
|
1120
|
+
for (let i = maxIndex; i >= tagLength; i--) {
|
|
1121
|
+
const startIndex = i - tagLength;
|
|
1122
|
+
if (isEqualSubString(string, startIndex, tag, 0, tagLength) && string[startIndex + tagLength] !== " ") return startIndex;
|
|
1123
|
+
}
|
|
1124
|
+
return -1;
|
|
1125
|
+
}
|
|
1126
|
+
function isEqualSubString(stringA, aStart, stringB, bStart, length) {
|
|
1127
|
+
for (let i = 0; i < length; i++) if (stringA[aStart + i] !== stringB[bStart + i]) return false;
|
|
1128
|
+
return true;
|
|
1129
|
+
}
|
|
1130
|
+
function registerMarkdownShortcuts(editor, transformers = TRANSFORMERS) {
|
|
1131
|
+
const byType = transformersByType(transformers);
|
|
1132
|
+
const textFormatTransformersByTrigger = indexBy(byType.textFormat, ({ tag }) => tag[tag.length - 1]);
|
|
1133
|
+
const textMatchTransformersByTrigger = indexBy(byType.textMatch, ({ trigger }) => trigger);
|
|
1134
|
+
for (const transformer of transformers) {
|
|
1135
|
+
const type = transformer.type;
|
|
1136
|
+
if (type === "element" || type === "text-match" || type === "multiline-element") {
|
|
1137
|
+
const dependencies = transformer.dependencies;
|
|
1138
|
+
for (const node of dependencies) if (!editor.hasNode(node)) formatDevErrorMessage(`MarkdownShortcuts: missing dependency ${node.getType()} for transformer. Ensure node dependency is included in editor initial config.`);
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
const $transform = (parentNode, anchorNode, anchorOffset) => {
|
|
1142
|
+
if (runElementTransformers(parentNode, anchorNode, anchorOffset, byType.element)) return true;
|
|
1143
|
+
if (runMultilineElementTransformers(parentNode, anchorNode, anchorOffset, byType.multilineElement)) return true;
|
|
1144
|
+
if (runTextMatchTransformers(anchorNode, anchorOffset, textMatchTransformersByTrigger)) return true;
|
|
1145
|
+
if ($runTextFormatTransformers(anchorNode, anchorOffset, textFormatTransformersByTrigger)) return true;
|
|
1146
|
+
return false;
|
|
1147
|
+
};
|
|
1148
|
+
return mergeRegister(editor.registerUpdateListener(({ tags, dirtyLeaves, editorState, prevEditorState }) => {
|
|
1149
|
+
if (tags.has(COLLABORATION_TAG) || tags.has(HISTORIC_TAG)) return;
|
|
1150
|
+
if (editor.isComposing()) return;
|
|
1151
|
+
const selection = editorState.read($getSelection);
|
|
1152
|
+
const prevSelection = prevEditorState.read($getSelection);
|
|
1153
|
+
if (!$isRangeSelection(prevSelection) || !$isRangeSelection(selection) || !selection.isCollapsed() || selection.is(prevSelection)) return;
|
|
1154
|
+
const anchorKey = selection.anchor.key;
|
|
1155
|
+
const anchorOffset = selection.anchor.offset;
|
|
1156
|
+
const anchorNode = editorState._nodeMap.get(anchorKey);
|
|
1157
|
+
if (!$isTextNode(anchorNode) || !dirtyLeaves.has(anchorKey) || anchorOffset !== 1 && anchorOffset > prevSelection.anchor.offset + 1) return;
|
|
1158
|
+
editor.update(() => {
|
|
1159
|
+
if (!canContainTransformableMarkdown(anchorNode)) return;
|
|
1160
|
+
const parentNode = anchorNode.getParent();
|
|
1161
|
+
if (parentNode === null || $isCodeNode(parentNode)) return;
|
|
1162
|
+
if ($transform(parentNode, anchorNode, selection.anchor.offset)) $addUpdateTag(HISTORY_PUSH_TAG);
|
|
1163
|
+
});
|
|
1164
|
+
}), editor.registerCommand(KEY_ENTER_COMMAND, (event) => {
|
|
1165
|
+
if (event !== null && event.shiftKey) return false;
|
|
1166
|
+
const selection = $getSelection();
|
|
1167
|
+
if (!$isRangeSelection(selection) || !selection.isCollapsed()) return false;
|
|
1168
|
+
const anchorOffset = selection.anchor.offset;
|
|
1169
|
+
const anchorNode = selection.anchor.getNode();
|
|
1170
|
+
if (!$isTextNode(anchorNode) || !canContainTransformableMarkdown(anchorNode)) return false;
|
|
1171
|
+
const parentNode = anchorNode.getParent();
|
|
1172
|
+
if (parentNode === null || $isCodeNode(parentNode)) return false;
|
|
1173
|
+
if (anchorOffset !== anchorNode.getTextContent().length) return false;
|
|
1174
|
+
if (runMultilineElementTransformers(parentNode, anchorNode, anchorOffset, byType.multilineElement, true)) {
|
|
1175
|
+
if (event !== null) event.preventDefault();
|
|
1176
|
+
return true;
|
|
1177
|
+
}
|
|
1178
|
+
return false;
|
|
1179
|
+
}, COMMAND_PRIORITY_LOW));
|
|
1180
|
+
}
|
|
1181
|
+
/**
|
|
1182
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
1183
|
+
*
|
|
1184
|
+
* This source code is licensed under the MIT license found in the
|
|
1185
|
+
* LICENSE file in the root directory of this source tree.
|
|
1186
|
+
*
|
|
1187
|
+
*/
|
|
1188
|
+
/**
|
|
1189
|
+
* Renders markdown from a string. The selection is moved to the start after the operation.
|
|
1190
|
+
*
|
|
1191
|
+
* @param {boolean} [shouldPreserveNewLines] By setting this to true, new lines will be preserved between conversions
|
|
1192
|
+
* @param {boolean} [shouldMergeAdjacentLines] By setting this to true, adjacent non empty lines will be merged according to commonmark spec: https://spec.commonmark.org/0.24/#example-177. Not applicable if shouldPreserveNewLines = true.
|
|
1193
|
+
*/
|
|
1194
|
+
function $convertFromMarkdownString(markdown, transformers = TRANSFORMERS, node, shouldPreserveNewLines = false, shouldMergeAdjacentLines = false) {
|
|
1195
|
+
const sanitizedMarkdown = shouldPreserveNewLines ? markdown : normalizeMarkdown(markdown, shouldMergeAdjacentLines);
|
|
1196
|
+
return createMarkdownImport(transformers, shouldPreserveNewLines)(sanitizedMarkdown, node);
|
|
1197
|
+
}
|
|
1198
|
+
/**
|
|
1199
|
+
* Renders string from markdown. The selection is moved to the start after the operation.
|
|
1200
|
+
*/
|
|
1201
|
+
function $convertToMarkdownString(transformers = TRANSFORMERS, node, shouldPreserveNewLines = false) {
|
|
1202
|
+
return createMarkdownExport(transformers, shouldPreserveNewLines)(node);
|
|
1203
|
+
}
|
|
1204
|
+
//#endregion
|
|
1205
|
+
export { $convertFromMarkdownString, $convertToMarkdownString, BOLD_ITALIC_STAR, BOLD_ITALIC_UNDERSCORE, BOLD_STAR, BOLD_UNDERSCORE, CHECK_LIST, CODE, ELEMENT_TRANSFORMERS, HEADING, HIGHLIGHT, INLINE_CODE, ITALIC_STAR, ITALIC_UNDERSCORE, LINK, MULTILINE_ELEMENT_TRANSFORMERS, ORDERED_LIST, QUOTE, STRIKETHROUGH, TEXT_FORMAT_TRANSFORMERS, TEXT_MATCH_TRANSFORMERS, TRANSFORMERS, UNORDERED_LIST, registerMarkdownShortcuts };
|
|
1206
|
+
|
|
1207
|
+
//# sourceMappingURL=LexicalMarkdown.dev-C8e-eh6y.mjs.map
|