@mx-space/cli 0.7.8 → 0.8.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/dist/{Lexical.dev-rcxzwpir.mjs → Lexical.dev-By5dOKBN.mjs} +1486 -356
- package/dist/{Lexical.node-BUsI9gWr.mjs → Lexical.node-fXM8Jp7p.mjs} +39 -17
- package/dist/{Lexical.prod-C8HtkSD6.mjs → Lexical.prod-BlCvXPGa.mjs} +2279 -1768
- package/dist/LexicalClipboard.dev--HxGoSkO.mjs +915 -0
- package/dist/{LexicalClipboard.node-CO-MCKx5.mjs → LexicalClipboard.node-C3mRbrmW.mjs} +10 -3
- package/dist/LexicalClipboard.prod-DNJzFMcT.mjs +371 -0
- package/dist/LexicalCodeCore.dev-DjSrd4A4.mjs +1109 -0
- package/dist/LexicalCodeCore.prod-DTDShkR3.mjs +642 -0
- package/dist/{LexicalDragon.dev-gBP8WSRS.mjs → LexicalDragon.dev-DwprRH0z.mjs} +3 -3
- package/dist/{LexicalDragon.node-OG6G55nl.mjs → LexicalDragon.node-BVhw4C7s.mjs} +2 -2
- package/dist/{LexicalDragon.prod-DP-_Q8cv.mjs → LexicalDragon.prod-nh4J-8vn.mjs} +3 -3
- package/dist/{LexicalExtension.dev-DVbjljrm.mjs → LexicalExtension.dev-BPNyvGqe.mjs} +335 -6
- package/dist/{LexicalExtension.node-CF3EAPN7.mjs → LexicalExtension.node-BVlcrgOx.mjs} +15 -8
- package/dist/{LexicalExtension.prod-DklHHErZ.mjs → LexicalExtension.prod-DFKbiNt-.mjs} +375 -265
- package/dist/{LexicalHeadless.dev-DdWLM7Nl.mjs → LexicalHeadless.dev-B-cj7Pr5.mjs} +2 -2
- package/dist/{LexicalHeadless.prod-CoiiTDzR.mjs → LexicalHeadless.prod-Byp1vNzT.mjs} +2 -2
- package/dist/LexicalHtml.dev-prBAwszN.mjs +2424 -0
- package/dist/LexicalHtml.node-BvNF96jZ.mjs +56 -0
- package/dist/LexicalHtml.prod-Sz3CW1ht.mjs +1207 -0
- package/dist/{LexicalLink.dev-BS1Bf-yD.mjs → LexicalLink.dev-NySTYhVR.mjs} +42 -8
- package/dist/{LexicalLink.prod-B_crkoHP.mjs → LexicalLink.prod-BuCM8gts.mjs} +209 -191
- package/dist/{LexicalList.dev-OMqmcnQ-.mjs → LexicalList.dev-DIMOvSFD.mjs} +252 -80
- package/dist/{LexicalList.prod-CpL1s8vS.mjs → LexicalList.prod-MVqfA6Vo.mjs} +364 -278
- package/dist/{LexicalMarkdown.dev-BHSdx_Gr.mjs → LexicalMarkdown.dev-C7aylvCG.mjs} +729 -552
- package/dist/LexicalMarkdown.prod-CfQSM406.mjs +868 -0
- package/dist/{LexicalRichText.dev-Bz9A_WbM.mjs → LexicalRichText.dev-DfICq6lU.mjs} +272 -77
- package/dist/{LexicalRichText.node-DDpwfE-P.mjs → LexicalRichText.node-Bg9jND3Q.mjs} +21 -8
- package/dist/LexicalRichText.prod-GsFzCK-o.mjs +550 -0
- package/dist/{LexicalSelection.dev-CQ380fnD.mjs → LexicalSelection.dev-DGjj12wW.mjs} +50 -38
- package/dist/{LexicalSelection.node-DesBMjIE.mjs → LexicalSelection.node-BU5L4193.mjs} +4 -4
- package/dist/{LexicalSelection.prod-D2jivCDB.mjs → LexicalSelection.prod-D-PwRbyK.mjs} +158 -140
- package/dist/{LexicalTable.dev-Ca7mQ7Jk.mjs → LexicalTable.dev-ChP7cugd.mjs} +215 -53
- package/dist/{LexicalTable.prod-DyPAcC7y.mjs → LexicalTable.prod-Bpr9YRXp.mjs} +668 -573
- package/dist/{LexicalUtils.dev-HxM8F0g6.mjs → LexicalUtils.dev-BiFU3789.mjs} +10 -47
- package/dist/{LexicalUtils.node-lCWjRjoG.mjs → LexicalUtils.node-j3Llm7Y3.mjs} +2 -2
- package/dist/{LexicalUtils.prod-Bti5w4ki.mjs → LexicalUtils.prod-DCvrA78p.mjs} +103 -105
- package/dist/bin/mxs.d.mts +1 -1
- package/dist/bin/mxs.mjs +1 -1
- package/dist/esm-By7trG9K.mjs +2 -0
- package/dist/{esm-CK9m5JKX.mjs → esm-Dg-WhPCe.mjs} +989 -989
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{mxs-BZt1cLW9.mjs → mxs-DT0oYk6U.mjs} +11935 -11866
- package/package.json +15 -14
- package/dist/LexicalClipboard.dev-BpqRwTLP.mjs +0 -494
- package/dist/LexicalClipboard.prod-B_xdeiAC.mjs +0 -291
- package/dist/LexicalCodeCore.dev-7_cexm39.mjs +0 -537
- package/dist/LexicalCodeCore.prod-Bd6WFHcO.mjs +0 -381
- package/dist/LexicalHtml.dev-C3ZSWBFZ.mjs +0 -684
- package/dist/LexicalHtml.node-D0TD152E.mjs +0 -24
- package/dist/LexicalHtml.prod-CX47X0zl.mjs +0 -430
- package/dist/LexicalMarkdown.prod-C-S7Ii6-.mjs +0 -754
- package/dist/LexicalRichText.prod-C8qXACDL.mjs +0 -427
- package/dist/esm-DRbkkY3r.mjs +0 -2
- /package/dist/{mxs-CM8-6uAr.d.mts → mxs-iqJBopvE.d.mts} +0 -0
|
@@ -1,7 +1,8 @@
|
|
|
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-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
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-Bg9jND3Q.mjs";
|
|
2
|
+
import { $ as $isElementNode, Bt as COMMAND_PRIORITY_LOW, Et as $setState, Ft as COLLABORATION_TAG, G as $getState, H as $getRoot, Nn as KEY_ENTER_COMMAND, Or as mergeRegister, U as $getSelection, Vt as COMPOSITION_END_TAG, Z as $isDecoratorNode, _ as $createTextNode, an as HISTORY_PUSH_TAG, f as $createParagraphNode, ft as $isTextNode, g as $createTabNode, it as $isLineBreakNode, lt as $isRootOrShadowRoot, m as $createRangeSelection, or as createState, ot as $isParagraphNode, rn as HISTORIC_TAG, st as $isRangeSelection, t as $addUpdateTag, u as $createLineBreakNode, wt as $setSelection, y as $findMatchingParent } from "./Lexical.node-fXM8Jp7p.mjs";
|
|
3
|
+
import { i as $sliceSelectedTextNodeContent } from "./LexicalSelection.node-BU5L4193.mjs";
|
|
4
|
+
import { r as $findMatchingParent$1 } from "./LexicalUtils.node-j3Llm7Y3.mjs";
|
|
5
|
+
//#region ../../node_modules/.pnpm/@lexical+markdown@0.45.0/node_modules/@lexical/markdown/dist/LexicalMarkdown.dev.mjs
|
|
5
6
|
/**
|
|
6
7
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
7
8
|
*
|
|
@@ -36,7 +37,7 @@ function transformersByType(transformers) {
|
|
|
36
37
|
};
|
|
37
38
|
}
|
|
38
39
|
const PUNCTUATION_OR_SPACE = /[!-/:-@[-`{-~\s]/;
|
|
39
|
-
const WHITESPACE =
|
|
40
|
+
const WHITESPACE = /\s/;
|
|
40
41
|
const PUNCTUATION = /[!"#$%&'()*+,\-./:;<=>?@[\]^_`{|}~]/;
|
|
41
42
|
const MARKDOWN_EMPTY_LINE_REG_EXP = /^\s{0,3}$/;
|
|
42
43
|
function isEmptyParagraph(node) {
|
|
@@ -54,6 +55,443 @@ function unescapeText(value) {
|
|
|
54
55
|
* LICENSE file in the root directory of this source tree.
|
|
55
56
|
*
|
|
56
57
|
*/
|
|
58
|
+
const ORDERED_LIST_REGEX = /^(\s*)(\d{1,})\.\s/;
|
|
59
|
+
const UNORDERED_LIST_REGEX = /^(\s*)[-*+]\s/;
|
|
60
|
+
const CHECK_LIST_REGEX = /^(\s*)(?:[-*+]\s)?\s?(\[(\s|x)?\])\s/i;
|
|
61
|
+
const HEADING_REGEX = /^(#{1,6})\s/;
|
|
62
|
+
const QUOTE_REGEX = /^>\s/;
|
|
63
|
+
const CODE_START_REGEX = /^([ \t]*`{3,})([\w-]+)?[ \t]?/;
|
|
64
|
+
const CODE_END_REGEX = /^[ \t]*`{3,}$/;
|
|
65
|
+
const CODE_SINGLE_LINE_REGEX = /^[ \t]*```[^`]+(?:(?:`{1,2}|`{4,})[^`]+)*```(?:[^`]|$)/;
|
|
66
|
+
const TABLE_ROW_REG_EXP = /^(?:\|)(.+)(?:\|)\s?$/;
|
|
67
|
+
const TABLE_ROW_DIVIDER_REG_EXP = /^(\| ?:?-*:? ?)+\|\s?$/;
|
|
68
|
+
const TAG_START_REGEX = /^<[a-z_][\w-]*(?:\s[^<>]*)?\/?>/i;
|
|
69
|
+
const TAG_END_REGEX = /^<\/[a-z_][\w-]*\s*>/i;
|
|
70
|
+
const ENDS_WITH = (regex) => new RegExp(`(?:${regex.source})$`, regex.flags);
|
|
71
|
+
const listMarkerState = createState("mdListMarker", {
|
|
72
|
+
parse: (v) => typeof v === "string" && /^[-*+]$/.test(v) ? v : "-",
|
|
73
|
+
resetOnCopyNode: true
|
|
74
|
+
});
|
|
75
|
+
const codeFenceState = createState("mdCodeFence", {
|
|
76
|
+
parse: (val) => {
|
|
77
|
+
if (typeof val === "string" && /^`{3,}$/.test(val)) return val;
|
|
78
|
+
return "```";
|
|
79
|
+
},
|
|
80
|
+
resetOnCopyNode: true
|
|
81
|
+
});
|
|
82
|
+
const hardLineBreakState = createState("mdHardLineBreak", {
|
|
83
|
+
parse: (val) => {
|
|
84
|
+
if (typeof val === "string" && /^(\\| {2,})$/.test(val)) return val;
|
|
85
|
+
return "";
|
|
86
|
+
},
|
|
87
|
+
resetOnCopyNode: true
|
|
88
|
+
});
|
|
89
|
+
function parseMarkdownHardLineBreak(line) {
|
|
90
|
+
if (line.endsWith("\\")) return [line.slice(0, -1), "\\"];
|
|
91
|
+
const spaces = line.match(/^(.*?\S)( {2,})$/);
|
|
92
|
+
return spaces ? [spaces[1], spaces[2]] : null;
|
|
93
|
+
}
|
|
94
|
+
function hasNonWhitespaceContentOnLine(children, endIndex) {
|
|
95
|
+
for (let i = endIndex - 1; i >= 0; i--) {
|
|
96
|
+
if ($isLineBreakNode(children[i])) return false;
|
|
97
|
+
if (/\S/.test(children[i].getTextContent())) return true;
|
|
98
|
+
}
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
function $extractMarkdownHardLineBreakMarker(previousNode) {
|
|
102
|
+
const children = previousNode.getChildren();
|
|
103
|
+
const lastChildIndex = children.length - 1;
|
|
104
|
+
const lastChild = children[lastChildIndex];
|
|
105
|
+
if (!$isTextNode(lastChild)) return null;
|
|
106
|
+
const lastText = lastChild.getTextContent();
|
|
107
|
+
const hardLineBreak = parseMarkdownHardLineBreak(lastText);
|
|
108
|
+
if (hardLineBreak !== null) {
|
|
109
|
+
const [text, marker] = hardLineBreak;
|
|
110
|
+
lastChild.setTextContent(text);
|
|
111
|
+
return marker;
|
|
112
|
+
}
|
|
113
|
+
if (/^ {2,}$/.test(lastText) && hasNonWhitespaceContentOnLine(children, lastChildIndex)) {
|
|
114
|
+
lastChild.setTextContent("");
|
|
115
|
+
return lastText;
|
|
116
|
+
}
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
function $createMarkdownLineBreakNode(previousNode) {
|
|
120
|
+
const lineBreakNode = $createLineBreakNode();
|
|
121
|
+
const hardLineBreak = $extractMarkdownHardLineBreakMarker(previousNode);
|
|
122
|
+
if (hardLineBreak !== null) $setState(lineBreakNode, hardLineBreakState, hardLineBreak);
|
|
123
|
+
return lineBreakNode;
|
|
124
|
+
}
|
|
125
|
+
const createBlockNode = (createNode) => {
|
|
126
|
+
return (parentNode, children, match, isImport) => {
|
|
127
|
+
const node = createNode(match);
|
|
128
|
+
node.append(...children);
|
|
129
|
+
parentNode.replace(node);
|
|
130
|
+
if (!isImport) node.select(0, 0);
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
const LIST_INDENT_SIZE = 4;
|
|
134
|
+
function getIndent(whitespaces) {
|
|
135
|
+
const tabs = whitespaces.match(/\t/g);
|
|
136
|
+
const spaces = whitespaces.match(/ /g);
|
|
137
|
+
let indent = 0;
|
|
138
|
+
if (tabs) indent += tabs.length;
|
|
139
|
+
if (spaces) indent += Math.floor(spaces.length / LIST_INDENT_SIZE);
|
|
140
|
+
return indent;
|
|
141
|
+
}
|
|
142
|
+
const listReplace = (listType) => {
|
|
143
|
+
return (parentNode, children, match, isImport) => {
|
|
144
|
+
const previousNode = parentNode.getPreviousSibling();
|
|
145
|
+
const nextNode = parentNode.getNextSibling();
|
|
146
|
+
const listItem = $createListItemNode(listType === "check" ? match[3] === "x" : void 0);
|
|
147
|
+
const firstMatchChar = match[0].trim()[0];
|
|
148
|
+
const listMarker = (listType === "bullet" || listType === "check") && firstMatchChar === listMarkerState.parse(firstMatchChar) ? firstMatchChar : void 0;
|
|
149
|
+
if ($isListNode(nextNode) && nextNode.getListType() === listType) {
|
|
150
|
+
if (listMarker) $setState(nextNode, listMarkerState, listMarker);
|
|
151
|
+
const firstChild = nextNode.getFirstChild();
|
|
152
|
+
if (firstChild !== null) firstChild.insertBefore(listItem);
|
|
153
|
+
else nextNode.append(listItem);
|
|
154
|
+
parentNode.remove();
|
|
155
|
+
} else if ($isListNode(previousNode) && previousNode.getListType() === listType) {
|
|
156
|
+
if (listMarker) $setState(previousNode, listMarkerState, listMarker);
|
|
157
|
+
previousNode.append(listItem);
|
|
158
|
+
parentNode.remove();
|
|
159
|
+
} else {
|
|
160
|
+
const list = $createListNode(listType, listType === "number" ? Number(match[2]) : void 0);
|
|
161
|
+
if (listMarker) $setState(list, listMarkerState, listMarker);
|
|
162
|
+
list.append(listItem);
|
|
163
|
+
parentNode.replace(list);
|
|
164
|
+
}
|
|
165
|
+
listItem.append(...children);
|
|
166
|
+
if (!isImport) listItem.select(0, 0);
|
|
167
|
+
const indent = getIndent(match[1]);
|
|
168
|
+
if (indent) listItem.setIndent(indent);
|
|
169
|
+
};
|
|
170
|
+
};
|
|
171
|
+
const $listExport = (listNode, exportChildren, depth, selection) => {
|
|
172
|
+
const output = [];
|
|
173
|
+
const children = listNode.getChildren();
|
|
174
|
+
let index = 0;
|
|
175
|
+
for (const listItemNode of children) if ($isListItemNode(listItemNode)) {
|
|
176
|
+
if (listItemNode.getChildrenSize() === 1) {
|
|
177
|
+
const firstChild = listItemNode.getFirstChild();
|
|
178
|
+
if ($isListNode(firstChild)) {
|
|
179
|
+
const nestedResult = $listExport(firstChild, exportChildren, depth + 1, selection);
|
|
180
|
+
if (nestedResult) output.push(nestedResult);
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (selection && !listItemNode.getChildren().some((child) => child.isSelected(selection))) continue;
|
|
185
|
+
const indent = " ".repeat(depth * LIST_INDENT_SIZE);
|
|
186
|
+
const listType = listNode.getListType();
|
|
187
|
+
const listMarker = $getState(listNode, listMarkerState);
|
|
188
|
+
const prefix = listType === "number" ? `${listNode.getStart() + index}. ` : listType === "check" ? `${listMarker} [${listItemNode.getChecked() ? "x" : " "}] ` : listMarker + " ";
|
|
189
|
+
let childrenText = exportChildren(listItemNode);
|
|
190
|
+
if (listType !== "number") childrenText = childrenText.replace(/^(\s{0,3}\d+)(\.\s)/, "$1\\$2");
|
|
191
|
+
output.push(indent + prefix + childrenText);
|
|
192
|
+
index++;
|
|
193
|
+
}
|
|
194
|
+
return output.join("\n");
|
|
195
|
+
};
|
|
196
|
+
const HEADING = {
|
|
197
|
+
dependencies: [HeadingNode],
|
|
198
|
+
export: (node, exportChildren) => {
|
|
199
|
+
if (!$isHeadingNode(node)) return null;
|
|
200
|
+
const level = Number(node.getTag().slice(1));
|
|
201
|
+
return "#".repeat(level) + " " + exportChildren(node);
|
|
202
|
+
},
|
|
203
|
+
regExp: HEADING_REGEX,
|
|
204
|
+
replace: createBlockNode((match) => {
|
|
205
|
+
return $createHeadingNode("h" + match[1].length);
|
|
206
|
+
}),
|
|
207
|
+
triggerOnEnter: true,
|
|
208
|
+
type: "element"
|
|
209
|
+
};
|
|
210
|
+
const QUOTE = {
|
|
211
|
+
dependencies: [QuoteNode],
|
|
212
|
+
export: (node, exportChildren) => {
|
|
213
|
+
if (!$isQuoteNode(node)) return null;
|
|
214
|
+
const lines = exportChildren(node).split("\n");
|
|
215
|
+
const output = [];
|
|
216
|
+
for (const line of lines) output.push("> " + line);
|
|
217
|
+
return output.join("\n");
|
|
218
|
+
},
|
|
219
|
+
regExp: QUOTE_REGEX,
|
|
220
|
+
replace: (parentNode, children, _match, isImport) => {
|
|
221
|
+
if (isImport) {
|
|
222
|
+
const previousNode = parentNode.getPreviousSibling();
|
|
223
|
+
if ($isQuoteNode(previousNode)) {
|
|
224
|
+
previousNode.splice(previousNode.getChildrenSize(), 0, [$createMarkdownLineBreakNode(previousNode), ...children]);
|
|
225
|
+
parentNode.remove();
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const node = $createQuoteNode();
|
|
230
|
+
node.append(...children);
|
|
231
|
+
parentNode.replace(node);
|
|
232
|
+
if (!isImport) node.select(0, 0);
|
|
233
|
+
},
|
|
234
|
+
triggerOnEnter: true,
|
|
235
|
+
type: "element"
|
|
236
|
+
};
|
|
237
|
+
const CODE = {
|
|
238
|
+
dependencies: [CodeNode],
|
|
239
|
+
export: (node) => {
|
|
240
|
+
if (!$isCodeNode(node)) return null;
|
|
241
|
+
const textContent = node.getTextContent();
|
|
242
|
+
let fence = $getState(node, codeFenceState);
|
|
243
|
+
if (textContent.indexOf(fence) > -1) {
|
|
244
|
+
const backticks = textContent.match(/`{3,}/g);
|
|
245
|
+
if (backticks) {
|
|
246
|
+
const maxLength = Math.max(...backticks.map((b) => b.length));
|
|
247
|
+
fence = "`".repeat(maxLength + 1);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return fence + (node.getLanguage() || "") + (textContent ? "\n" + textContent : "") + "\n" + fence;
|
|
251
|
+
},
|
|
252
|
+
handleImportAfterStartMatch: ({ lines, rootNode, startLineIndex, startMatch }) => {
|
|
253
|
+
const fence = startMatch[1];
|
|
254
|
+
const fenceLength = fence.trim().length;
|
|
255
|
+
const currentLine = lines[startLineIndex];
|
|
256
|
+
const afterFenceIndex = startMatch.index + fence.length;
|
|
257
|
+
const afterFence = currentLine.slice(afterFenceIndex);
|
|
258
|
+
const singleLineEndRegex = new RegExp(`\`{${fenceLength},}$`);
|
|
259
|
+
if (singleLineEndRegex.test(afterFence)) {
|
|
260
|
+
const endMatch = afterFence.match(singleLineEndRegex);
|
|
261
|
+
const content = afterFence.slice(0, afterFence.lastIndexOf(endMatch[0]));
|
|
262
|
+
const fakeStartMatch = [...startMatch];
|
|
263
|
+
fakeStartMatch[2] = "";
|
|
264
|
+
CODE.replace(rootNode, null, fakeStartMatch, endMatch, [content], true);
|
|
265
|
+
return [true, startLineIndex];
|
|
266
|
+
}
|
|
267
|
+
const multilineEndRegex = new RegExp(`^[ \\t]*\`{${fenceLength},}$`);
|
|
268
|
+
for (let i = startLineIndex + 1; i < lines.length; i++) {
|
|
269
|
+
const line = lines[i];
|
|
270
|
+
if (multilineEndRegex.test(line)) {
|
|
271
|
+
const endMatch = line.match(multilineEndRegex);
|
|
272
|
+
const linesInBetween = lines.slice(startLineIndex + 1, i);
|
|
273
|
+
const afterFullMatch = currentLine.slice(startMatch[0].length);
|
|
274
|
+
if (afterFullMatch.length > 0) linesInBetween.unshift(afterFullMatch);
|
|
275
|
+
CODE.replace(rootNode, null, startMatch, endMatch, linesInBetween, true);
|
|
276
|
+
return [true, i];
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
const linesInBetween = lines.slice(startLineIndex + 1);
|
|
280
|
+
const afterFullMatch = currentLine.slice(startMatch[0].length);
|
|
281
|
+
if (afterFullMatch.length > 0) linesInBetween.unshift(afterFullMatch);
|
|
282
|
+
CODE.replace(rootNode, null, startMatch, null, linesInBetween, true);
|
|
283
|
+
return [true, lines.length - 1];
|
|
284
|
+
},
|
|
285
|
+
regExpEnd: {
|
|
286
|
+
optional: true,
|
|
287
|
+
regExp: CODE_END_REGEX
|
|
288
|
+
},
|
|
289
|
+
regExpStart: CODE_START_REGEX,
|
|
290
|
+
replace: (rootNode, children, startMatch, endMatch, linesInBetween, isImport) => {
|
|
291
|
+
let codeBlockNode;
|
|
292
|
+
let code;
|
|
293
|
+
const fence = startMatch[1] ? startMatch[1].trim() : "```";
|
|
294
|
+
const language = startMatch[2] || void 0;
|
|
295
|
+
if (!children && linesInBetween) {
|
|
296
|
+
if (linesInBetween.length === 1) if (endMatch) {
|
|
297
|
+
codeBlockNode = $createCodeNode(language);
|
|
298
|
+
code = linesInBetween[0];
|
|
299
|
+
} else {
|
|
300
|
+
codeBlockNode = $createCodeNode(language);
|
|
301
|
+
code = linesInBetween[0].startsWith(" ") ? linesInBetween[0].slice(1) : linesInBetween[0];
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
codeBlockNode = $createCodeNode(language);
|
|
305
|
+
if (linesInBetween.length > 0) {
|
|
306
|
+
if (linesInBetween[0].trim().length === 0) linesInBetween.shift();
|
|
307
|
+
else if (linesInBetween[0].startsWith(" ")) linesInBetween[0] = linesInBetween[0].slice(1);
|
|
308
|
+
}
|
|
309
|
+
while (linesInBetween.length > 0 && !linesInBetween[linesInBetween.length - 1].length) linesInBetween.pop();
|
|
310
|
+
code = linesInBetween.join("\n");
|
|
311
|
+
}
|
|
312
|
+
$setState(codeBlockNode, codeFenceState, fence);
|
|
313
|
+
const textNode = $createTextNode(code);
|
|
314
|
+
codeBlockNode.append(textNode);
|
|
315
|
+
rootNode.append(codeBlockNode);
|
|
316
|
+
} else if (children) createBlockNode((match) => {
|
|
317
|
+
return $createCodeNode(match ? match[2] : void 0);
|
|
318
|
+
})(rootNode, children, startMatch, isImport);
|
|
319
|
+
},
|
|
320
|
+
type: "multiline-element"
|
|
321
|
+
};
|
|
322
|
+
const UNORDERED_LIST = {
|
|
323
|
+
dependencies: [ListNode, ListItemNode],
|
|
324
|
+
export: (node, exportChildren, selection) => {
|
|
325
|
+
return $isListNode(node) ? $listExport(node, exportChildren, 0, selection) : null;
|
|
326
|
+
},
|
|
327
|
+
regExp: UNORDERED_LIST_REGEX,
|
|
328
|
+
replace: listReplace("bullet"),
|
|
329
|
+
triggerOnEnter: true,
|
|
330
|
+
type: "element"
|
|
331
|
+
};
|
|
332
|
+
const CHECK_LIST = {
|
|
333
|
+
dependencies: [ListNode, ListItemNode],
|
|
334
|
+
export: (node, exportChildren, selection) => {
|
|
335
|
+
return $isListNode(node) ? $listExport(node, exportChildren, 0, selection) : null;
|
|
336
|
+
},
|
|
337
|
+
regExp: CHECK_LIST_REGEX,
|
|
338
|
+
replace: listReplace("check"),
|
|
339
|
+
triggerOnEnter: true,
|
|
340
|
+
type: "element"
|
|
341
|
+
};
|
|
342
|
+
const ORDERED_LIST = {
|
|
343
|
+
dependencies: [ListNode, ListItemNode],
|
|
344
|
+
export: (node, exportChildren, selection) => {
|
|
345
|
+
return $isListNode(node) ? $listExport(node, exportChildren, 0, selection) : null;
|
|
346
|
+
},
|
|
347
|
+
regExp: ORDERED_LIST_REGEX,
|
|
348
|
+
replace: listReplace("number"),
|
|
349
|
+
triggerOnEnter: true,
|
|
350
|
+
type: "element"
|
|
351
|
+
};
|
|
352
|
+
const INLINE_CODE = {
|
|
353
|
+
format: ["code"],
|
|
354
|
+
tag: "`",
|
|
355
|
+
type: "text-format"
|
|
356
|
+
};
|
|
357
|
+
const HIGHLIGHT = {
|
|
358
|
+
format: ["highlight"],
|
|
359
|
+
tag: "==",
|
|
360
|
+
type: "text-format"
|
|
361
|
+
};
|
|
362
|
+
const BOLD_ITALIC_STAR = {
|
|
363
|
+
format: ["bold", "italic"],
|
|
364
|
+
tag: "***",
|
|
365
|
+
type: "text-format"
|
|
366
|
+
};
|
|
367
|
+
const BOLD_ITALIC_UNDERSCORE = {
|
|
368
|
+
format: ["bold", "italic"],
|
|
369
|
+
intraword: false,
|
|
370
|
+
tag: "___",
|
|
371
|
+
type: "text-format"
|
|
372
|
+
};
|
|
373
|
+
const BOLD_STAR = {
|
|
374
|
+
format: ["bold"],
|
|
375
|
+
tag: "**",
|
|
376
|
+
type: "text-format"
|
|
377
|
+
};
|
|
378
|
+
const BOLD_UNDERSCORE = {
|
|
379
|
+
format: ["bold"],
|
|
380
|
+
intraword: false,
|
|
381
|
+
tag: "__",
|
|
382
|
+
type: "text-format"
|
|
383
|
+
};
|
|
384
|
+
const STRIKETHROUGH = {
|
|
385
|
+
format: ["strikethrough"],
|
|
386
|
+
tag: "~~",
|
|
387
|
+
type: "text-format"
|
|
388
|
+
};
|
|
389
|
+
const ITALIC_STAR = {
|
|
390
|
+
format: ["italic"],
|
|
391
|
+
tag: "*",
|
|
392
|
+
type: "text-format"
|
|
393
|
+
};
|
|
394
|
+
const ITALIC_UNDERSCORE = {
|
|
395
|
+
format: ["italic"],
|
|
396
|
+
intraword: false,
|
|
397
|
+
tag: "_",
|
|
398
|
+
type: "text-format"
|
|
399
|
+
};
|
|
400
|
+
const LINK = {
|
|
401
|
+
dependencies: [LinkNode],
|
|
402
|
+
export: (node, exportChildren, exportFormat) => {
|
|
403
|
+
if (!$isLinkNode(node) || $isAutoLinkNode(node)) return null;
|
|
404
|
+
const textContent = exportChildren(node);
|
|
405
|
+
let title = node.getTitle();
|
|
406
|
+
if (title != null) title = title.replace(/([\\"])/g, "\\$1");
|
|
407
|
+
return title ? `[${textContent}](${node.getURL()} "${title}")` : `[${textContent}](${node.getURL()})`;
|
|
408
|
+
},
|
|
409
|
+
importRegExp: /(?:\[(.+?)\])(?:\((?:([^()\s]+)(?:\s"((?:[^"]*\\")*[^"]*)"\s*)?)\))/,
|
|
410
|
+
regExp: /(?:\[([^[\]]*(?:\[[^[\]]*\][^[\]]*)*)\])(?:\((?:([^()\s]+)(?:\s"((?:[^"]*\\")*[^"]*)"\s*)?)\))$/,
|
|
411
|
+
replace: (textNode, match) => {
|
|
412
|
+
if ($findMatchingParent(textNode, $isLinkNode)) return;
|
|
413
|
+
const [, linkText, rawLinkUrl, rawLinkTitle] = match;
|
|
414
|
+
const linkNode = $createLinkNode(rawLinkUrl != null ? unescapeText(rawLinkUrl) : void 0, { title: rawLinkTitle != null ? unescapeText(rawLinkTitle) : void 0 });
|
|
415
|
+
const openBracketAmount = linkText.split("[").length - 1;
|
|
416
|
+
const closeBracketAmount = linkText.split("]").length - 1;
|
|
417
|
+
let parsedLinkText = linkText;
|
|
418
|
+
let outsideLinkText = "";
|
|
419
|
+
if (openBracketAmount < closeBracketAmount) return;
|
|
420
|
+
else if (openBracketAmount > closeBracketAmount) {
|
|
421
|
+
const linkTextParts = linkText.split("[");
|
|
422
|
+
outsideLinkText = "[" + linkTextParts[0];
|
|
423
|
+
parsedLinkText = linkTextParts.slice(1).join("[");
|
|
424
|
+
}
|
|
425
|
+
const linkTextNode = $createTextNode(parsedLinkText);
|
|
426
|
+
linkTextNode.setFormat(textNode.getFormat());
|
|
427
|
+
linkNode.append(linkTextNode);
|
|
428
|
+
textNode.replace(linkNode);
|
|
429
|
+
if (outsideLinkText) linkNode.insertBefore($createTextNode(outsideLinkText));
|
|
430
|
+
return linkTextNode;
|
|
431
|
+
},
|
|
432
|
+
trigger: ")",
|
|
433
|
+
type: "text-match"
|
|
434
|
+
};
|
|
435
|
+
const ELEMENT_TRANSFORMERS = [
|
|
436
|
+
HEADING,
|
|
437
|
+
QUOTE,
|
|
438
|
+
UNORDERED_LIST,
|
|
439
|
+
ORDERED_LIST
|
|
440
|
+
];
|
|
441
|
+
const MULTILINE_ELEMENT_TRANSFORMERS = [CODE];
|
|
442
|
+
const TEXT_FORMAT_TRANSFORMERS = [
|
|
443
|
+
INLINE_CODE,
|
|
444
|
+
BOLD_ITALIC_STAR,
|
|
445
|
+
BOLD_ITALIC_UNDERSCORE,
|
|
446
|
+
BOLD_STAR,
|
|
447
|
+
BOLD_UNDERSCORE,
|
|
448
|
+
HIGHLIGHT,
|
|
449
|
+
ITALIC_STAR,
|
|
450
|
+
ITALIC_UNDERSCORE,
|
|
451
|
+
STRIKETHROUGH
|
|
452
|
+
];
|
|
453
|
+
const TEXT_MATCH_TRANSFORMERS = [LINK];
|
|
454
|
+
const TRANSFORMERS = [
|
|
455
|
+
...ELEMENT_TRANSFORMERS,
|
|
456
|
+
...MULTILINE_ELEMENT_TRANSFORMERS,
|
|
457
|
+
...TEXT_FORMAT_TRANSFORMERS,
|
|
458
|
+
...TEXT_MATCH_TRANSFORMERS
|
|
459
|
+
];
|
|
460
|
+
function normalizeMarkdown(input, shouldMergeAdjacentLines = false) {
|
|
461
|
+
const lines = input.split("\n");
|
|
462
|
+
let inCodeBlock = false;
|
|
463
|
+
const sanitizedLines = [];
|
|
464
|
+
for (let i = 0; i < lines.length; i++) {
|
|
465
|
+
const rawLine = lines[i];
|
|
466
|
+
const line = rawLine.trimEnd();
|
|
467
|
+
const lastLine = sanitizedLines[sanitizedLines.length - 1];
|
|
468
|
+
const hardLineBreak = i < lines.length - 1 ? parseMarkdownHardLineBreak(rawLine) : null;
|
|
469
|
+
const lastLineHasHardLineBreak = lastLine !== void 0 && parseMarkdownHardLineBreak(lastLine) !== null;
|
|
470
|
+
if (CODE_SINGLE_LINE_REGEX.test(line)) {
|
|
471
|
+
sanitizedLines.push(line);
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
474
|
+
if (CODE_START_REGEX.test(line) || CODE_END_REGEX.test(line)) {
|
|
475
|
+
inCodeBlock = !inCodeBlock;
|
|
476
|
+
sanitizedLines.push(line);
|
|
477
|
+
continue;
|
|
478
|
+
}
|
|
479
|
+
if (inCodeBlock) {
|
|
480
|
+
sanitizedLines.push(rawLine);
|
|
481
|
+
continue;
|
|
482
|
+
}
|
|
483
|
+
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) || lastLineHasHardLineBreak || !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 !== "" || hardLineBreak !== null ? rawLine : line);
|
|
484
|
+
else sanitizedLines[sanitizedLines.length - 1] = lastLine + " " + (hardLineBreak === null ? line : rawLine).trimStart();
|
|
485
|
+
}
|
|
486
|
+
return sanitizedLines.join("\n");
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
490
|
+
*
|
|
491
|
+
* This source code is licensed under the MIT license found in the
|
|
492
|
+
* LICENSE file in the root directory of this source tree.
|
|
493
|
+
*
|
|
494
|
+
*/
|
|
57
495
|
/**
|
|
58
496
|
* Renders string from markdown. The selection is moved to the start after the operation.
|
|
59
497
|
*/
|
|
@@ -69,23 +507,131 @@ function createMarkdownExport(transformers, shouldPreserveNewLines = false) {
|
|
|
69
507
|
const children = (node || $getRoot()).getChildren();
|
|
70
508
|
for (let i = 0; i < children.length; i++) {
|
|
71
509
|
const child = children[i];
|
|
72
|
-
const result = exportTopLevelElements(child, elementTransformers, textFormatTransformers, byType.textMatch, shouldPreserveNewLines);
|
|
510
|
+
const result = $exportTopLevelElements(child, elementTransformers, textFormatTransformers, byType.textMatch, shouldPreserveNewLines);
|
|
73
511
|
if (result != null) output.push(isNewlineDelimited && i > 0 && !isEmptyParagraph(child) && !isEmptyParagraph(children[i - 1]) ? "\n".concat(result) : result);
|
|
74
512
|
}
|
|
75
513
|
return output.join("\n");
|
|
76
514
|
};
|
|
77
515
|
}
|
|
78
|
-
|
|
516
|
+
/**
|
|
517
|
+
* Creates a markdown export function that only exports selected content.
|
|
518
|
+
* Uses a recursive structure similar to $appendNodesToHTML to support
|
|
519
|
+
* extractWithChild for proper handling of partial selections within
|
|
520
|
+
* inline elements like links.
|
|
521
|
+
*/
|
|
522
|
+
function createSelectionMarkdownExport(transformers, shouldPreserveNewLines = false) {
|
|
523
|
+
const byType = transformersByType(transformers);
|
|
524
|
+
const elementTransformers = [...byType.multilineElement, ...byType.element];
|
|
525
|
+
const isNewlineDelimited = !shouldPreserveNewLines;
|
|
526
|
+
const textFormatTransformers = byType.textFormat.filter((transformer) => transformer.format.length === 1).sort((a, b) => {
|
|
527
|
+
return Number(a.format.includes("code")) - Number(b.format.includes("code"));
|
|
528
|
+
});
|
|
529
|
+
return (selection) => {
|
|
530
|
+
const output = [];
|
|
531
|
+
const children = $getRoot().getChildren();
|
|
532
|
+
for (let i = 0; i < children.length; i++) {
|
|
533
|
+
const child = children[i];
|
|
534
|
+
const { shouldInclude, markdown } = $processNodeForSelection(child, selection, elementTransformers, textFormatTransformers, byType.textMatch, shouldPreserveNewLines);
|
|
535
|
+
if (shouldInclude && markdown != null) output.push(isNewlineDelimited && i > 0 && !isEmptyParagraph(child) && !isEmptyParagraph(children[i - 1]) ? "\n".concat(markdown) : markdown);
|
|
536
|
+
}
|
|
537
|
+
return output.join("\n");
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
function $processNodeForSelection(node, selection, elementTransformers, textFormatTransformers, textMatchTransformers, shouldPreserveNewLines) {
|
|
541
|
+
let shouldInclude = node.isSelected(selection);
|
|
542
|
+
for (const transformer of elementTransformers) {
|
|
543
|
+
if (!transformer.export) continue;
|
|
544
|
+
const result = transformer.export(node, (node_) => $exportChildrenForSelection(node_, selection, textFormatTransformers, textMatchTransformers, shouldPreserveNewLines).markdown, selection);
|
|
545
|
+
if (result != null) {
|
|
546
|
+
if (!shouldInclude) {
|
|
547
|
+
if ($isElementNode(node)) {
|
|
548
|
+
if ($exportChildrenForSelection(node, selection, textFormatTransformers, textMatchTransformers, shouldPreserveNewLines).shouldInclude) shouldInclude = true;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
return {
|
|
552
|
+
markdown: result,
|
|
553
|
+
shouldInclude
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
if ($isElementNode(node)) {
|
|
558
|
+
const childResult = $exportChildrenForSelection(node, selection, textFormatTransformers, textMatchTransformers, shouldPreserveNewLines);
|
|
559
|
+
return {
|
|
560
|
+
markdown: childResult.markdown,
|
|
561
|
+
shouldInclude: shouldInclude || childResult.shouldInclude
|
|
562
|
+
};
|
|
563
|
+
} else if ($isDecoratorNode(node)) return {
|
|
564
|
+
markdown: node.getTextContent(),
|
|
565
|
+
shouldInclude
|
|
566
|
+
};
|
|
567
|
+
else return {
|
|
568
|
+
markdown: null,
|
|
569
|
+
shouldInclude
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
function $exportChildrenForSelection(node, selection, textFormatTransformers, textMatchTransformers, shouldPreserveNewLines, unclosedTags, unclosableTags) {
|
|
573
|
+
const output = [];
|
|
574
|
+
const children = node.getChildren();
|
|
575
|
+
let anyChildIncluded = false;
|
|
576
|
+
if (!unclosedTags) unclosedTags = [];
|
|
577
|
+
if (!unclosableTags) unclosableTags = [];
|
|
578
|
+
mainLoop: for (const child of children) {
|
|
579
|
+
let childIncluded = child.isSelected(selection);
|
|
580
|
+
for (const transformer of textMatchTransformers) {
|
|
581
|
+
if (!transformer.export) continue;
|
|
582
|
+
const result = transformer.export(child, (parentNode) => $exportChildrenForSelection(parentNode, selection, textFormatTransformers, textMatchTransformers, shouldPreserveNewLines, unclosedTags, [...unclosableTags, ...unclosedTags]).markdown, (textNode, textContent) => {
|
|
583
|
+
return exportTextFormat(textNode, $sliceSelectedTextNodeContent(selection, textNode, "clone").getTextContent(), textFormatTransformers, unclosedTags, unclosableTags, shouldPreserveNewLines);
|
|
584
|
+
});
|
|
585
|
+
if (result != null) {
|
|
586
|
+
if (!childIncluded && $isElementNode(child) && child.getChildren().some((c) => c.isSelected(selection)) && child.extractWithChild(child, selection, "html")) childIncluded = true;
|
|
587
|
+
if (childIncluded) {
|
|
588
|
+
output.push(result);
|
|
589
|
+
anyChildIncluded = true;
|
|
590
|
+
}
|
|
591
|
+
continue mainLoop;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
if ($isLineBreakNode(child)) {
|
|
595
|
+
if (childIncluded) {
|
|
596
|
+
output.push($exportLineBreak(child));
|
|
597
|
+
anyChildIncluded = true;
|
|
598
|
+
}
|
|
599
|
+
} else if ($isTextNode(child)) {
|
|
600
|
+
if (childIncluded) {
|
|
601
|
+
const target = $sliceSelectedTextNodeContent(selection, child, "clone");
|
|
602
|
+
output.push(exportTextFormat(child, target.getTextContent(), textFormatTransformers, unclosedTags, unclosableTags, shouldPreserveNewLines));
|
|
603
|
+
anyChildIncluded = true;
|
|
604
|
+
}
|
|
605
|
+
} else if ($isElementNode(child)) {
|
|
606
|
+
const childResult = $exportChildrenForSelection(child, selection, textFormatTransformers, textMatchTransformers, shouldPreserveNewLines, unclosedTags, unclosableTags);
|
|
607
|
+
if (!childIncluded && childResult.shouldInclude && child.extractWithChild(child, selection, "html")) childIncluded = true;
|
|
608
|
+
if (childIncluded || childResult.shouldInclude) {
|
|
609
|
+
output.push(childResult.markdown);
|
|
610
|
+
anyChildIncluded = true;
|
|
611
|
+
}
|
|
612
|
+
} else if ($isDecoratorNode(child)) {
|
|
613
|
+
if (childIncluded) {
|
|
614
|
+
output.push(child.getTextContent());
|
|
615
|
+
anyChildIncluded = true;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
return {
|
|
620
|
+
markdown: output.join(""),
|
|
621
|
+
shouldInclude: anyChildIncluded
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
function $exportTopLevelElements(node, elementTransformers, textTransformersIndex, textMatchTransformers, shouldPreserveNewLines) {
|
|
79
625
|
for (const transformer of elementTransformers) {
|
|
80
626
|
if (!transformer.export) continue;
|
|
81
|
-
const result = transformer.export(node, (_node) => exportChildren(_node, textTransformersIndex, textMatchTransformers, void 0, void 0, shouldPreserveNewLines));
|
|
627
|
+
const result = transformer.export(node, (_node) => $exportChildren(_node, textTransformersIndex, textMatchTransformers, void 0, void 0, shouldPreserveNewLines));
|
|
82
628
|
if (result != null) return result;
|
|
83
629
|
}
|
|
84
|
-
if ($isElementNode(node)) return exportChildren(node, textTransformersIndex, textMatchTransformers, void 0, void 0, shouldPreserveNewLines);
|
|
630
|
+
if ($isElementNode(node)) return $exportChildren(node, textTransformersIndex, textMatchTransformers, void 0, void 0, shouldPreserveNewLines);
|
|
85
631
|
else if ($isDecoratorNode(node)) return node.getTextContent();
|
|
86
632
|
else return null;
|
|
87
633
|
}
|
|
88
|
-
function exportChildren(node, textTransformersIndex, textMatchTransformers, unclosedTags, unclosableTags, shouldPreserveNewLines = false) {
|
|
634
|
+
function $exportChildren(node, textTransformersIndex, textMatchTransformers, unclosedTags, unclosableTags, shouldPreserveNewLines = false) {
|
|
89
635
|
const output = [];
|
|
90
636
|
const children = node.getChildren();
|
|
91
637
|
if (!unclosedTags) unclosedTags = [];
|
|
@@ -93,19 +639,22 @@ function exportChildren(node, textTransformersIndex, textMatchTransformers, uncl
|
|
|
93
639
|
mainLoop: for (const child of children) {
|
|
94
640
|
for (const transformer of textMatchTransformers) {
|
|
95
641
|
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));
|
|
642
|
+
const result = transformer.export(child, (parentNode) => $exportChildren(parentNode, textTransformersIndex, textMatchTransformers, unclosedTags, [...unclosableTags, ...unclosedTags], shouldPreserveNewLines), (textNode, textContent) => exportTextFormat(textNode, textContent, textTransformersIndex, unclosedTags, unclosableTags, shouldPreserveNewLines));
|
|
97
643
|
if (result != null) {
|
|
98
644
|
output.push(result);
|
|
99
645
|
continue mainLoop;
|
|
100
646
|
}
|
|
101
647
|
}
|
|
102
|
-
if ($isLineBreakNode(child)) output.push(
|
|
648
|
+
if ($isLineBreakNode(child)) output.push($exportLineBreak(child));
|
|
103
649
|
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));
|
|
650
|
+
else if ($isElementNode(child)) output.push($exportChildren(child, textTransformersIndex, textMatchTransformers, unclosedTags, unclosableTags, shouldPreserveNewLines));
|
|
105
651
|
else if ($isDecoratorNode(child)) output.push(child.getTextContent());
|
|
106
652
|
}
|
|
107
653
|
return output.join("");
|
|
108
654
|
}
|
|
655
|
+
function $exportLineBreak(node) {
|
|
656
|
+
return $getState(node, hardLineBreakState) + "\n";
|
|
657
|
+
}
|
|
109
658
|
function exportTextFormat(node, textContent, textTransformers, unclosedTags, unclosableTags, shouldPreserveNewLines = false) {
|
|
110
659
|
let output = textContent;
|
|
111
660
|
if (!node.hasFormat("code")) output = shouldPreserveNewLines ? output.replace(/([*_`~])/g, "\\$1") : output.replace(/([*_`~\\])/g, "\\$1");
|
|
@@ -440,165 +989,9 @@ function importTextTransformers(textNode, textFormatTransformersIndex, textMatch
|
|
|
440
989
|
if (canContainTransformableMarkdown(result.nodeAfter)) importTextTransformers(result.nodeAfter, textFormatTransformersIndex, textMatchTransformers);
|
|
441
990
|
if (canContainTransformableMarkdown(result.nodeBefore)) importTextTransformers(result.nodeBefore, textFormatTransformersIndex, textMatchTransformers);
|
|
442
991
|
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
|
-
};
|
|
992
|
+
}
|
|
993
|
+
const unescapedText = unescapeText(textNode.getTextContent());
|
|
994
|
+
textNode.setTextContent(unescapedText);
|
|
602
995
|
}
|
|
603
996
|
/**
|
|
604
997
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
@@ -607,401 +1000,169 @@ function createTextFormatTransformersIndex(textTransformers) {
|
|
|
607
1000
|
* LICENSE file in the root directory of this source tree.
|
|
608
1001
|
*
|
|
609
1002
|
*/
|
|
610
|
-
function formatDevErrorMessage(message) {
|
|
611
|
-
throw new Error(message);
|
|
612
|
-
}
|
|
613
1003
|
/**
|
|
614
|
-
*
|
|
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
|
-
*
|
|
1004
|
+
* Renders markdown from a string. The selection is moved to the start after the operation.
|
|
619
1005
|
*/
|
|
620
|
-
|
|
621
|
-
const
|
|
622
|
-
const
|
|
623
|
-
|
|
624
|
-
const
|
|
625
|
-
const
|
|
626
|
-
const
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
const
|
|
630
|
-
const
|
|
631
|
-
|
|
632
|
-
|
|
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));
|
|
1006
|
+
function createMarkdownImport(transformers, shouldPreserveNewLines = false) {
|
|
1007
|
+
const byType = transformersByType(transformers);
|
|
1008
|
+
const textFormatTransformersIndex = createTextFormatTransformersIndex(byType.textFormat);
|
|
1009
|
+
return (markdownString, node) => {
|
|
1010
|
+
const lines = markdownString.split("\n");
|
|
1011
|
+
const linesLength = lines.length;
|
|
1012
|
+
const root = node || $getRoot();
|
|
1013
|
+
root.clear();
|
|
1014
|
+
for (let i = 0; i < linesLength; i++) {
|
|
1015
|
+
const lineText = lines[i];
|
|
1016
|
+
const [imported, shiftedIndex] = $importMultiline(lines, i, byType.multilineElement, root);
|
|
1017
|
+
if (imported) {
|
|
1018
|
+
i = shiftedIndex;
|
|
699
1019
|
continue;
|
|
700
1020
|
}
|
|
1021
|
+
$importBlocks(lineText, root, byType.element, textFormatTransformersIndex, byType.textMatch, shouldPreserveNewLines);
|
|
701
1022
|
}
|
|
702
|
-
const
|
|
703
|
-
const
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
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);
|
|
1023
|
+
const children = root.getChildren();
|
|
1024
|
+
for (const child of children) {
|
|
1025
|
+
if (!shouldPreserveNewLines && isEmptyParagraph(child) && root.getChildrenSize() > 1) {
|
|
1026
|
+
child.remove();
|
|
1027
|
+
continue;
|
|
763
1028
|
}
|
|
1029
|
+
if ($isElementNode(child)) for (const textNode of child.getAllTextNodes()) $normalizeMarkdownTextNode(textNode);
|
|
764
1030
|
}
|
|
765
|
-
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
if (
|
|
786
|
-
|
|
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
|
-
}
|
|
1031
|
+
if ($getSelection() !== null) root.selectStart();
|
|
1032
|
+
};
|
|
1033
|
+
}
|
|
1034
|
+
/**
|
|
1035
|
+
*
|
|
1036
|
+
* @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.
|
|
1037
|
+
*/
|
|
1038
|
+
function $importMultiline(lines, startLineIndex, multilineElementTransformers, rootNode) {
|
|
1039
|
+
for (const transformer of multilineElementTransformers) {
|
|
1040
|
+
const { handleImportAfterStartMatch, regExpEnd, regExpStart, replace } = transformer;
|
|
1041
|
+
const startMatch = lines[startLineIndex].match(regExpStart);
|
|
1042
|
+
if (!startMatch) continue;
|
|
1043
|
+
if (handleImportAfterStartMatch) {
|
|
1044
|
+
const result = handleImportAfterStartMatch({
|
|
1045
|
+
lines,
|
|
1046
|
+
rootNode,
|
|
1047
|
+
startLineIndex,
|
|
1048
|
+
startMatch,
|
|
1049
|
+
transformer
|
|
1050
|
+
});
|
|
1051
|
+
if (result === null) continue;
|
|
1052
|
+
else if (result) return result;
|
|
793
1053
|
}
|
|
794
|
-
const
|
|
795
|
-
const
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
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);
|
|
1054
|
+
const regexpEndRegex = typeof regExpEnd === "object" && "regExp" in regExpEnd ? regExpEnd.regExp : regExpEnd;
|
|
1055
|
+
const isEndOptional = regExpEnd && typeof regExpEnd === "object" && "optional" in regExpEnd ? regExpEnd.optional : !regExpEnd;
|
|
1056
|
+
let endLineIndex = startLineIndex;
|
|
1057
|
+
const linesLength = lines.length;
|
|
1058
|
+
while (endLineIndex < linesLength) {
|
|
1059
|
+
const endMatch = regexpEndRegex ? lines[endLineIndex].match(regexpEndRegex) : null;
|
|
1060
|
+
if (!endMatch) {
|
|
1061
|
+
if (!isEndOptional || isEndOptional && endLineIndex < linesLength - 1) {
|
|
1062
|
+
endLineIndex++;
|
|
1063
|
+
continue;
|
|
823
1064
|
}
|
|
824
|
-
while (linesInBetween.length > 0 && !linesInBetween[linesInBetween.length - 1].length) linesInBetween.pop();
|
|
825
|
-
code = linesInBetween.join("\n");
|
|
826
1065
|
}
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
}
|
|
837
|
-
const
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
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;
|
|
1066
|
+
if (endMatch && startLineIndex === endLineIndex && endMatch.index === startMatch.index) {
|
|
1067
|
+
endLineIndex++;
|
|
1068
|
+
continue;
|
|
1069
|
+
}
|
|
1070
|
+
const linesInBetween = [];
|
|
1071
|
+
if (endMatch && startLineIndex === endLineIndex) linesInBetween.push(lines[startLineIndex].slice(startMatch[0].length, -endMatch[0].length));
|
|
1072
|
+
else for (let i = startLineIndex; i <= endLineIndex; i++) if (i === startLineIndex) {
|
|
1073
|
+
const text = lines[i].slice(startMatch[0].length);
|
|
1074
|
+
linesInBetween.push(text);
|
|
1075
|
+
} else if (i === endLineIndex && endMatch) {
|
|
1076
|
+
const text = lines[i].slice(0, -endMatch[0].length);
|
|
1077
|
+
linesInBetween.push(text);
|
|
1078
|
+
} else linesInBetween.push(lines[i]);
|
|
1079
|
+
if (replace(rootNode, null, startMatch, endMatch, linesInBetween, true) !== false) return [true, endLineIndex];
|
|
1080
|
+
break;
|
|
983
1081
|
}
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
1082
|
+
}
|
|
1083
|
+
return [false, startLineIndex];
|
|
1084
|
+
}
|
|
1085
|
+
function $importBlocks(lineText, rootNode, elementTransformers, textFormatTransformersIndex, textMatchTransformers, shouldPreserveNewLines) {
|
|
1086
|
+
const textNode = $createTextNode(lineText);
|
|
1087
|
+
const elementNode = $createParagraphNode();
|
|
1088
|
+
elementNode.append(textNode);
|
|
1089
|
+
rootNode.append(elementNode);
|
|
1090
|
+
for (const { regExp, replace } of elementTransformers) {
|
|
1091
|
+
const match = lineText.match(regExp);
|
|
1092
|
+
if (match) {
|
|
1093
|
+
textNode.setTextContent(lineText.slice(match[0].length));
|
|
1094
|
+
if (replace(elementNode, [textNode], match, true) !== false) break;
|
|
988
1095
|
}
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
1096
|
+
}
|
|
1097
|
+
importTextTransformers(textNode, textFormatTransformersIndex, textMatchTransformers);
|
|
1098
|
+
if (elementNode.isAttached() && lineText.length > 0) {
|
|
1099
|
+
const previousNode = elementNode.getPreviousSibling();
|
|
1100
|
+
if (!shouldPreserveNewLines && ($isParagraphNode(previousNode) || $isQuoteNode(previousNode) || $isListNode(previousNode))) {
|
|
1101
|
+
let targetNode = previousNode;
|
|
1102
|
+
if ($isListNode(previousNode)) {
|
|
1103
|
+
const lastDescendant = previousNode.getLastDescendant();
|
|
1104
|
+
if (lastDescendant == null) targetNode = null;
|
|
1105
|
+
else targetNode = $findMatchingParent$1(lastDescendant, $isListItemNode);
|
|
1106
|
+
}
|
|
1107
|
+
if (targetNode != null && targetNode.getTextContentSize() > 0) {
|
|
1108
|
+
targetNode.splice(targetNode.getChildrenSize(), 0, [$createMarkdownLineBreakNode(targetNode), ...elementNode.getChildren()]);
|
|
1109
|
+
elementNode.remove();
|
|
1110
|
+
}
|
|
992
1111
|
}
|
|
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
1112
|
}
|
|
996
|
-
return sanitizedLines.join("\n");
|
|
997
1113
|
}
|
|
998
|
-
function
|
|
1114
|
+
function $normalizeMarkdownTextNode(textNode) {
|
|
1115
|
+
const tabOffsets = /* @__PURE__ */ new Set();
|
|
1116
|
+
const text = textNode.getTextContent();
|
|
1117
|
+
let index = text.indexOf(" ");
|
|
1118
|
+
while (index !== -1) {
|
|
1119
|
+
tabOffsets.add(index);
|
|
1120
|
+
tabOffsets.add(index + 1);
|
|
1121
|
+
index = text.indexOf(" ", index + 1);
|
|
1122
|
+
}
|
|
1123
|
+
textNode.splitText(...tabOffsets).forEach((node) => {
|
|
1124
|
+
if (node.getTextContent() === " ") node.replace($createTabNode());
|
|
1125
|
+
});
|
|
1126
|
+
}
|
|
1127
|
+
function createTextFormatTransformersIndex(textTransformers) {
|
|
1128
|
+
const transformersByTag = {};
|
|
1129
|
+
const fullMatchRegExpByTag = {};
|
|
1130
|
+
const openTagsRegExp = [];
|
|
1131
|
+
for (const transformer of textTransformers) {
|
|
1132
|
+
const { tag } = transformer;
|
|
1133
|
+
transformersByTag[tag] = transformer;
|
|
1134
|
+
const tagRegExp = tag.replace(/(\*|\^|\+)/g, "\\$1");
|
|
1135
|
+
openTagsRegExp.push(tagRegExp);
|
|
1136
|
+
if (tag.length === 1) if (tag === "`") fullMatchRegExpByTag[tag] = new RegExp(`(^|[^\\\\\`])(\`)((?:\\\\\`|[^\`])+?)(\`)(?!\`)`);
|
|
1137
|
+
else fullMatchRegExpByTag[tag] = new RegExp(`(^|[^\\\\${tagRegExp}])(${tagRegExp})((\\\\${tagRegExp})?.*?[^${tagRegExp}\\s](\\\\${tagRegExp})?)(${tagRegExp})(?![\\\\${tagRegExp}])`);
|
|
1138
|
+
else fullMatchRegExpByTag[tag] = new RegExp(`(^|[^\\\\])(${tagRegExp})((\\\\${tagRegExp})?.*?[^\\s](\\\\${tagRegExp})?)(${tagRegExp})(?!\\\\)`);
|
|
1139
|
+
}
|
|
1140
|
+
return {
|
|
1141
|
+
fullMatchRegExpByTag,
|
|
1142
|
+
openTagsRegExp: new RegExp(`(${openTagsRegExp.join("|")})`, "g"),
|
|
1143
|
+
transformersByTag
|
|
1144
|
+
};
|
|
1145
|
+
}
|
|
1146
|
+
/**
|
|
1147
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
1148
|
+
*
|
|
1149
|
+
* This source code is licensed under the MIT license found in the
|
|
1150
|
+
* LICENSE file in the root directory of this source tree.
|
|
1151
|
+
*
|
|
1152
|
+
*/
|
|
1153
|
+
function formatDevErrorMessage(message) {
|
|
1154
|
+
throw new Error(message);
|
|
1155
|
+
}
|
|
1156
|
+
function runElementTransformers(parentNode, anchorNode, anchorOffset, elementTransformers, triggerOnEnter) {
|
|
999
1157
|
if (!$isRootOrShadowRoot(parentNode.getParent()) || parentNode.getFirstChild() !== anchorNode) return false;
|
|
1000
1158
|
const textContent = anchorNode.getTextContent();
|
|
1001
|
-
if (
|
|
1159
|
+
if (!triggerOnEnter) {
|
|
1160
|
+
if (textContent[anchorOffset - 1] !== " ") return false;
|
|
1161
|
+
}
|
|
1002
1162
|
for (const { regExp, replace } of elementTransformers) {
|
|
1003
1163
|
const match = textContent.match(regExp);
|
|
1004
|
-
|
|
1164
|
+
const expectedMatchLength = triggerOnEnter || match && match[0].endsWith(" ") ? anchorOffset : anchorOffset - 1;
|
|
1165
|
+
if (match && match[0].length === expectedMatchLength) {
|
|
1005
1166
|
const nextSiblings = anchorNode.getNextSiblings();
|
|
1006
1167
|
const [leadingNode, remainderNode] = anchorNode.splitText(anchorOffset);
|
|
1007
1168
|
if (replace(parentNode, remainderNode ? [remainderNode, ...nextSiblings] : nextSiblings, match, false) !== false) {
|
|
@@ -1129,8 +1290,12 @@ function isEqualSubString(stringA, aStart, stringB, bStart, length) {
|
|
|
1129
1290
|
}
|
|
1130
1291
|
function registerMarkdownShortcuts(editor, transformers = TRANSFORMERS) {
|
|
1131
1292
|
const byType = transformersByType(transformers);
|
|
1293
|
+
const elementTransformersForEnter = byType.element.filter((t) => t.triggerOnEnter);
|
|
1132
1294
|
const textFormatTransformersByTrigger = indexBy(byType.textFormat, ({ tag }) => tag[tag.length - 1]);
|
|
1133
1295
|
const textMatchTransformersByTrigger = indexBy(byType.textMatch, ({ trigger }) => trigger);
|
|
1296
|
+
const compositionEndTriggerChars = new Set([" "]);
|
|
1297
|
+
for (const t of byType.textFormat) compositionEndTriggerChars.add(t.tag.slice(-1));
|
|
1298
|
+
for (const t of byType.textMatch) if (t.trigger !== void 0) compositionEndTriggerChars.add(t.trigger);
|
|
1134
1299
|
for (const transformer of transformers) {
|
|
1135
1300
|
const type = transformer.type;
|
|
1136
1301
|
if (type === "element" || type === "text-match" || type === "multiline-element") {
|
|
@@ -1148,13 +1313,18 @@ function registerMarkdownShortcuts(editor, transformers = TRANSFORMERS) {
|
|
|
1148
1313
|
return mergeRegister(editor.registerUpdateListener(({ tags, dirtyLeaves, editorState, prevEditorState }) => {
|
|
1149
1314
|
if (tags.has(COLLABORATION_TAG) || tags.has(HISTORIC_TAG)) return;
|
|
1150
1315
|
if (editor.isComposing()) return;
|
|
1316
|
+
const isCompositionEnd = tags.has(COMPOSITION_END_TAG);
|
|
1151
1317
|
const selection = editorState.read($getSelection);
|
|
1152
1318
|
const prevSelection = prevEditorState.read($getSelection);
|
|
1153
|
-
if (!$isRangeSelection(prevSelection) || !$isRangeSelection(selection) || !selection.isCollapsed() || selection.is(prevSelection)) return;
|
|
1319
|
+
if (!$isRangeSelection(prevSelection) || !$isRangeSelection(selection) || !selection.isCollapsed() || selection.is(prevSelection) && !isCompositionEnd) return;
|
|
1154
1320
|
const anchorKey = selection.anchor.key;
|
|
1155
1321
|
const anchorOffset = selection.anchor.offset;
|
|
1156
1322
|
const anchorNode = editorState._nodeMap.get(anchorKey);
|
|
1157
|
-
if (!$isTextNode(anchorNode) || !dirtyLeaves.has(anchorKey) || anchorOffset !== 1 && anchorOffset > prevSelection.anchor.offset + 1) return;
|
|
1323
|
+
if (!$isTextNode(anchorNode) || !dirtyLeaves.has(anchorKey) || !isCompositionEnd && anchorOffset !== 1 && anchorOffset > prevSelection.anchor.offset + 1) return;
|
|
1324
|
+
if (isCompositionEnd) {
|
|
1325
|
+
const closeChar = editorState.read(() => anchorNode.getTextContent())[anchorOffset - 1];
|
|
1326
|
+
if (!compositionEndTriggerChars.has(closeChar)) return;
|
|
1327
|
+
}
|
|
1158
1328
|
editor.update(() => {
|
|
1159
1329
|
if (!canContainTransformableMarkdown(anchorNode)) return;
|
|
1160
1330
|
const parentNode = anchorNode.getParent();
|
|
@@ -1171,7 +1341,7 @@ function registerMarkdownShortcuts(editor, transformers = TRANSFORMERS) {
|
|
|
1171
1341
|
const parentNode = anchorNode.getParent();
|
|
1172
1342
|
if (parentNode === null || $isCodeNode(parentNode)) return false;
|
|
1173
1343
|
if (anchorOffset !== anchorNode.getTextContent().length) return false;
|
|
1174
|
-
if (runMultilineElementTransformers(parentNode, anchorNode, anchorOffset, byType.multilineElement, true)) {
|
|
1344
|
+
if (runMultilineElementTransformers(parentNode, anchorNode, anchorOffset, byType.multilineElement, true) || runElementTransformers(parentNode, anchorNode, anchorOffset, elementTransformersForEnter, true)) {
|
|
1175
1345
|
if (event !== null) event.preventDefault();
|
|
1176
1346
|
return true;
|
|
1177
1347
|
}
|
|
@@ -1201,5 +1371,12 @@ function $convertFromMarkdownString(markdown, transformers = TRANSFORMERS, node,
|
|
|
1201
1371
|
function $convertToMarkdownString(transformers = TRANSFORMERS, node, shouldPreserveNewLines = false) {
|
|
1202
1372
|
return createMarkdownExport(transformers, shouldPreserveNewLines)(node);
|
|
1203
1373
|
}
|
|
1374
|
+
/**
|
|
1375
|
+
* Converts the selected content to a markdown string.
|
|
1376
|
+
*/
|
|
1377
|
+
function $convertSelectionToMarkdownString(transformers = TRANSFORMERS, selection, shouldPreserveNewLines = false) {
|
|
1378
|
+
if (!selection || $isRangeSelection(selection) && selection.isCollapsed()) return "";
|
|
1379
|
+
return createSelectionMarkdownExport(transformers, shouldPreserveNewLines)(selection);
|
|
1380
|
+
}
|
|
1204
1381
|
//#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 };
|
|
1382
|
+
export { $convertFromMarkdownString, $convertSelectionToMarkdownString, $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 };
|