@lexical/markdown 0.53.0 → 0.53.1-nightly.20261030.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/LexicalMarkdown.dev.js +161 -114
- package/dist/LexicalMarkdown.prod.js +1 -1
- package/package.json +11 -11
- package/src/MarkdownExport.ts +135 -87
- package/src/MarkdownTransformers.ts +53 -47
- package/src/importTextTransformers.ts +1 -1
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { $isParagraphNode, $isTextNode, $setState, $createTextNode, $getState, $findMatchingParent, $createLineBreakNode, createState, $isLineBreakNode, $getRoot, $isElementNode, $isDecoratorNode, $isTabNode, $createTabNode, $createParagraphNode, mergeRegister, COLLABORATION_TAG, HISTORIC_TAG, COMPOSITION_END_TAG, $getSelection, $
|
|
9
|
+
import { $isParagraphNode, $isTextNode, $setState, $createTextNode, $getState, $findMatchingParent, $createLineBreakNode, createState, $isLineBreakNode, $isRangeSelection, $getRoot, $isElementNode, $isDecoratorNode, $isTabNode, $createTabNode, $createParagraphNode, mergeRegister, COLLABORATION_TAG, HISTORIC_TAG, COMPOSITION_END_TAG, $getSelection, $addUpdateTag, HISTORY_PUSH_TAG, KEY_ENTER_COMMAND, COMMAND_PRIORITY_LOW, $isRootOrShadowRoot, $createRangeSelection, $setSelection, TEXT_TYPE_TO_FORMAT, ArtificialNode__DO_NOT_USE } from 'lexical';
|
|
10
10
|
import { $sliceSelectedTextNodeContent } from '@lexical/selection';
|
|
11
11
|
import { CodeNode, $createCodeNode, $isCodeNode } from '@lexical/code-core';
|
|
12
12
|
import { LinkNode, $isLinkNode, $createLinkNode, $isAutoLinkNode } from '@lexical/link';
|
|
@@ -1099,7 +1099,9 @@ function getCodeSpanDelimiter(content) {
|
|
|
1099
1099
|
const backtickRuns = content.match(/`+/g);
|
|
1100
1100
|
const longestRun = backtickRuns ? Math.max(...backtickRuns.map(run => run.length)) : 0;
|
|
1101
1101
|
const fence = '`'.repeat(longestRun + 1);
|
|
1102
|
-
|
|
1102
|
+
// A reader strips one space from each end only when the content is not all
|
|
1103
|
+
// spaces, so content made only of spaces goes out as it is.
|
|
1104
|
+
const needsPadding = content.length === 0 || content.includes('`') || /^\s/.test(content) && /\s$/.test(content) && /[^ ]/.test(content);
|
|
1103
1105
|
const padded = needsPadding ? ` ${content} ` : content;
|
|
1104
1106
|
return {
|
|
1105
1107
|
fence,
|
|
@@ -1150,14 +1152,36 @@ const ITALIC_UNDERSCORE = {
|
|
|
1150
1152
|
type: 'text-format'
|
|
1151
1153
|
};
|
|
1152
1154
|
|
|
1153
|
-
//
|
|
1154
|
-
//
|
|
1155
|
-
//
|
|
1156
|
-
//
|
|
1157
|
-
//
|
|
1158
|
-
//
|
|
1159
|
-
|
|
1160
|
-
|
|
1155
|
+
// A raw link destination cannot hold an ASCII control character or a space in
|
|
1156
|
+
// CommonMark, nor any Unicode whitespace in the raw branch of `LINK`'s import
|
|
1157
|
+
// patterns, so export writes a URL with any of them in the pointy form. Import
|
|
1158
|
+
// still reads control characters in a raw destination, as older exports wrote
|
|
1159
|
+
// them there. A NUL reads back as U+FFFD in a CommonMark reader whichever form
|
|
1160
|
+
// it is in, since no spelling of it avoids that.
|
|
1161
|
+
// eslint-disable-next-line no-control-regex
|
|
1162
|
+
const NOT_RAW_DESTINATION = /[\s\0-\x1f\x7f]/;
|
|
1163
|
+
|
|
1164
|
+
// A link destination or title is read back through `unescapeText`, which
|
|
1165
|
+
// decodes a numeric character reference, and a CommonMark reader decodes the
|
|
1166
|
+
// named ones too. So an `&` that begins one goes out as `&`, or the part
|
|
1167
|
+
// would come back as the character the reference names. An `&` that begins
|
|
1168
|
+
// nothing is an ordinary character and stays as it is, so a query string keeps
|
|
1169
|
+
// the separators it was written with.
|
|
1170
|
+
//
|
|
1171
|
+
// Then every match of `syntax`, a global regular expression for the characters
|
|
1172
|
+
// the part's shape treats as syntax, gets a backslash. So does a backtick: this
|
|
1173
|
+
// package's importer reads code spans before links, so one anywhere in the
|
|
1174
|
+
// link could pair with one in the text after it and swallow the link, although
|
|
1175
|
+
// a CommonMark reader would not let it.
|
|
1176
|
+
//
|
|
1177
|
+
// Neither part may hold a line ending either. CommonMark allows none in a
|
|
1178
|
+
// destination and no blank line in a title, where two CRs make one as surely
|
|
1179
|
+
// as two LFs, and the importer reads one LF-separated line at a time, so even
|
|
1180
|
+
// a single LF would split the link. Each goes out as the character reference
|
|
1181
|
+
// that `unescapeText` and a CommonMark reader both turn back into the line
|
|
1182
|
+
// ending, written after the `&` escape so that one leaves it alone.
|
|
1183
|
+
function escapeLinkPart(value, syntax) {
|
|
1184
|
+
return value.replace(/&(?=#\d+;|#[Xx][\dA-Fa-f]+;|[A-Za-z][\dA-Za-z]*;)/g, '&').replace(syntax, '\\$&').replace(/`/g, '\\`').replace(/[\r\n]/g, lineEnding => `&#${lineEnding.charCodeAt(0)};`);
|
|
1161
1185
|
}
|
|
1162
1186
|
|
|
1163
1187
|
// Mask escaped/code brackets without changing source offsets, then find an inner
|
|
@@ -1207,35 +1231,20 @@ const LINK = {
|
|
|
1207
1231
|
return null;
|
|
1208
1232
|
}
|
|
1209
1233
|
const textContent = exportChildren(node);
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
// A
|
|
1213
|
-
//
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
//
|
|
1219
|
-
// written in the pointy form, where only `<`, `>` and a backslash need an
|
|
1220
|
-
// escape. An empty URL goes there too, since the raw form has nothing left
|
|
1221
|
-
// to match. Everywhere else the destination is written raw, where a
|
|
1222
|
-
// parenthesis would close it early, a backslash would start an escape, and
|
|
1223
|
-
// only a `<` in first place turns it into the pointy form. An angle
|
|
1224
|
-
// bracket anywhere else is an ordinary character and goes out as it is.
|
|
1225
|
-
//
|
|
1226
|
-
// Neither shape may hold a line ending, so a literal one would leave a
|
|
1227
|
-
// destination that no reader can close and would split the paragraph in
|
|
1228
|
-
// two. It goes out as the character reference that `unescapeText` and a
|
|
1229
|
-
// CommonMark reader both turn back into the line ending.
|
|
1230
|
-
//
|
|
1231
|
-
// That spelling only survives because a reader decodes it, so an `&` that
|
|
1232
|
-
// already begins a character reference has to go out as one itself, or the
|
|
1233
|
-
// URL comes back as whatever the reference names. Escaping it first keeps
|
|
1234
|
-
// the references written for the line endings below out of its way.
|
|
1234
|
+
const title = node.getTitle();
|
|
1235
|
+
|
|
1236
|
+
// A URL that `NOT_RAW_DESTINATION` matches goes in the pointy form, where
|
|
1237
|
+
// `<`, `>` and a backslash are syntax. An empty URL goes there too, since
|
|
1238
|
+
// the raw form has nothing left to match. Everywhere else the destination
|
|
1239
|
+
// is written raw, where a parenthesis would close it early, a backslash
|
|
1240
|
+
// would start an escape, and only a `<` in first place turns it into the
|
|
1241
|
+
// pointy form. An angle bracket anywhere else is an ordinary character and
|
|
1242
|
+
// goes out as it is.
|
|
1235
1243
|
const rawUrl = node.getURL();
|
|
1236
|
-
const
|
|
1237
|
-
|
|
1238
|
-
|
|
1244
|
+
const url = rawUrl === '' || NOT_RAW_DESTINATION.test(rawUrl) ? `<${escapeLinkPart(rawUrl, /[\\<>]/g)}>` : escapeLinkPart(rawUrl, /[\\()]|^</g);
|
|
1245
|
+
|
|
1246
|
+
// In the double-quoted title only `"` and a backslash are syntax.
|
|
1247
|
+
const linkContent = title ? `[${textContent}](${url} "${escapeLinkPart(title, /[\\"]/g)}")` : `[${textContent}](${url})`;
|
|
1239
1248
|
return linkContent;
|
|
1240
1249
|
},
|
|
1241
1250
|
// A link destination comes in two shapes, is itself optional, and may have
|
|
@@ -1265,8 +1274,8 @@ const LINK = {
|
|
|
1265
1274
|
// whitespace side by side can be split between them in as many ways as there
|
|
1266
1275
|
// are characters, which costs a quadratic walk of every run that never
|
|
1267
1276
|
// reaches the closing parenthesis.
|
|
1268
|
-
importRegExp: /(?:\[(.+?)\])(?:\(\s*(?:(?:<((
|
|
1269
|
-
regExp: /(?:\[([^[\]]*(?:\[[^[\]]*\][^[\]]*)*)\])(?:\(\s*(?:(?:<((
|
|
1277
|
+
importRegExp: /(?:\[(.+?)\])(?:\(\s*(?:(?:<((?:\\[^\n\r]|[^<>\n\r\\])*)>|((?!<)(?:\\[^\s]|\\(?=\s)|\((?:\\[^\s]|[^\s()\\]|\((?:\\[^\s]|[^\s()\\]|\((?:\\[^\s]|[^\s()\\])*\))*\))*\)|[^\s()\\])+))(?:\s+(?:"((?:\\[\s\S]|[^"\\])*)"|'((?:\\[\s\S]|[^'\\])*)'|\(((?:\\[\s\S]|[^()\\])*)\)))?\s*)?\))/,
|
|
1278
|
+
regExp: /(?:\[([^[\]]*(?:\[[^[\]]*\][^[\]]*)*)\])(?:\(\s*(?:(?:<((?:\\[^\n\r]|[^<>\n\r\\])*)>|((?!<)(?:\\[^\s]|\\(?=\s)|\((?:\\[^\s]|[^\s()\\]|\((?:\\[^\s]|[^\s()\\]|\((?:\\[^\s]|[^\s()\\])*\))*\))*\)|[^\s()\\])+))(?:\s+(?:"((?:\\[\s\S]|[^"\\])*)"|'((?:\\[\s\S]|[^'\\])*)'|\(((?:\\[\s\S]|[^()\\])*)\)))?\s*)?\))$/,
|
|
1270
1279
|
replace: (textNode, match) => {
|
|
1271
1280
|
// https://spec.commonmark.org/0.31.2/#inline-link
|
|
1272
1281
|
const source = match.input || '';
|
|
@@ -1442,7 +1451,17 @@ function createSelectionMarkdownExport(transformers, shouldPreserveNewLines = fa
|
|
|
1442
1451
|
const textFormatTransformers = byType.textFormat.filter(transformer => transformer.format.length === 1).sort((a, b) => {
|
|
1443
1452
|
return Number(a.format.includes('code')) - Number(b.format.includes('code'));
|
|
1444
1453
|
});
|
|
1445
|
-
return
|
|
1454
|
+
return exportedSelection => {
|
|
1455
|
+
// Every node asks whether it is selected, which reads the selection's
|
|
1456
|
+
// nodes. A read-only selection doesn't cache them, so this works on a
|
|
1457
|
+
// copy that does, instead of recomputing them for every node.
|
|
1458
|
+
// Its direction is cached too, since slicing a node asks for it.
|
|
1459
|
+
const nodes = exportedSelection.getNodes();
|
|
1460
|
+
const selection = exportedSelection.clone();
|
|
1461
|
+
selection.setCachedNodes(nodes);
|
|
1462
|
+
if ($isRangeSelection(selection)) {
|
|
1463
|
+
selection._cachedIsBackward = exportedSelection.isBackward();
|
|
1464
|
+
}
|
|
1446
1465
|
const output = [];
|
|
1447
1466
|
// The separator depends on the previously *emitted* block, not on the
|
|
1448
1467
|
// previous root child: unselected children produce no output, so keying
|
|
@@ -1523,10 +1542,7 @@ function $exportChildrenForSelection(node, selection, textFormatTransformers, te
|
|
|
1523
1542
|
if (!transformer.export) {
|
|
1524
1543
|
continue;
|
|
1525
1544
|
}
|
|
1526
|
-
const result = transformer.export(child, parentNode => $exportChildrenForSelection(parentNode, selection, textFormatTransformers, textMatchTransformers, shouldPreserveNewLines, unclosedTags, [...unclosableTags, ...unclosedTags]).markdown, (textNode,
|
|
1527
|
-
const slicedNode = $sliceSelectedTextNodeContent(selection, textNode, 'clone');
|
|
1528
|
-
return exportTextFormat(textNode, slicedNode.getTextContent(), textFormatTransformers, unclosedTags, unclosableTags, shouldPreserveNewLines);
|
|
1529
|
-
});
|
|
1545
|
+
const result = transformer.export(child, parentNode => $exportChildrenForSelection(parentNode, selection, textFormatTransformers, textMatchTransformers, shouldPreserveNewLines, unclosedTags, [...unclosableTags, ...unclosedTags]).markdown, textNode => $exportTextFormat(textNode, $exportedText(textNode, selection), textFormatTransformers, unclosedTags, unclosableTags, shouldPreserveNewLines, selection));
|
|
1530
1546
|
if (result != null) {
|
|
1531
1547
|
// Check extractWithChild if this node wasn't directly selected
|
|
1532
1548
|
if (!childIncluded && $isElementNode(child) && child.getChildren().some(c => c.isSelected(selection)) && child.extractWithChild(child, selection, 'html')) {
|
|
@@ -1546,8 +1562,7 @@ function $exportChildrenForSelection(node, selection, textFormatTransformers, te
|
|
|
1546
1562
|
}
|
|
1547
1563
|
} else if ($isTextNode(child)) {
|
|
1548
1564
|
if (childIncluded) {
|
|
1549
|
-
|
|
1550
|
-
output.push(exportTextFormat(child, target.getTextContent(), textFormatTransformers, unclosedTags, unclosableTags, shouldPreserveNewLines));
|
|
1565
|
+
output.push($exportTextFormat(child, $exportedText(child, selection), textFormatTransformers, unclosedTags, unclosableTags, shouldPreserveNewLines, selection));
|
|
1551
1566
|
anyChildIncluded = true;
|
|
1552
1567
|
}
|
|
1553
1568
|
} else if ($isElementNode(child)) {
|
|
@@ -1612,7 +1627,7 @@ function $exportChildren(node, textTransformersIndex, textMatchTransformers, unc
|
|
|
1612
1627
|
// E.g. **text [text**](https://lexical.io)
|
|
1613
1628
|
// is invalid markdown, as the closing ** is inside the link.
|
|
1614
1629
|
//
|
|
1615
|
-
[...unclosableTags, ...unclosedTags], shouldPreserveNewLines), (textNode, textContent) => exportTextFormat(textNode, textContent, textTransformersIndex, unclosedTags, unclosableTags, shouldPreserveNewLines));
|
|
1630
|
+
[...unclosableTags, ...unclosedTags], shouldPreserveNewLines), (textNode, textContent) => $exportTextFormat(textNode, textContent, textTransformersIndex, unclosedTags, unclosableTags, shouldPreserveNewLines, null));
|
|
1616
1631
|
if (result != null) {
|
|
1617
1632
|
output.push(result);
|
|
1618
1633
|
continue mainLoop;
|
|
@@ -1621,7 +1636,7 @@ function $exportChildren(node, textTransformersIndex, textMatchTransformers, unc
|
|
|
1621
1636
|
if ($isLineBreakNode(child)) {
|
|
1622
1637
|
output.push($exportLineBreak(child));
|
|
1623
1638
|
} else if ($isTextNode(child)) {
|
|
1624
|
-
output.push(exportTextFormat(child, child.getTextContent(), textTransformersIndex, unclosedTags, unclosableTags, shouldPreserveNewLines));
|
|
1639
|
+
output.push($exportTextFormat(child, child.getTextContent(), textTransformersIndex, unclosedTags, unclosableTags, shouldPreserveNewLines, null));
|
|
1625
1640
|
} else if ($isElementNode(child)) {
|
|
1626
1641
|
// empty paragraph returns ""
|
|
1627
1642
|
output.push($exportChildren(child, textTransformersIndex, textMatchTransformers, unclosedTags, unclosableTags, shouldPreserveNewLines));
|
|
@@ -1634,14 +1649,14 @@ function $exportChildren(node, textTransformersIndex, textMatchTransformers, unc
|
|
|
1634
1649
|
function $exportLineBreak(node) {
|
|
1635
1650
|
return $getState(node, hardLineBreakState) + '\n';
|
|
1636
1651
|
}
|
|
1637
|
-
function exportTextFormat(node, textContent, textTransformers,
|
|
1652
|
+
function $exportTextFormat(node, textContent, textTransformers,
|
|
1638
1653
|
// unclosed tags include the markdown tags that haven't been closed yet, and their associated formats
|
|
1639
|
-
unclosedTags, unclosableTags, shouldPreserveNewLines
|
|
1654
|
+
unclosedTags, unclosableTags, shouldPreserveNewLines,
|
|
1655
|
+
// the selection being exported, which ends the text a tag can extend over
|
|
1656
|
+
selection) {
|
|
1640
1657
|
// This function handles the case of a string looking like this: " foo "
|
|
1641
1658
|
// Where it would be invalid markdown to generate: "** foo **"
|
|
1642
|
-
//
|
|
1643
|
-
// Otherwise, we escape leading and trailing whitespaces to their corresponding code points,
|
|
1644
|
-
// ensuring the returned string maintains its original formatting, e.g., "**   foo   **".
|
|
1659
|
+
// so the tags go inside the whitespace instead: " **foo** ".
|
|
1645
1660
|
|
|
1646
1661
|
const isCode = node.hasFormat('code');
|
|
1647
1662
|
let output = textContent;
|
|
@@ -1652,30 +1667,7 @@ unclosedTags, unclosableTags, shouldPreserveNewLines = false) {
|
|
|
1652
1667
|
// Guard ambiguous '<' and '&' at node ends for constructs split across nodes.
|
|
1653
1668
|
output = shouldPreserveNewLines ? output.replace(/([*_`~])/g, '\\$1') : output.replace(/([[\]*_`~\\]|<(?=\S|$)|&(?=#|$))/g, character => /[*_`~\\]/.test(character) ? `\\${character}` : `&#${character.charCodeAt(0)};`);
|
|
1654
1669
|
}
|
|
1655
|
-
|
|
1656
|
-
let trimmedOutput;
|
|
1657
|
-
let trailingSpace;
|
|
1658
|
-
let isWhitespaceOnly;
|
|
1659
|
-
if (isCode) {
|
|
1660
|
-
// Inline code is an atomic literal span with a content-derived fence, so
|
|
1661
|
-
// its whitespace stays inside the fence and other formats wrap around it.
|
|
1662
|
-
const {
|
|
1663
|
-
fence,
|
|
1664
|
-
padded
|
|
1665
|
-
} = getCodeSpanDelimiter(textContent);
|
|
1666
|
-
leadingSpace = '';
|
|
1667
|
-
trailingSpace = '';
|
|
1668
|
-
trimmedOutput = fence + padded + fence;
|
|
1669
|
-
isWhitespaceOnly = false;
|
|
1670
|
-
} else {
|
|
1671
|
-
// Extract leading and trailing whitespaces.
|
|
1672
|
-
// CommonMark flanking rules require formatting tags to be adjacent to non-whitespace characters.
|
|
1673
|
-
const match = output.match(/^(\s*)(.*?)(\s*)$/s) || ['', '', output, ''];
|
|
1674
|
-
leadingSpace = match[1];
|
|
1675
|
-
trimmedOutput = match[2];
|
|
1676
|
-
trailingSpace = match[3];
|
|
1677
|
-
isWhitespaceOnly = trimmedOutput === '';
|
|
1678
|
-
}
|
|
1670
|
+
const holdsTag = canHoldTag(textContent);
|
|
1679
1671
|
|
|
1680
1672
|
// the opening tags to be added to the result
|
|
1681
1673
|
let openingTags = '';
|
|
@@ -1683,31 +1675,27 @@ unclosedTags, unclosableTags, shouldPreserveNewLines = false) {
|
|
|
1683
1675
|
let closingTagsBefore = '';
|
|
1684
1676
|
let closingTagsAfter = '';
|
|
1685
1677
|
const prevNode = getTextSibling(node, true);
|
|
1686
|
-
const nextNode = getTextSibling(node, false);
|
|
1687
1678
|
const applied = new Set();
|
|
1688
1679
|
for (const transformer of textTransformers) {
|
|
1689
1680
|
const format = transformer.format[0];
|
|
1690
1681
|
const tag = transformer.tag;
|
|
1691
1682
|
|
|
1692
|
-
// Inline code uses a content-derived fence handled
|
|
1683
|
+
// Inline code uses a content-derived fence handled below, not a static tag.
|
|
1693
1684
|
if (format === 'code') {
|
|
1694
1685
|
continue;
|
|
1695
1686
|
}
|
|
1696
1687
|
|
|
1697
1688
|
// dedup applied formats
|
|
1698
|
-
|
|
1699
|
-
// exported may be a selection slice of it. When the slice is entirely
|
|
1700
|
-
// whitespace the tags are dropped by the early return below, so
|
|
1701
|
-
// registering them here would leave an unclosed tag for a later node to
|
|
1702
|
-
// close. In the full-document path `checkHasFormat` already rejects
|
|
1703
|
-
// whitespace-only nodes, so this guard only affects sliced content.
|
|
1704
|
-
if (!isWhitespaceOnly && checkHasFormat(node, format) && !applied.has(format)) {
|
|
1689
|
+
if (holdsTag && node.hasFormat(format) && !applied.has(format)) {
|
|
1705
1690
|
applied.add(format);
|
|
1706
1691
|
|
|
1707
1692
|
// append the tag to openingTags, if it's not applied to the previous nodes,
|
|
1708
|
-
// or the nodes before that (which would result in an unclosed tag)
|
|
1709
|
-
|
|
1693
|
+
// or the nodes before that (which would result in an unclosed tag).
|
|
1694
|
+
// A whitespace-only previous node with the format keeps the tag open
|
|
1695
|
+
// without emitting it, so it counts as applied here.
|
|
1696
|
+
if (!hasFormat(prevNode, format) || !unclosedTags.find(element => element.tag === tag)) {
|
|
1710
1697
|
unclosedTags.push({
|
|
1698
|
+
answers: new Map(),
|
|
1711
1699
|
format,
|
|
1712
1700
|
tag
|
|
1713
1701
|
});
|
|
@@ -1719,10 +1707,8 @@ unclosedTags, unclosableTags, shouldPreserveNewLines = false) {
|
|
|
1719
1707
|
// close any tags in the same order they were applied, if necessary
|
|
1720
1708
|
for (let i = 0; i < unclosedTags.length; i++) {
|
|
1721
1709
|
const nodeHasFormat = hasFormat(node, unclosedTags[i].format);
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
// prevent adding closing tag if next sibling will do it
|
|
1725
|
-
if (nodeHasFormat && nextNodeHasFormat) {
|
|
1710
|
+
// prevent adding closing tag if later text with the format will do it
|
|
1711
|
+
if (nodeHasFormat && $continuesTag(node, unclosedTags[i], selection)) {
|
|
1726
1712
|
continue;
|
|
1727
1713
|
}
|
|
1728
1714
|
const unhandledUnclosedTags = [...unclosedTags]; // Shallow copy to avoid modifying the original array
|
|
@@ -1732,7 +1718,7 @@ unclosedTags, unclosableTags, shouldPreserveNewLines = false) {
|
|
|
1732
1718
|
|
|
1733
1719
|
// If tag is unclosable, don't close it and leave it in the original array,
|
|
1734
1720
|
// So that it can be closed when it's no longer unclosable
|
|
1735
|
-
if (
|
|
1721
|
+
if (unclosedTag && unclosableTags.find(element => element.tag === unclosedTag.tag)) {
|
|
1736
1722
|
continue;
|
|
1737
1723
|
}
|
|
1738
1724
|
if (unclosedTag && typeof unclosedTag.tag === 'string') {
|
|
@@ -1740,7 +1726,7 @@ unclosedTags, unclosableTags, shouldPreserveNewLines = false) {
|
|
|
1740
1726
|
// Handles cases where the tag has not been closed before, e.g. if the previous node
|
|
1741
1727
|
// was a text match transformer that did not account for closing tags of the next node (e.g. a link)
|
|
1742
1728
|
closingTagsBefore += unclosedTag.tag;
|
|
1743
|
-
} else
|
|
1729
|
+
} else {
|
|
1744
1730
|
closingTagsAfter += unclosedTag.tag;
|
|
1745
1731
|
}
|
|
1746
1732
|
}
|
|
@@ -1749,13 +1735,28 @@ unclosedTags, unclosableTags, shouldPreserveNewLines = false) {
|
|
|
1749
1735
|
}
|
|
1750
1736
|
break;
|
|
1751
1737
|
}
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1738
|
+
if (isCode && textContent !== '') {
|
|
1739
|
+
// Inline code is an atomic literal span with a content-derived fence, so
|
|
1740
|
+
// its whitespace stays inside the fence and other formats wrap around it.
|
|
1741
|
+
const {
|
|
1742
|
+
fence,
|
|
1743
|
+
padded
|
|
1744
|
+
} = getCodeSpanDelimiter(textContent);
|
|
1745
|
+
output = fence + padded + fence;
|
|
1746
|
+
} else if (!holdsTag) {
|
|
1747
|
+
// If the node is entirely whitespace, we don't apply opening/closing tags
|
|
1748
|
+
// around it, but it must still output any closing tags.
|
|
1749
|
+
return closingTagsBefore + closingTagsAfter + output;
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
// Flanking Compliance: CommonMark flanking rules require formatting tags to be
|
|
1753
|
+
// adjacent to non-whitespace characters, so openingTags and closingTagsAfter
|
|
1754
|
+
// are placed INSIDE the whitespace boundaries!
|
|
1755
|
+
// (Trimming rather than a regex keeps this linear in long whitespace runs.)
|
|
1756
|
+
const trimmedStart = output.trimStart();
|
|
1757
|
+
const trimmedOutput = trimmedStart.trimEnd();
|
|
1758
|
+
const leadingSpace = output.slice(0, output.length - trimmedStart.length);
|
|
1759
|
+
const trailingSpace = trimmedStart.slice(trimmedOutput.length);
|
|
1759
1760
|
return closingTagsBefore + leadingSpace + openingTags + trimmedOutput + closingTagsAfter + trailingSpace;
|
|
1760
1761
|
}
|
|
1761
1762
|
function getTextSibling(node, backward) {
|
|
@@ -1765,20 +1766,66 @@ function getTextSibling(node, backward) {
|
|
|
1765
1766
|
}
|
|
1766
1767
|
return null;
|
|
1767
1768
|
}
|
|
1769
|
+
|
|
1770
|
+
/**
|
|
1771
|
+
* Whether `tag` carries on past `node`, which has its format, to exported
|
|
1772
|
+
* text that can hold it. Whitespace-only siblings cannot (the tag must close
|
|
1773
|
+
* before the space), so they are looked past while they keep the format.
|
|
1774
|
+
* Text outside the exported selection does not count. Every whitespace node
|
|
1775
|
+
* the walk passes over shares its answer, so that is remembered on the tag
|
|
1776
|
+
* and each run is walked once, whatever order its nodes are asked in.
|
|
1777
|
+
*/
|
|
1778
|
+
function $continuesTag(node, tag, selection) {
|
|
1779
|
+
const {
|
|
1780
|
+
answers
|
|
1781
|
+
} = tag;
|
|
1782
|
+
const known = answers.get(node.getKey());
|
|
1783
|
+
if (known !== undefined) {
|
|
1784
|
+
return known;
|
|
1785
|
+
}
|
|
1786
|
+
const passed = [];
|
|
1787
|
+
let next = getTextSibling(node, false);
|
|
1788
|
+
let result = false;
|
|
1789
|
+
while (next && next.hasFormat(tag.format) && (!selection || next.isSelected(selection))) {
|
|
1790
|
+
const text = $exportedText(next, selection);
|
|
1791
|
+
if (canHoldTag(text)) {
|
|
1792
|
+
result = true;
|
|
1793
|
+
break;
|
|
1794
|
+
}
|
|
1795
|
+
// Markdown import matches a tag within one line.
|
|
1796
|
+
if (text.includes('\n')) {
|
|
1797
|
+
break;
|
|
1798
|
+
}
|
|
1799
|
+
// A whitespace node already answered for shares the answer.
|
|
1800
|
+
const passedAnswer = answers.get(next.getKey());
|
|
1801
|
+
if (passedAnswer !== undefined) {
|
|
1802
|
+
result = passedAnswer;
|
|
1803
|
+
break;
|
|
1804
|
+
}
|
|
1805
|
+
passed.push(next);
|
|
1806
|
+
next = getTextSibling(next, false);
|
|
1807
|
+
}
|
|
1808
|
+
answers.set(node.getKey(), result);
|
|
1809
|
+
for (const passedNode of passed) {
|
|
1810
|
+
answers.set(passedNode.getKey(), result);
|
|
1811
|
+
}
|
|
1812
|
+
return result;
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
/** The text of `node` that the export emits: its selected slice, if any. */
|
|
1816
|
+
function $exportedText(node, selection) {
|
|
1817
|
+
return selection ? $sliceSelectedTextNodeContent(selection, node, 'clone').getTextContent() : node.getTextContent();
|
|
1818
|
+
}
|
|
1768
1819
|
function hasFormat(node, format) {
|
|
1769
1820
|
return $isTextNode(node) && node.hasFormat(format);
|
|
1770
1821
|
}
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
if (n && /^\s*$/.test(n.getTextContent())) {
|
|
1779
|
-
return false;
|
|
1780
|
-
}
|
|
1781
|
-
return true;
|
|
1822
|
+
|
|
1823
|
+
/**
|
|
1824
|
+
* Whether exported text can carry a format's tag: CommonMark flanking rules
|
|
1825
|
+
* keep tags off whitespace.
|
|
1826
|
+
*/
|
|
1827
|
+
function canHoldTag(text) {
|
|
1828
|
+
return /\S/.test(text);
|
|
1782
1829
|
}
|
|
1783
1830
|
|
|
1784
1831
|
/**
|
|
@@ -1891,7 +1938,7 @@ function importTextTransformers(textNode, textFormatTransformersIndex, textMatch
|
|
|
1891
1938
|
// or links). A code span must never be partially consumed by a text
|
|
1892
1939
|
// match, so prefer the code format unless the text match fully wraps it
|
|
1893
1940
|
// (in which case the code span is part of the match's raw content).
|
|
1894
|
-
// https://github.com/
|
|
1941
|
+
// https://github.com/meta/lexical/issues/8687
|
|
1895
1942
|
if (foundTextMatch.startIndex <= foundTextFormat.startIndex && foundTextMatch.endIndex >= foundTextFormat.endIndex) {
|
|
1896
1943
|
// foundTextMatch wraps the code span - apply foundTextMatch
|
|
1897
1944
|
foundTextFormat = null;
|
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import{$isParagraphNode as t,$isTextNode as e,$setState as n,$createTextNode as o,$getState as r,$findMatchingParent as s,$createLineBreakNode as l,createState as i,$isLineBreakNode as c,$getRoot as f,$isElementNode as u,$isDecoratorNode as a,$isTabNode as d,$createTabNode as g,$createParagraphNode as h,mergeRegister as p,COLLABORATION_TAG as x,HISTORIC_TAG as m,COMPOSITION_END_TAG as C,$getSelection as I,$isRangeSelection as T,$addUpdateTag as v,HISTORY_PUSH_TAG as $,KEY_ENTER_COMMAND as y,COMMAND_PRIORITY_LOW as E,$isRootOrShadowRoot as S,$createRangeSelection as b,$setSelection as w,TEXT_TYPE_TO_FORMAT as N,ArtificialNode__DO_NOT_USE as k}from"lexical";import{$sliceSelectedTextNodeContent as F}from"@lexical/selection";import{CodeNode as O,$createCodeNode as P,$isCodeNode as M}from"@lexical/code-core";import{LinkNode as R,$isLinkNode as _,$createLinkNode as B,$isAutoLinkNode as L}from"@lexical/link";import{ListNode as A,ListItemNode as j,$isListNode as z,$createListItemNode as W,$createListNode as U,$isListItemNode as D}from"@lexical/list";import{HeadingNode as X,QuoteNode as Z,$isHeadingNode as H,$isQuoteNode as K,$createQuoteNode as q,$createHeadingNode as G}from"@lexical/rich-text";function J(t,e){const n={};for(const o of t){const t=e(o);t&&(n[t]?n[t].push(o):n[t]=[o])}return n}function Q(t){const e=J(t,t=>t.type);return{element:e.element||[],multilineElement:e["multiline-element"]||[],textFormat:e["text-format"]||[],textMatch:e["text-match"]||[]}}const V=/[!-/:-@[-`{-~\s]/,Y=/\s/,tt=/[!"#$%&'()*+,\-./:;<=>?@[\]^_`{|}~]/,et=/^\s{0,3}$/;function nt(n){if(!t(n))return!1;const o=n.getFirstChild();return null==o||1===n.getChildrenSize()&&e(o)&&et.test(o.getTextContent())}function ot(t){return t.replace(/\\([!-/:-@[-`{-~])|&#(?:(\d{1,7})|[xX]([\da-fA-F]{1,6}));/g,(t,e,n,o)=>e??function(t,e){const n=void 0!==t?Number(t):parseInt(e,16);return 0===n||n>=55296&&n<=57343||n>1114111?"\ufffd":String.fromCodePoint(n)}(n,o))}function rt(t,e){let n=0;for(let o=e-1;o>=0&&"\\"===t[o];o--)n++;return n%2==1}function st(t){const e=e=>{let n=0;for(let o=e-1;o>=0&&"\\"===t[o];o--)n++;return n%2==1},n=[];let o=0;for(;o<t.length;)if("`"===t[o]){let e=1;for(;o+e<t.length&&"`"===t[o+e];)e++;n.push({index:o,length:e}),o+=e}else o++;const r=[];let s=0;for(;s<n.length;){const o=n[s];if(e(o.index)){s++;continue}let l=-1;for(let t=s+1;t<n.length;t++)if(n[t].length===o.length){l=t;break}if(-1===l){s++;continue}const i=n[l];let c=t.slice(o.index+o.length,i.index);c.length>=2&&c.startsWith(" ")&&c.endsWith(" ")&&/[^ ]/.test(c)&&(c=c.slice(1,-1)),r.push({content:c,endIndex:i.index+i.length,startIndex:o.index}),s=l+1}return r}function lt(t,e,n,o,r){if(!it(e,n,o,r))return!1;if("*"===t)return!0;if("_"===t){if(!it(e,n,o,!r))return!0;const t=r?e[n-1]:e[n+o];return void 0!==t&&tt.test(t)}return!0}function it(t,e,n,o){const r=t[e-1],s=t[e+n],[l,i]=o?[s,r]:[r,s];return void 0!==l&&!Y.test(l)&&(!tt.test(l)||void 0===i||Y.test(i)||tt.test(i))}const ct=/^(\s*)(\d{1,})\.\s/,ft=/^(\s*)[-*+]\s/,ut=/^(\s*)(?:[-*+]\s)?\s?(\[(\s|x)?\])\s/i,at=/^(#{1,6})\s/,dt=/^>\s/,gt=/^([ \t]*`{3,})([\w-]+)?[ \t]?/,ht=/^[ \t]*`{3,}$/,pt=/^[ \t]*```[^`]+(?:(?:`{1,2}|`{4,})[^`]+)*```(?:[^`]|$)/,xt=/^(?:\|)(.+)(?:\|)\s?$/;function mt(t){if("|"!==t[0])return!1;const{length:e}=t;let n=1,o=0;for(;n<e;){let e=n;for(" "===t[e]&&e++,":"===t[e]&&e++;"-"===t[e];)e++;if(":"===t[e]&&e++," "===t[e]&&e++,"|"!==t[e])break;o++,n=e+1}return o>0&&(n===e||n===e-1&&/\s/.test(t[n]))}const Ct=/^<[a-z_][\w-]*(?:\s[^<>]*)?\/?>/i,It=/^<\/[a-z_][\w-]*\s*>/i,Tt=t=>new RegExp(`(?:${t.source})$`,t.flags),vt=/* @__PURE__ */i("mdListMarker",{parse:t=>"string"==typeof t&&/^[-*+]$/.test(t)?t:"-",resetOnCopyNode:!0}),$t=/* @__PURE__ */i("mdCodeFence",{parse:t=>"string"==typeof t&&/^`{3,}$/.test(t)?t:"```",resetOnCopyNode:!0}),yt=/* @__PURE__ */i("mdCodeMeta",{parse:t=>"string"==typeof t?t:"",resetOnCopyNode:!0}),Et=/* @__PURE__ */i("mdHardLineBreak",{parse:t=>"string"==typeof t&&/^(\\| {2,})$/.test(t)?t:"",resetOnCopyNode:!0});function St(t){if(t.endsWith("\\")){let e=0;for(let n=t.length-1;n>=0&&"\\"===t[n];n--)e++;return e%2==1?[t.slice(0,-1),"\\"]:null}const e=t.match(/^(.*?\S)( {2,})$/);return e?[e[1],e[2]]:null}function bt(t){const o=l(),r=function(t){const n=t.getChildren(),o=n.length-1,r=n[o];if(!e(r))return null;const s=r.getTextContent(),l=St(s);if(null!==l){const[t,e]=l;return r.setTextContent(t),e}return/^ {2,}$/.test(s)&&function(t,e){for(let n=e-1;n>=0;n--){if(c(t[n]))return!1;if(/\S/.test(t[n].getTextContent()))return!0}return!1}(n,o)?(r.setTextContent(""),s):null}(t);return null!==r&&n(o,Et,r),o}function wt(t){return K(t)}function Nt(t,e){let n=0;for(;n<e&&(" "===t[n]||"\t"===t[n]);)n++;return t.slice(n)}function kt(t,e){const o=t.getLastChild();e&&M(o)&&n(o,yt,e)}const Ft=t=>(e,n,o,r)=>{const s=t(o);s.append(...n),e.replace(s),r||s.select(0,0)};function Ot(t){let e=0;for(const n of t)e+="\t"===n?4-e%4:1;return e}let Pt=null,Mt=!1;const Rt=t=>(e,o,r,s)=>{if(H(e)||!s&&wt(e))return!1;const l=e.getPreviousSibling(),i=e.getNextSibling(),c=W("check"===t?/^x$/i.test(r[3]||""):void 0),f=r[0].trim()[0],u="bullet"!==t&&"check"!==t||f!==vt.parse(f)?void 0:f,a=Pt;let d=l;if(null!==a){if(Mt)for(;null!==d&&nt(d);)d=d.getPreviousSibling();z(d)||(a.length=0)}const g=null===a||0===a.length?function(t){const e=t.match(/\t/g),n=t.match(/ /g);let o=0;return e&&(o+=e.length),n&&(o+=Math.floor(n.length/4)),o}(r[1]):function(t,e){const n=Ot(e);for(let e=t.length-1;e>=0;e--)if(n>=t[e])return e+1;return 0}(a,r[1]);if(z(i)&&i.getListType()===t){const n=i.getFirstChild();null!==n?n.insertBefore(c):i.append(c),"number"===t&&0===g&&i.setStart(Number(r[2])),e.remove()}else if(z(d)&&(d.getListType()===t||g>0))d.append(c),e.remove();else{const n=U(t,"number"===t?Number(r[2]):void 0);n.append(c),e.replace(n)}c.append(...o),s||c.select(0,0),g&&(c.setIndent(g),function(t,e,n){const o=t.getParent();if(!z(o)||o.getListType()===e)return;const r=o.getParent();if(!D(r))return;const s=U(e,"number"===e?Number(n[2]):void 0),l=null===t.getPreviousSibling();s.append(t);const i=W();i.append(s),l?r.insertBefore(i):r.insertAfter(i),0===o.getChildrenSize()&&r.remove()}(c,t,r));const h=c.getParent();u&&z(h)&&n(h,vt,u),null!==a&&function(t,e,n,o){for(let n=t.length;n<e;n++)t[n]=4*(n+1);t.length=e,t[e]=function(t,e){let n=t[0];if("check"===e){const e=n.slice(t[1].length).match(/^[-*+]\s/);e&&(n=t[1]+e[0])}return Math.min(Ot(n),Ot(t[1])+4)}(n,o)}(a,g,r,t)},_t=(t,e,n,o)=>{const s=[],l=t.getChildren();let i=0;for(const c of l)if(D(c)){if(1===c.getChildrenSize()){const t=c.getFirstChild();if(z(t)){const r=_t(t,e,n+1,o);r&&s.push(r);continue}}if(o&&!c.getChildren().some(t=>t.isSelected(o)))continue;const l=" ".repeat(4*n),f=t.getListType(),u=r(t,vt),a="number"===f?`${t.getStart()+i}. `:"check"===f?`${u} [${c.getChecked()?"x":" "}] `:u+" ";let d=e(c);"number"!==f&&(d=d.replace(/^(\s{0,3}\d+)(\.\s)/,"$1\\$2")),s.push(l+a+d),i++}return s.join("\n")},Bt=/* @__PURE__ */Ft(t=>{const e="h"+t[1].length;return G(e)}),Lt={dependencies:[X],export:(t,e)=>{if(!H(t))return null;const n=Number(t.getTag().slice(1));return"#".repeat(n)+" "+e(t)},regExp:at,replace:(t,e,n,o)=>!(!o&&wt(t))&&Bt(t,e,n,o),triggerOnEnter:!0,type:"element"},At={dependencies:[Z],export:(t,e)=>{if(!K(t))return null;const n=e(t).split("\n"),o=[];for(const t of n)o.push("> "+t);return o.join("\n")},regExp:dt,replace:(t,e,n,o)=>{if(o){const n=t.getPreviousSibling();if(K(n))return n.splice(n.getChildrenSize(),0,[bt(n),...e]),void t.remove()}const r=q();r.append(...e),t.replace(r),o||r.select(0,0)},triggerOnEnter:!0,type:"element"},jt={dependencies:[O],export:t=>{if(!M(t))return null;const e=t.getTextContent();let n=r(t,$t);if(e.indexOf(n)>-1){const t=e.match(/`{3,}/g);if(t){const e=Math.max(...t.map(t=>t.length));n="`".repeat(e+1)}}const o=t.getLanguage()||"",s=o?r(t,yt):"";return n+o+(s?" "+s:"")+(e?"\n"+e:"")+"\n"+n},handleImportAfterStartMatch:({lines:t,rootNode:e,startLineIndex:n,startMatch:o})=>{const r=o[1],s=r.trim().length,l=t[n],i=o.index+r.length,c=l.slice(i),f=new RegExp(`\`{${s},}$`);if(f.test(c)){const t=c.match(f),r=c.slice(0,c.lastIndexOf(t[0])),s=[...o];return s[2]="",jt.replace(e,null,s,t,[r],!0),[!0,n]}const u=new RegExp(`^[ \\t]*\`{${s},}$`);for(let r=n+1;r<t.length;r++){const s=t[r];if(u.test(s)){const i=s.match(u),c=t.slice(n+1,r),f=o[2]?l.slice(o[0].length).trim():"";return c.unshift(f?"":l.slice(o[0].length)),jt.replace(e,null,o,i,c,!0),kt(e,f),[!0,r]}}const a=t.slice(n+1);return a.unshift(l.slice(o[0].length)),jt.replace(e,null,o,null,a,!0),[!0,t.length-1]},regExpEnd:{optional:!0,regExp:ht},regExpStart:gt,replace:(t,e,r,s,l,i)=>{let c,f;const u=r[1]?r[1].trim():"```",a=r[2]||void 0,d=r[1]?r[1].length-r[1].trimStart().length:0;if(!e&&l){if(1===l.length)s?(c=P(a),f=Nt(l[0],d)):(c=P(a),f=l[0].startsWith(" ")?l[0].slice(1):l[0]);else{for(c=P(a),l.length>0&&(0===l[0].trim().length?l.shift():l[0].startsWith(" ")&&(l[0]=l[0].slice(1)));l.length>0&&!l[l.length-1].length;)l.pop();f=l.map(t=>Nt(t,d)).join("\n")}n(c,$t,u);const e=o(f);c.append(e),t.append(c)}else if(e){if(!i&&wt(t))return!1;Ft(t=>P(t?t[2]:void 0))(t,e,r,i)}},type:"multiline-element"},zt={dependencies:[A,j],export:(t,e,n)=>z(t)?_t(t,e,0,n):null,regExp:ft,replace:/* @__PURE__ */Rt("bullet"),triggerOnEnter:!0,type:"element"},Wt={dependencies:[A,j],export:(t,e,n)=>z(t)?_t(t,e,0,n):null,regExp:ut,replace:/* @__PURE__ */Rt("check"),triggerOnEnter:!0,type:"element"},Ut={dependencies:[A,j],export:(t,e,n)=>z(t)?_t(t,e,0,n):null,regExp:ct,replace:/* @__PURE__ */Rt("number"),triggerOnEnter:!0,type:"element"},Dt={format:["code"],tag:"`",type:"text-format"},Xt={format:["highlight"],tag:"==",type:"text-format"},Zt={format:["bold","italic"],tag:"***",type:"text-format"},Ht={format:["bold","italic"],intraword:!1,tag:"___",type:"text-format"},Kt={format:["bold"],tag:"**",type:"text-format"},qt={format:["bold"],intraword:!1,tag:"__",type:"text-format"},Gt={format:["strikethrough"],tag:"~~",type:"text-format"},Jt={format:["italic"],tag:"*",type:"text-format"},Qt={format:["italic"],intraword:!1,tag:"_",type:"text-format"};function Vt(t){return t.replace(/&(?=#\d+;|#[Xx][\dA-Fa-f]+;|[A-Za-z][\dA-Za-z]*;)/g,"&")}const Yt={dependencies:[R],export:(t,e,n)=>{if(!_(t)||L(t))return null;const o=e(t);let r=t.getTitle();null!=r&&(r=Vt(r).replace(/([\\"])/g,"\\$1"));const s=t.getURL(),l=Vt(s),i=""===s||/\s/.test(s)?`<${l.replace(/([\\<>])/g,"\\$1").replace(/\r/g," ").replace(/\n/g," ")}>`:l.replace(/([\\()])/g,"\\$1").replace(/^</,"\\<");return r?`[${o}](${i} "${r}")`:`[${o}](${i})`},importRegExp:/(?:\[(.+?)\])(?:\(\s*(?:(?:<((?:\\.|[^<>\n\\])*)>|((?!<)(?:\\[^\s]|\\(?=\s)|\((?:\\[^\s]|[^\s()\\]|\((?:\\[^\s]|[^\s()\\]|\((?:\\[^\s]|[^\s()\\])*\))*\))*\)|[^\s()\\])+))(?:\s+(?:"((?:[^"]*\\")*[^"]*)"|'((?:[^']*\\')*[^']*)'|\(((?:\\.|[^()\\])*)\)))?\s*)?\))/,regExp:/(?:\[([^[\]]*(?:\[[^[\]]*\][^[\]]*)*)\])(?:\(\s*(?:(?:<((?:\\.|[^<>\n\\])*)>|((?!<)(?:\\[^\s]|\\(?=\s)|\((?:\\[^\s]|[^\s()\\]|\((?:\\[^\s]|[^\s()\\]|\((?:\\[^\s]|[^\s()\\])*\))*\))*\)|[^\s()\\])+))(?:\s+(?:"((?:[^"]*\\")*[^"]*)"|'((?:[^']*\\')*[^']*)'|\(((?:\\.|[^()\\])*)\)))?\s*)?\))$/,replace:(t,e)=>{const n=e.input||"",r=e.index||0;if(s(t,_)||rt(n,r)||rt(n,r+e[1].length+1))return;const[,l,i,c,f,u,a]=e,d=ot(i??c??""),g=f??u??a,h=null!=g?ot(g):void 0,p=B(d,{title:h}),x=function(t){const e=st(t);let n=0;const o=t.replace(/\\.|[[\]]/g,(t,o)=>{for(;n<e.length&&o>=e[n].endIndex;)n++;return n<e.length&&o>=e[n].startIndex||"\\"===t[0]?" ".repeat(t.length):t}),r=[];let s=!1;for(let t=0;t<o.length;t++){const e=o[t];"["===e?r.push(t):"]"===e&&void 0===r.pop()&&(s=!0)}return r.pop()??(s?null:-1)}(l);if(null===x)return;let m=l,C="";-1!==x&&(C="["+function(t){let e="",n=0;for(const{startIndex:o,endIndex:r}of st(t))e+=ot(t.slice(n,o))+t.slice(o,r),n=r;return e+ot(t.slice(n))}(l.slice(0,x)),m=l.slice(x+1));const I=t.getFormat(),T=o(m);return T.setFormat(I),p.append(T),t.replace(p),C&&p.insertBefore(o(C).setFormat(I)),T},trigger:")",type:"text-match"},te=[Lt,At,zt,Ut],ee=[jt],ne=[Dt,Zt,Ht,Kt,qt,Xt,Jt,Qt,Gt],oe=[Yt];function re(...t){return t.flat()}const se=/* @__PURE__ */re(te,ee,ne,oe);function le(t,e=!1){const n=t.split("\n");let o=0;const r=[];for(let t=0;t<n.length;t++){const s=n[t],l=s.trimEnd(),i=r[r.length-1],c=t<n.length-1?St(s):null,f=void 0!==i&&null!==St(i);if(pt.test(l))r.push(l);else if(0===o){{const t=l.match(gt);if(t){o=t[1].trim().length,r.push(l);continue}}""===l||""===i||!i||at.test(i)||at.test(l)||dt.test(l)||ct.test(l)||ft.test(l)||ut.test(l)||xt.test(l)||mt(l)||f||!e||Ct.test(l)||It.test(l)||Tt(It).test(i)||Tt(Ct).test(i)||ht.test(i)?r.push(!e&&""!==l||null!==c?s:l):r[r.length-1]=i+" "+(null===c?l:s).trimStart()}else{if(ht.test(l)&&l.trim().length>=o){o=0,r.push(l);continue}r.push(s)}}return r.join("\n")}function ie(t,e,n,o,r,s){let l=t.isSelected(e);for(const i of n){if(!i.export)continue;const n=i.export(t,t=>ce(t,e,o,r,s).markdown,e);if(null!=n)return!l&&u(t)&&ce(t,e,o,r,s).shouldInclude&&(l=!0),{markdown:n,shouldInclude:l}}if(u(t)){const n=ce(t,e,o,r,s);return{markdown:n.markdown,shouldInclude:l||n.shouldInclude}}return a(t)?{markdown:t.getTextContent(),shouldInclude:l}:{markdown:null,shouldInclude:l}}function ce(t,n,o,r,s,l,i){const f=[],d=t.getChildren();let g=!1;l||(l=[]),i||(i=[]);t:for(const t of d){let d=t.isSelected(n);for(const e of r){if(!e.export)continue;const c=e.export(t,t=>ce(t,n,o,r,s,l,[...i,...l]).markdown,(t,e)=>de(t,F(n,t,"clone").getTextContent(),o,l,i,s));if(null!=c){!d&&u(t)&&t.getChildren().some(t=>t.isSelected(n))&&t.extractWithChild(t,n,"html")&&(d=!0),d&&(f.push(c),g=!0);continue t}}if(c(t))d&&(f.push(ae(t)),g=!0);else if(e(t)){if(d){const e=F(n,t,"clone");f.push(de(t,e.getTextContent(),o,l,i,s)),g=!0}}else if(u(t)){const e=ce(t,n,o,r,s,l,i);!d&&e.shouldInclude&&t.extractWithChild(t,n,"html")&&(d=!0),(d||e.shouldInclude)&&(f.push(e.markdown),g=!0)}else a(t)&&d&&(f.push(t.getTextContent()),g=!0)}return{markdown:f.join(""),shouldInclude:g}}function fe(t,e,n,o,r){for(const s of e){if(!s.export)continue;const e=s.export(t,t=>ue(t,n,o,void 0,void 0,r));if(null!=e)return e}return u(t)?ue(t,n,o,void 0,void 0,r):a(t)?t.getTextContent():null}function ue(t,n,o,r,s,l=!1){const i=[],f=t.getChildren();r||(r=[]),s||(s=[]);t:for(const t of f){for(const e of o){if(!e.export)continue;const c=e.export(t,t=>ue(t,n,o,r,[...s,...r],l),(t,e)=>de(t,e,n,r,s,l));if(null!=c){i.push(c);continue t}}c(t)?i.push(ae(t)):e(t)?i.push(de(t,t.getTextContent(),n,r,s,l)):u(t)?i.push(ue(t,n,o,r,s,l)):a(t)&&i.push(t.getTextContent())}return i.join("")}function ae(t){return r(t,Et)+"\n"}function de(t,e,n,o,r,s=!1){const l=t.hasFormat("code");let i,c,f,u,a=e;if(l||(a=s?a.replace(/([*_`~])/g,"\\$1"):a.replace(/([[\]*_`~\\]|<(?=\S|$)|&(?=#|$))/g,t=>/[*_`~\\]/.test(t)?`\\${t}`:`&#${t.charCodeAt(0)};`)),l){const{fence:t,padded:n}=function(t){const e=t.match(/`+/g),n=e?Math.max(...e.map(t=>t.length)):0;return{fence:"`".repeat(n+1),padded:0===t.length||t.includes("`")||/^\s/.test(t)&&/\s$/.test(t)?` ${t} `:t}}(e);i="",f="",c=t+n+t,u=!1}else{const t=a.match(/^(\s*)(.*?)(\s*)$/s)||["","",a,""];i=t[1],c=t[2],f=t[3],u=""===c}let d="",g="",h="";const p=ge(t,!0),x=ge(t,!1),m=new Set;for(const e of n){const n=e.format[0],r=e.tag;"code"!==n&&(u||!pe(t,n)||m.has(n)||(m.add(n),pe(p,n)&&o.find(t=>t.tag===r)||(o.push({format:n,tag:r}),d+=r)))}for(let e=0;e<o.length;e++){const n=he(t,o[e].format),s=he(x,o[e].format);if(n&&s)continue;const l=[...o];for(;l.length>e;){const t=l.pop();r&&t&&r.find(e=>e.tag===t.tag)||(t&&"string"==typeof t.tag&&(n?s||(h+=t.tag):g+=t.tag),o.pop())}break}return u&&!t.hasFormat("code")?g+a:g+i+d+c+h+f}function ge(t,n){const o=n?t.getPreviousSibling():t.getNextSibling();return e(o)?o:null}function he(t,n){return e(t)&&t.hasFormat(n)}function pe(t,e){return!(!he(t,e)||"code"!==e&&t&&/^\s*$/.test(t.getTextContent()))}function xe(t,e){const n=new RegExp(e.source,e.flags.replace(/[gy]/g,"")+"g");let o;for(;null!==(o=n.exec(t));){if(!rt(t,o.index))return o;n.lastIndex=o.index+1}return null}function me(t){return e(t)&&!t.hasFormat("code")}function Ce(t,e,n){let o=function(t,e){const n=t.getTextContent(),o=e.transformersByTag["`"],r=[];let s=null;if(o){const t=st(n);for(const e of t)s||(s={content:e.content,endIndex:e.endIndex,startIndex:e.startIndex,tag:"`"}),r.push({end:e.endIndex,start:e.startIndex})}const l=function(t,e,n=[]){const o=[],r=new Set(Object.keys(e.transformersByTag).filter(t=>"`"!==t[0]).map(t=>t[0])),s=e=>{let n=0;for(let o=e-1;o>=0&&"\\"===t[o];o--)n++;return n%2==1},l=t=>n.some(e=>t>=e.start&&t<e.end);let i=0;for(;i<t.length;){const e=t[i];if(!r.has(e)||s(i)||l(i)){i++;continue}let n=1;for(;i+n<t.length&&t[i+n]===e;)n++;const c=lt(e,t,i,n,!0),f=lt(e,t,i,n,!1);(c||f)&&o.push({active:!0,canClose:f,canOpen:c,char:e,index:i,length:n}),i+=n}return o}(n,e,r),i=l.length>0?function(t,e,n){const o={};let r=0,s=null;for(;r<e.length;){const l=e[r];if(!l.active||!l.canClose||0===l.length){r++;continue}const i=`${l.char}${l.canOpen}${l.length%3}`,c=o[i]??-1;let f=!1;for(let o=r-1;o>c;o--){const i=e[o];if(!i.active||!i.canOpen||0===i.length||i.char!==l.char)continue;if((i.canClose||l.canOpen)&&(i.length+l.length)%3==0&&i.length%3!=0&&l.length%3!=0)continue;const c=Math.min(i.length,l.length),u=Object.keys(n.transformersByTag).filter(t=>t[0]===i.char&&t.length<=c).sort((t,e)=>e.length-t.length)[0];if(!u)continue;f=!0;const a=u.length,d={content:t.slice(i.index+i.length,l.index),endIndex:l.index+a,startIndex:i.index+(i.length-a),tag:u};(!s||d.startIndex<s.startIndex||d.startIndex===s.startIndex&&d.endIndex>s.endIndex)&&(s=d);for(let t=o+1;t<r;t++)e[t].active=!1;i.length-=a,l.length-=a,i.active=i.length>0,l.length>0?l.index+=a:(l.active=!1,r++);break}f||(o[i]=r-1,l.canOpen||(l.active=!1),r++)}return s}(n,l,e):null;let c=null,f=null;if(s&&i?i.startIndex<=s.startIndex&&i.endIndex>=s.endIndex?(c=i,f=e.transformersByTag[i.tag]):(c=s,f=o):s?(c=s,f=o):i&&(c=i,f=e.transformersByTag[i.tag]),!c||!f)return null;const u=[n.slice(c.startIndex,c.endIndex),c.tag,c.content];return u.index=c.startIndex,u.input=n,{endIndex:c.endIndex,isCodeSpan:f===o,match:u,startIndex:c.startIndex,transformer:f}}(t,e),r=function(t,e){const n=t;let o,r,s,l;for(const t of e){if(!t.replace||!t.importRegExp)continue;const e=n.getTextContent(),i=void 0!==Yt.importRegExp&&t.importRegExp.source===Yt.importRegExp.source?xe(e,t.importRegExp):e.match(t.importRegExp);if(!i)continue;const c=i.index||0,f=t.getEndIndex?t.getEndIndex(n,i):c+i[0].length;!1!==f&&(void 0===o||void 0===r||c<o&&(f>r||f<=o))&&(o=c,r=f,s=t,l=i)}return void 0===o||void 0===r||void 0===s||void 0===l?null:{endIndex:r,match:l,startIndex:o,transformer:s}}(t,n);if(o&&r&&(o.isCodeSpan?r.startIndex<=o.startIndex&&r.endIndex>=o.endIndex?o=null:r=null:o.startIndex<=r.startIndex&&o.endIndex>=r.endIndex||r.startIndex>o.endIndex?r=null:o=null),o){const r=function(t,e,n,o,r){const s=t.getTextContent();let l,i,c;if(r[0]===s?l=t:0===e?[l,i]=t.splitText(n):[c,l,i]=t.splitText(e,n),l.setTextContent(r[2]),o)for(const t of o.format)l.hasFormat(t)||l.toggleFormat(t);return{nodeAfter:i,nodeBefore:c,transformedNode:l}}(t,o.startIndex,o.endIndex,o.transformer,o.match);me(r.nodeAfter)&&Ce(r.nodeAfter,e,n),me(r.nodeBefore)&&Ce(r.nodeBefore,e,n),me(r.transformedNode)&&Ce(r.transformedNode,e,n)}else if(r){const o=function(t,e,n,o,r){let s,l,i;return 0===e?[s,l]=t.splitText(n):[i,s,l]=t.splitText(e,n),o.replace?{matchedNode:s,nodeAfter:l,nodeBefore:i,transformedNode:o.replace(s,r)||void 0}:null}(t,r.startIndex,r.endIndex,r.transformer,r.match);if(!o)return;me(o.nodeAfter)&&Ce(o.nodeAfter,e,n),me(o.nodeBefore)&&Ce(o.nodeBefore,e,n),me(o.transformedNode)?Ce(o.transformedNode,e,n):void 0===o.transformedNode&&me(o.matchedNode)&&null!==o.matchedNode.getParent()&&o.matchedNode.setTextContent(ot(o.matchedNode.getTextContent()))}if(!o&&!r){const e=ot(t.getTextContent());t.setTextContent(e)}}function Ie(t,e,n,o=!1){const r=Q(n),s=function(t){const e={},n={},o=[];for(const r of t){const{tag:t}=r;e[t]=r;const s=t.replace(/(\*|\^|\+)/g,"\\$1");o.push(s),1===t.length?n[t]="`"===t?new RegExp("(^|[^\\\\`])(`)((?:\\\\`|[^`])+?)(`)(?!`)"):new RegExp(`(^|[^\\\\${s}])(${s})((\\\\${s})?.*?[^${s}\\s](\\\\${s})?)(${s})(?![\\\\${s}])`):n[t]=new RegExp(`(^|[^\\\\])(${s})((\\\\${s})?.*?[^\\s](\\\\${s})?)(${s})(?!\\\\)`)}return{fullMatchRegExpByTag:n,openTagsRegExp:new RegExp(`(${o.join("|")})`,"g"),transformersByTag:e}}(r.textFormat),l=t.split("\n"),i=l.length;!function(t){const n=Pt,c=Mt;Pt=[],Mt=t;try{return(()=>{for(let t=0;t<i;t++){const n=l[t],[i,c]=Te(l,t,r.multilineElement,e);i?t=c:ve(n,e,r.element,s,r.textMatch,o)}})()}finally{Pt=n,Mt=c}}(!o);const c=e.getChildren();for(const t of c)if(!o&&nt(t)&&e.getChildrenSize()>1)t.remove();else if(u(t))for(const e of t.getAllTextNodes())$e(e)}function Te(t,e,n,o){for(const r of n){const{handleImportAfterStartMatch:n,regExpEnd:s,regExpStart:l,replace:i}=r,c=t[e].match(l);if(!c)continue;if(n){const s=n({lines:t,rootNode:o,startLineIndex:e,startMatch:c,transformer:r});if(null===s)continue;if(s)return s}const f="object"==typeof s&&"regExp"in s?s.regExp:s,u=s&&"object"==typeof s&&"optional"in s?s.optional:!s;let a=e;const d=t.length;for(;a<d;){const n=f?t[a].match(f):null;if(!n&&(!u||u&&a<d-1)){a++;continue}if(n&&e===a&&n.index===c.index){a++;continue}const r=[];if(n&&e===a)r.push(t[e].slice(c[0].length,-n[0].length));else for(let o=e;o<=a;o++)if(o===e){const e=t[o].slice(c[0].length);r.push(e)}else if(o===a&&n){const e=t[o].slice(0,-n[0].length);r.push(e)}else r.push(t[o]);if(!1!==i(o,null,c,n,r,!0))return[!0,a];break}}return[!1,e]}function ve(e,n,r,l,i,c){const f=o(e),u=h();u.append(f),n.append(u);for(const{regExp:t,replace:n}of r){const o=e.match(t);if(o&&(f.setTextContent(e.slice(o[0].length)),!1!==n(u,[f],o,!0)))break}if(Ce(f,l,i),null!==u.getParent()&&e.length>0){const e=u.getPreviousSibling();if(!c&&(t(e)||K(e)||z(e))){let t=e;if(z(e)){const n=e.getLastDescendant();t=null==n?null:s(n,D)}null!=t&&t.getTextContentSize()>0&&(t.splice(t.getChildrenSize(),0,[bt(t),...u.getChildren()]),u.remove())}}}function $e(t){if(d(t))return;const e=t.getTextContent();if(!e.includes("\t"))return;const n=t.getFormat(),r=t.getStyle(),s=[];let l=0;for(let t=e.indexOf("\t");-1!==t;t=e.indexOf("\t",t+1))t>l&&s.push(o(e.slice(l,t)).setFormat(n).setStyle(r)),s.push(g()),l=t+1;l<e.length&&s.push(o(e.slice(l)).setFormat(n).setStyle(r)),t.getParentOrThrow().splice(t.getIndexWithinParent(),1,s)}function ye(t,...e){throw function(t,...e){const n=new URL("https://lexical.dev/docs/error"),o=new URLSearchParams;o.append("code",t);for(const t of e)o.append("v",t);return n.search=o.toString(),new Error(`Minified Lexical error #${t}; visit ${n.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}(t,...e)}function Ee(t,e,n,o,r){const s=t.getParent();if(!S(s)||t.getFirstChild()!==e)return!1;const l=e.getTextContent();if(!r&&" "!==l[n-1])return!1;for(const{regExp:s,replace:i}of o){const o=l.match(s),c=r||o&&o[0].endsWith(" ")?n:n-1;if(o&&o[0].length===c){const r=e.getNextSiblings(),[s,l]=e.splitText(n);if(!1!==i(t,l?[l,...r]:r,o,!1))return s.remove(),!0}}return!1}function Se(t,e,n,o,r){const s=t.getParent();if(!S(s)||t.getFirstChild()!==e)return!1;const l=e.getTextContent();if(!r&&" "!==l[n-1])return!1;for(const{regExpStart:s,replace:i,regExpEnd:c}of o){if(c&&!("optional"in c)||c&&"optional"in c&&!c.optional)continue;const o=l.match(s);if(o){const s=r||o[0].endsWith(" ")?n:n-1;if(o[0].length!==s)continue;const l=e.getNextSiblings(),[c,f]=e.splitText(n);if(!1!==i(t,f?[f,...l]:l,o,null,null,!1))return c.remove(),!0}}return!1}function be(t,e){let n=0;const o=t.getTextContent();for(let t=0;t<e;t++)"`"===o[t]&&n++;return n%2!=0}function we(t,e,n){const o=n.length;for(let r=e;r>=o;r--){const e=r-o;if(ke(t,e,n,0,o)&&" "!==t[e+o])return e}return-1}function Ne(t){const n=t.getNode();let o=0;if(e(n))o=t.offset;else if(u(n))for(const e of n.getChildren().slice(0,t.offset))o+=e.getTextContentSize();for(let t=n.getPreviousSibling();null!==t;t=t.getPreviousSibling())o+=t.getTextContentSize();return o}function ke(t,e,n,o,r){for(let s=0;s<r;s++)if(t[e+s]!==n[o+s])return!1;return!0}function Fe(t,n=se){const o=Q(n),r=o.element.filter(t=>t.triggerOnEnter),s=J(o.textFormat,({tag:t})=>t[t.length-1]),l=J(o.textMatch,({trigger:t})=>t),i=new Set([" "]);for(const t of o.textFormat)i.add(t.tag.slice(-1));for(const t of o.textMatch)void 0!==t.trigger&&i.add(t.trigger);for(const e of n){const n=e.type;if("element"===n||"text-match"===n||"multiline-element"===n){const n=e.dependencies;for(const e of n)t.hasNode(e)||ye(173,e.getType())}}return p(t.registerUpdateListener(({tags:n,dirtyLeaves:r,editorState:f,prevEditorState:u})=>{if(n.has(x)||n.has(m))return;if(t.isComposing())return;const a=n.has(C),d=f.read(I),g=u.read(I);if(!T(g)||!T(d)||!d.isCollapsed()||d.is(g)&&!a)return;const h=d.anchor.key,p=d.anchor.offset,y=f._nodeMap.get(h);if(e(y)&&r.has(h)&&(a||1===p||!(f.read(()=>Ne(d.anchor))>u.read(()=>Ne(g.anchor))+1))){if(a){const t=f.read(()=>y.getTextContent())[p-1];if(!i.has(t))return}t.update(()=>{if(!me(y))return;const t=y.getParent();null===t||M(t)||((t,n,r)=>!!(Ee(t,n,r,o.element)||Se(t,n,r,o.multilineElement)||function(t,e,n){let o=t.getTextContent();const r=n[o[e-1]];if(null==r)return!1;e<o.length&&(o=o.slice(0,e));for(const e of r){if(!e.replace||!e.regExp)continue;const n=o.match(e.regExp);if(null===n)continue;const r=n.index||0,s=r+n[0].length;let l;return 0===r?[l]=t.splitText(s):[,l]=t.splitText(r,s),l.selectNext(0,0),e.replace(l,n),!0}return!1}(n,r,l)||function(t,n,o){const r=t.getTextContent(),s=n-1,l=r[s],i=o[l];if(!i)return!1;for(const n of i){const{tag:o}=n,i=o.length,f=s-i+1;if(i>1&&!ke(r,f,o,0,i))continue;if(" "===r[f-1])continue;const u=r[s+1];if(!1===n.intraword&&u&&!V.test(u))continue;const a=t;let d=a,g=we(r,f,o),h=d;for(;g<0&&(h=h.getPreviousSibling())&&!c(h);)if(e(h)){if(h.hasFormat("code"))continue;const t=h.getTextContent();d=h,g=we(t,t.length,o)}if(g<0)continue;if(d===a&&g+i===f)continue;const p=d.getTextContent();if(g>0&&p[g-1]===l)continue;const x=p[g-1];if(!1===n.intraword&&x&&!V.test(x))continue;if(!n.format.includes("code")&&be(d,g))continue;const m=a.getTextContent(),C=m.slice(0,f)+m.slice(s+1);a.setTextContent(C);const v=d===a?C:p;d.setTextContent(v.slice(0,g)+v.slice(g+i));const $=I(),y=b();w(y);const E=s-i*(d===a?2:1)+1;y.anchor.set(d.__key,g,"text"),y.focus.set(a.__key,E,"text");for(const t of n.format)y.formatText(t,N[t]);y.anchor.set(y.focus.key,y.focus.offset,y.focus.type);for(const t of n.format)y.hasFormat(t)&&y.toggleFormat(t);return T($)&&(y.format=$.format),!0}return!1}(n,r,s)))(t,y,d.anchor.offset)&&v($)})}}),t.registerCommand(y,t=>{if(null!==t&&t.shiftKey)return!1;const n=I();if(!T(n)||!n.isCollapsed())return!1;const s=n.anchor.offset,l=n.anchor.getNode();if(!e(l)||!me(l))return!1;const i=l.getParent();return null!==i&&!M(i)&&!(s!==l.getTextContent().length||!Se(i,l,s,o.multilineElement,!0)&&!Ee(i,l,s,r,!0)||(null!==t&&t.preventDefault(),0))},E))}function Oe(t,e=se,n,o=!1,r=!1){const s=o?t:le(t,r),l=n||f();l.clear(),Ie(s,l,e,o),null!==I()&&l.selectStart()}function Pe(t,e=se,n=!1,o=!1){const r=n?t:le(t,o),s=new k;return Ie(r,s,e,n),s.getChildren()}function Me(t=se,e,n=!1){const o=function(t,e=!1){const n=Q(t),o=[...n.multilineElement,...n.element],r=!e,s=n.textFormat.filter(t=>1===t.format.length).sort((t,e)=>Number(t.format.includes("code"))-Number(e.format.includes("code")));return t=>{const l=[],i=(t||f()).getChildren();for(let t=0;t<i.length;t++){const c=i[t],f=fe(c,o,s,n.textMatch,e);null!=f&&l.push(r&&t>0&&!nt(c)&&!nt(i[t-1])?"\n".concat(f):f)}return l.join("\n")}}(t,n);return o(e)}function Re(t=se,e,n=!1){if(!e||T(e)&&e.isCollapsed())return"";const o=function(t,e=!1){const n=Q(t),o=[...n.multilineElement,...n.element],r=!e,s=n.textFormat.filter(t=>1===t.format.length).sort((t,e)=>Number(t.format.includes("code"))-Number(e.format.includes("code")));return t=>{const l=[];let i=null;for(const c of f().getChildren()){const{shouldInclude:f,markdown:u}=ie(c,t,o,s,n.textMatch,e);f&&null!=u&&(l.push(!r||null===i||nt(c)||nt(i)?u:"\n".concat(u)),i=c)}return l.join("\n")}}(t,n);return o(e)}export{Oe as $convertFromMarkdownString,Re as $convertSelectionToMarkdownString,Me as $convertToMarkdownString,Pe as $generateNodesFromMarkdownString,Zt as BOLD_ITALIC_STAR,Ht as BOLD_ITALIC_UNDERSCORE,Kt as BOLD_STAR,qt as BOLD_UNDERSCORE,Wt as CHECK_LIST,jt as CODE,te as ELEMENT_TRANSFORMERS,Lt as HEADING,Xt as HIGHLIGHT,Dt as INLINE_CODE,Jt as ITALIC_STAR,Qt as ITALIC_UNDERSCORE,Yt as LINK,ee as MULTILINE_ELEMENT_TRANSFORMERS,Ut as ORDERED_LIST,At as QUOTE,Gt as STRIKETHROUGH,ne as TEXT_FORMAT_TRANSFORMERS,oe as TEXT_MATCH_TRANSFORMERS,se as TRANSFORMERS,zt as UNORDERED_LIST,mt as isTableRowDivider,Fe as registerMarkdownShortcuts};
|
|
9
|
+
import{$isParagraphNode as t,$isTextNode as e,$setState as n,$createTextNode as r,$getState as o,$findMatchingParent as s,$createLineBreakNode as i,createState as l,$isLineBreakNode as c,$isRangeSelection as f,$getRoot as u,$isElementNode as a,$isDecoratorNode as d,$isTabNode as g,$createTabNode as h,$createParagraphNode as p,mergeRegister as x,COLLABORATION_TAG as m,HISTORIC_TAG as C,COMPOSITION_END_TAG as I,$getSelection as T,$addUpdateTag as v,HISTORY_PUSH_TAG as S,KEY_ENTER_COMMAND as y,COMMAND_PRIORITY_LOW as E,$isRootOrShadowRoot as $,$createRangeSelection as b,$setSelection as w,TEXT_TYPE_TO_FORMAT as N,ArtificialNode__DO_NOT_USE as k}from"lexical";import{$sliceSelectedTextNodeContent as F}from"@lexical/selection";import{CodeNode as O,$createCodeNode as P,$isCodeNode as M}from"@lexical/code-core";import{LinkNode as R,$isLinkNode as B,$createLinkNode as _,$isAutoLinkNode as L}from"@lexical/link";import{ListNode as A,ListItemNode as j,$isListNode as z,$createListItemNode as W,$createListNode as K,$isListItemNode as U}from"@lexical/list";import{HeadingNode as D,QuoteNode as X,$isHeadingNode as Z,$isQuoteNode as H,$createQuoteNode as q,$createHeadingNode as G}from"@lexical/rich-text";function J(t,e){const n={};for(const r of t){const t=e(r);t&&(n[t]?n[t].push(r):n[t]=[r])}return n}function Q(t){const e=J(t,t=>t.type);return{element:e.element||[],multilineElement:e["multiline-element"]||[],textFormat:e["text-format"]||[],textMatch:e["text-match"]||[]}}const V=/[!-/:-@[-`{-~\s]/,Y=/\s/,tt=/[!"#$%&'()*+,\-./:;<=>?@[\]^_`{|}~]/,et=/^\s{0,3}$/;function nt(n){if(!t(n))return!1;const r=n.getFirstChild();return null==r||1===n.getChildrenSize()&&e(r)&&et.test(r.getTextContent())}function rt(t){return t.replace(/\\([!-/:-@[-`{-~])|&#(?:(\d{1,7})|[xX]([\da-fA-F]{1,6}));/g,(t,e,n,r)=>e??function(t,e){const n=void 0!==t?Number(t):parseInt(e,16);return 0===n||n>=55296&&n<=57343||n>1114111?"\ufffd":String.fromCodePoint(n)}(n,r))}function ot(t,e){let n=0;for(let r=e-1;r>=0&&"\\"===t[r];r--)n++;return n%2==1}function st(t){const e=e=>{let n=0;for(let r=e-1;r>=0&&"\\"===t[r];r--)n++;return n%2==1},n=[];let r=0;for(;r<t.length;)if("`"===t[r]){let e=1;for(;r+e<t.length&&"`"===t[r+e];)e++;n.push({index:r,length:e}),r+=e}else r++;const o=[];let s=0;for(;s<n.length;){const r=n[s];if(e(r.index)){s++;continue}let i=-1;for(let t=s+1;t<n.length;t++)if(n[t].length===r.length){i=t;break}if(-1===i){s++;continue}const l=n[i];let c=t.slice(r.index+r.length,l.index);c.length>=2&&c.startsWith(" ")&&c.endsWith(" ")&&/[^ ]/.test(c)&&(c=c.slice(1,-1)),o.push({content:c,endIndex:l.index+l.length,startIndex:r.index}),s=i+1}return o}function it(t,e,n,r,o){if(!lt(e,n,r,o))return!1;if("*"===t)return!0;if("_"===t){if(!lt(e,n,r,!o))return!0;const t=o?e[n-1]:e[n+r];return void 0!==t&&tt.test(t)}return!0}function lt(t,e,n,r){const o=t[e-1],s=t[e+n],[i,l]=r?[s,o]:[o,s];return void 0!==i&&!Y.test(i)&&(!tt.test(i)||void 0===l||Y.test(l)||tt.test(l))}const ct=/^(\s*)(\d{1,})\.\s/,ft=/^(\s*)[-*+]\s/,ut=/^(\s*)(?:[-*+]\s)?\s?(\[(\s|x)?\])\s/i,at=/^(#{1,6})\s/,dt=/^>\s/,gt=/^([ \t]*`{3,})([\w-]+)?[ \t]?/,ht=/^[ \t]*`{3,}$/,pt=/^[ \t]*```[^`]+(?:(?:`{1,2}|`{4,})[^`]+)*```(?:[^`]|$)/,xt=/^(?:\|)(.+)(?:\|)\s?$/;function mt(t){if("|"!==t[0])return!1;const{length:e}=t;let n=1,r=0;for(;n<e;){let e=n;for(" "===t[e]&&e++,":"===t[e]&&e++;"-"===t[e];)e++;if(":"===t[e]&&e++," "===t[e]&&e++,"|"!==t[e])break;r++,n=e+1}return r>0&&(n===e||n===e-1&&/\s/.test(t[n]))}const Ct=/^<[a-z_][\w-]*(?:\s[^<>]*)?\/?>/i,It=/^<\/[a-z_][\w-]*\s*>/i,Tt=t=>new RegExp(`(?:${t.source})$`,t.flags),vt=/* @__PURE__ */l("mdListMarker",{parse:t=>"string"==typeof t&&/^[-*+]$/.test(t)?t:"-",resetOnCopyNode:!0}),St=/* @__PURE__ */l("mdCodeFence",{parse:t=>"string"==typeof t&&/^`{3,}$/.test(t)?t:"```",resetOnCopyNode:!0}),yt=/* @__PURE__ */l("mdCodeMeta",{parse:t=>"string"==typeof t?t:"",resetOnCopyNode:!0}),Et=/* @__PURE__ */l("mdHardLineBreak",{parse:t=>"string"==typeof t&&/^(\\| {2,})$/.test(t)?t:"",resetOnCopyNode:!0});function $t(t){if(t.endsWith("\\")){let e=0;for(let n=t.length-1;n>=0&&"\\"===t[n];n--)e++;return e%2==1?[t.slice(0,-1),"\\"]:null}const e=t.match(/^(.*?\S)( {2,})$/);return e?[e[1],e[2]]:null}function bt(t){const r=i(),o=function(t){const n=t.getChildren(),r=n.length-1,o=n[r];if(!e(o))return null;const s=o.getTextContent(),i=$t(s);if(null!==i){const[t,e]=i;return o.setTextContent(t),e}return/^ {2,}$/.test(s)&&function(t,e){for(let n=e-1;n>=0;n--){if(c(t[n]))return!1;if(/\S/.test(t[n].getTextContent()))return!0}return!1}(n,r)?(o.setTextContent(""),s):null}(t);return null!==o&&n(r,Et,o),r}function wt(t){return H(t)}function Nt(t,e){let n=0;for(;n<e&&(" "===t[n]||"\t"===t[n]);)n++;return t.slice(n)}function kt(t,e){const r=t.getLastChild();e&&M(r)&&n(r,yt,e)}const Ft=t=>(e,n,r,o)=>{const s=t(r);s.append(...n),e.replace(s),o||s.select(0,0)};function Ot(t){let e=0;for(const n of t)e+="\t"===n?4-e%4:1;return e}let Pt=null,Mt=!1;const Rt=t=>(e,r,o,s)=>{if(Z(e)||!s&&wt(e))return!1;const i=e.getPreviousSibling(),l=e.getNextSibling(),c=W("check"===t?/^x$/i.test(o[3]||""):void 0),f=o[0].trim()[0],u="bullet"!==t&&"check"!==t||f!==vt.parse(f)?void 0:f,a=Pt;let d=i;if(null!==a){if(Mt)for(;null!==d&&nt(d);)d=d.getPreviousSibling();z(d)||(a.length=0)}const g=null===a||0===a.length?function(t){const e=t.match(/\t/g),n=t.match(/ /g);let r=0;return e&&(r+=e.length),n&&(r+=Math.floor(n.length/4)),r}(o[1]):function(t,e){const n=Ot(e);for(let e=t.length-1;e>=0;e--)if(n>=t[e])return e+1;return 0}(a,o[1]);if(z(l)&&l.getListType()===t){const n=l.getFirstChild();null!==n?n.insertBefore(c):l.append(c),"number"===t&&0===g&&l.setStart(Number(o[2])),e.remove()}else if(z(d)&&(d.getListType()===t||g>0))d.append(c),e.remove();else{const n=K(t,"number"===t?Number(o[2]):void 0);n.append(c),e.replace(n)}c.append(...r),s||c.select(0,0),g&&(c.setIndent(g),function(t,e,n){const r=t.getParent();if(!z(r)||r.getListType()===e)return;const o=r.getParent();if(!U(o))return;const s=K(e,"number"===e?Number(n[2]):void 0),i=null===t.getPreviousSibling();s.append(t);const l=W();l.append(s),i?o.insertBefore(l):o.insertAfter(l),0===r.getChildrenSize()&&o.remove()}(c,t,o));const h=c.getParent();u&&z(h)&&n(h,vt,u),null!==a&&function(t,e,n,r){for(let n=t.length;n<e;n++)t[n]=4*(n+1);t.length=e,t[e]=function(t,e){let n=t[0];if("check"===e){const e=n.slice(t[1].length).match(/^[-*+]\s/);e&&(n=t[1]+e[0])}return Math.min(Ot(n),Ot(t[1])+4)}(n,r)}(a,g,o,t)},Bt=(t,e,n,r)=>{const s=[],i=t.getChildren();let l=0;for(const c of i)if(U(c)){if(1===c.getChildrenSize()){const t=c.getFirstChild();if(z(t)){const o=Bt(t,e,n+1,r);o&&s.push(o);continue}}if(r&&!c.getChildren().some(t=>t.isSelected(r)))continue;const i=" ".repeat(4*n),f=t.getListType(),u=o(t,vt),a="number"===f?`${t.getStart()+l}. `:"check"===f?`${u} [${c.getChecked()?"x":" "}] `:u+" ";let d=e(c);"number"!==f&&(d=d.replace(/^(\s{0,3}\d+)(\.\s)/,"$1\\$2")),s.push(i+a+d),l++}return s.join("\n")},_t=/* @__PURE__ */Ft(t=>{const e="h"+t[1].length;return G(e)}),Lt={dependencies:[D],export:(t,e)=>{if(!Z(t))return null;const n=Number(t.getTag().slice(1));return"#".repeat(n)+" "+e(t)},regExp:at,replace:(t,e,n,r)=>!(!r&&wt(t))&&_t(t,e,n,r),triggerOnEnter:!0,type:"element"},At={dependencies:[X],export:(t,e)=>{if(!H(t))return null;const n=e(t).split("\n"),r=[];for(const t of n)r.push("> "+t);return r.join("\n")},regExp:dt,replace:(t,e,n,r)=>{if(r){const n=t.getPreviousSibling();if(H(n))return n.splice(n.getChildrenSize(),0,[bt(n),...e]),void t.remove()}const o=q();o.append(...e),t.replace(o),r||o.select(0,0)},triggerOnEnter:!0,type:"element"},jt={dependencies:[O],export:t=>{if(!M(t))return null;const e=t.getTextContent();let n=o(t,St);if(e.indexOf(n)>-1){const t=e.match(/`{3,}/g);if(t){const e=Math.max(...t.map(t=>t.length));n="`".repeat(e+1)}}const r=t.getLanguage()||"",s=r?o(t,yt):"";return n+r+(s?" "+s:"")+(e?"\n"+e:"")+"\n"+n},handleImportAfterStartMatch:({lines:t,rootNode:e,startLineIndex:n,startMatch:r})=>{const o=r[1],s=o.trim().length,i=t[n],l=r.index+o.length,c=i.slice(l),f=new RegExp(`\`{${s},}$`);if(f.test(c)){const t=c.match(f),o=c.slice(0,c.lastIndexOf(t[0])),s=[...r];return s[2]="",jt.replace(e,null,s,t,[o],!0),[!0,n]}const u=new RegExp(`^[ \\t]*\`{${s},}$`);for(let o=n+1;o<t.length;o++){const s=t[o];if(u.test(s)){const l=s.match(u),c=t.slice(n+1,o),f=r[2]?i.slice(r[0].length).trim():"";return c.unshift(f?"":i.slice(r[0].length)),jt.replace(e,null,r,l,c,!0),kt(e,f),[!0,o]}}const a=t.slice(n+1);return a.unshift(i.slice(r[0].length)),jt.replace(e,null,r,null,a,!0),[!0,t.length-1]},regExpEnd:{optional:!0,regExp:ht},regExpStart:gt,replace:(t,e,o,s,i,l)=>{let c,f;const u=o[1]?o[1].trim():"```",a=o[2]||void 0,d=o[1]?o[1].length-o[1].trimStart().length:0;if(!e&&i){if(1===i.length)s?(c=P(a),f=Nt(i[0],d)):(c=P(a),f=i[0].startsWith(" ")?i[0].slice(1):i[0]);else{for(c=P(a),i.length>0&&(0===i[0].trim().length?i.shift():i[0].startsWith(" ")&&(i[0]=i[0].slice(1)));i.length>0&&!i[i.length-1].length;)i.pop();f=i.map(t=>Nt(t,d)).join("\n")}n(c,St,u);const e=r(f);c.append(e),t.append(c)}else if(e){if(!l&&wt(t))return!1;Ft(t=>P(t?t[2]:void 0))(t,e,o,l)}},type:"multiline-element"},zt={dependencies:[A,j],export:(t,e,n)=>z(t)?Bt(t,e,0,n):null,regExp:ft,replace:/* @__PURE__ */Rt("bullet"),triggerOnEnter:!0,type:"element"},Wt={dependencies:[A,j],export:(t,e,n)=>z(t)?Bt(t,e,0,n):null,regExp:ut,replace:/* @__PURE__ */Rt("check"),triggerOnEnter:!0,type:"element"},Kt={dependencies:[A,j],export:(t,e,n)=>z(t)?Bt(t,e,0,n):null,regExp:ct,replace:/* @__PURE__ */Rt("number"),triggerOnEnter:!0,type:"element"},Ut={format:["code"],tag:"`",type:"text-format"},Dt={format:["highlight"],tag:"==",type:"text-format"},Xt={format:["bold","italic"],tag:"***",type:"text-format"},Zt={format:["bold","italic"],intraword:!1,tag:"___",type:"text-format"},Ht={format:["bold"],tag:"**",type:"text-format"},qt={format:["bold"],intraword:!1,tag:"__",type:"text-format"},Gt={format:["strikethrough"],tag:"~~",type:"text-format"},Jt={format:["italic"],tag:"*",type:"text-format"},Qt={format:["italic"],intraword:!1,tag:"_",type:"text-format"},Vt=/[\s\0-\x1f\x7f]/;function Yt(t,e){return t.replace(/&(?=#\d+;|#[Xx][\dA-Fa-f]+;|[A-Za-z][\dA-Za-z]*;)/g,"&").replace(e,"\\$&").replace(/`/g,"\\`").replace(/[\r\n]/g,t=>`&#${t.charCodeAt(0)};`)}const te={dependencies:[R],export:(t,e,n)=>{if(!B(t)||L(t))return null;const r=e(t),o=t.getTitle(),s=t.getURL(),i=""===s||Vt.test(s)?`<${Yt(s,/[\\<>]/g)}>`:Yt(s,/[\\()]|^</g);return o?`[${r}](${i} "${Yt(o,/[\\"]/g)}")`:`[${r}](${i})`},importRegExp:/(?:\[(.+?)\])(?:\(\s*(?:(?:<((?:\\[^\n\r]|[^<>\n\r\\])*)>|((?!<)(?:\\[^\s]|\\(?=\s)|\((?:\\[^\s]|[^\s()\\]|\((?:\\[^\s]|[^\s()\\]|\((?:\\[^\s]|[^\s()\\])*\))*\))*\)|[^\s()\\])+))(?:\s+(?:"((?:\\[\s\S]|[^"\\])*)"|'((?:\\[\s\S]|[^'\\])*)'|\(((?:\\[\s\S]|[^()\\])*)\)))?\s*)?\))/,regExp:/(?:\[([^[\]]*(?:\[[^[\]]*\][^[\]]*)*)\])(?:\(\s*(?:(?:<((?:\\[^\n\r]|[^<>\n\r\\])*)>|((?!<)(?:\\[^\s]|\\(?=\s)|\((?:\\[^\s]|[^\s()\\]|\((?:\\[^\s]|[^\s()\\]|\((?:\\[^\s]|[^\s()\\])*\))*\))*\)|[^\s()\\])+))(?:\s+(?:"((?:\\[\s\S]|[^"\\])*)"|'((?:\\[\s\S]|[^'\\])*)'|\(((?:\\[\s\S]|[^()\\])*)\)))?\s*)?\))$/,replace:(t,e)=>{const n=e.input||"",o=e.index||0;if(s(t,B)||ot(n,o)||ot(n,o+e[1].length+1))return;const[,i,l,c,f,u,a]=e,d=rt(l??c??""),g=f??u??a,h=null!=g?rt(g):void 0,p=_(d,{title:h}),x=function(t){const e=st(t);let n=0;const r=t.replace(/\\.|[[\]]/g,(t,r)=>{for(;n<e.length&&r>=e[n].endIndex;)n++;return n<e.length&&r>=e[n].startIndex||"\\"===t[0]?" ".repeat(t.length):t}),o=[];let s=!1;for(let t=0;t<r.length;t++){const e=r[t];"["===e?o.push(t):"]"===e&&void 0===o.pop()&&(s=!0)}return o.pop()??(s?null:-1)}(i);if(null===x)return;let m=i,C="";-1!==x&&(C="["+function(t){let e="",n=0;for(const{startIndex:r,endIndex:o}of st(t))e+=rt(t.slice(n,r))+t.slice(r,o),n=o;return e+rt(t.slice(n))}(i.slice(0,x)),m=i.slice(x+1));const I=t.getFormat(),T=r(m);return T.setFormat(I),p.append(T),t.replace(p),C&&p.insertBefore(r(C).setFormat(I)),T},trigger:")",type:"text-match"},ee=[Lt,At,zt,Kt],ne=[jt],re=[Ut,Xt,Zt,Ht,qt,Dt,Jt,Qt,Gt],oe=[te];function se(...t){return t.flat()}const ie=/* @__PURE__ */se(ee,ne,re,oe);function le(t,e=!1){const n=t.split("\n");let r=0;const o=[];for(let t=0;t<n.length;t++){const s=n[t],i=s.trimEnd(),l=o[o.length-1],c=t<n.length-1?$t(s):null,f=void 0!==l&&null!==$t(l);if(pt.test(i))o.push(i);else if(0===r){{const t=i.match(gt);if(t){r=t[1].trim().length,o.push(i);continue}}""===i||""===l||!l||at.test(l)||at.test(i)||dt.test(i)||ct.test(i)||ft.test(i)||ut.test(i)||xt.test(i)||mt(i)||f||!e||Ct.test(i)||It.test(i)||Tt(It).test(l)||Tt(Ct).test(l)||ht.test(l)?o.push(!e&&""!==i||null!==c?s:i):o[o.length-1]=l+" "+(null===c?i:s).trimStart()}else{if(ht.test(i)&&i.trim().length>=r){r=0,o.push(i);continue}o.push(s)}}return o.join("\n")}function ce(t,e,n,r,o,s){let i=t.isSelected(e);for(const l of n){if(!l.export)continue;const n=l.export(t,t=>fe(t,e,r,o,s).markdown,e);if(null!=n)return!i&&a(t)&&fe(t,e,r,o,s).shouldInclude&&(i=!0),{markdown:n,shouldInclude:i}}if(a(t)){const n=fe(t,e,r,o,s);return{markdown:n.markdown,shouldInclude:i||n.shouldInclude}}return d(t)?{markdown:t.getTextContent(),shouldInclude:i}:{markdown:null,shouldInclude:i}}function fe(t,n,r,o,s,i,l){const f=[],u=t.getChildren();let g=!1;i||(i=[]),l||(l=[]);t:for(const t of u){let u=t.isSelected(n);for(const e of o){if(!e.export)continue;const c=e.export(t,t=>fe(t,n,r,o,s,i,[...l,...i]).markdown,t=>ge(t,xe(t,n),r,i,l,s,n));if(null!=c){!u&&a(t)&&t.getChildren().some(t=>t.isSelected(n))&&t.extractWithChild(t,n,"html")&&(u=!0),u&&(f.push(c),g=!0);continue t}}if(c(t))u&&(f.push(de(t)),g=!0);else if(e(t))u&&(f.push(ge(t,xe(t,n),r,i,l,s,n)),g=!0);else if(a(t)){const e=fe(t,n,r,o,s,i,l);!u&&e.shouldInclude&&t.extractWithChild(t,n,"html")&&(u=!0),(u||e.shouldInclude)&&(f.push(e.markdown),g=!0)}else d(t)&&u&&(f.push(t.getTextContent()),g=!0)}return{markdown:f.join(""),shouldInclude:g}}function ue(t,e,n,r,o){for(const s of e){if(!s.export)continue;const e=s.export(t,t=>ae(t,n,r,void 0,void 0,o));if(null!=e)return e}return a(t)?ae(t,n,r,void 0,void 0,o):d(t)?t.getTextContent():null}function ae(t,n,r,o,s,i=!1){const l=[],f=t.getChildren();o||(o=[]),s||(s=[]);t:for(const t of f){for(const e of r){if(!e.export)continue;const c=e.export(t,t=>ae(t,n,r,o,[...s,...o],i),(t,e)=>ge(t,e,n,o,s,i,null));if(null!=c){l.push(c);continue t}}c(t)?l.push(de(t)):e(t)?l.push(ge(t,t.getTextContent(),n,o,s,i,null)):a(t)?l.push(ae(t,n,r,o,s,i)):d(t)&&l.push(t.getTextContent())}return l.join("")}function de(t){return o(t,Et)+"\n"}function ge(t,e,n,r,o,s,i){const l=t.hasFormat("code");let c=e;l||(c=s?c.replace(/([*_`~])/g,"\\$1"):c.replace(/([[\]*_`~\\]|<(?=\S|$)|&(?=#|$))/g,t=>/[*_`~\\]/.test(t)?`\\${t}`:`&#${t.charCodeAt(0)};`));const f=Ce(e);let u="",a="",d="";const g=he(t,!0),h=new Set;for(const e of n){const n=e.format[0],o=e.tag;"code"!==n&&f&&t.hasFormat(n)&&!h.has(n)&&(h.add(n),me(g,n)&&r.find(t=>t.tag===o)||(r.push({answers:new Map,format:n,tag:o}),u+=o))}for(let e=0;e<r.length;e++){const n=me(t,r[e].format);if(n&&pe(t,r[e],i))continue;const s=[...r];for(;s.length>e;){const t=s.pop();t&&o.find(e=>e.tag===t.tag)||(t&&"string"==typeof t.tag&&(n?d+=t.tag:a+=t.tag),r.pop())}break}if(l&&""!==e){const{fence:t,padded:n}=function(t){const e=t.match(/`+/g),n=e?Math.max(...e.map(t=>t.length)):0;return{fence:"`".repeat(n+1),padded:0===t.length||t.includes("`")||/^\s/.test(t)&&/\s$/.test(t)&&/[^ ]/.test(t)?` ${t} `:t}}(e);c=t+n+t}else if(!f)return a+d+c;const p=c.trimStart(),x=p.trimEnd();return a+c.slice(0,c.length-p.length)+u+x+d+p.slice(x.length)}function he(t,n){const r=n?t.getPreviousSibling():t.getNextSibling();return e(r)?r:null}function pe(t,e,n){const{answers:r}=e,o=r.get(t.getKey());if(void 0!==o)return o;const s=[];let i=he(t,!1),l=!1;for(;i&&i.hasFormat(e.format)&&(!n||i.isSelected(n));){const t=xe(i,n);if(Ce(t)){l=!0;break}if(t.includes("\n"))break;const e=r.get(i.getKey());if(void 0!==e){l=e;break}s.push(i),i=he(i,!1)}r.set(t.getKey(),l);for(const t of s)r.set(t.getKey(),l);return l}function xe(t,e){return e?F(e,t,"clone").getTextContent():t.getTextContent()}function me(t,n){return e(t)&&t.hasFormat(n)}function Ce(t){return/\S/.test(t)}function Ie(t,e){const n=new RegExp(e.source,e.flags.replace(/[gy]/g,"")+"g");let r;for(;null!==(r=n.exec(t));){if(!ot(t,r.index))return r;n.lastIndex=r.index+1}return null}function Te(t){return e(t)&&!t.hasFormat("code")}function ve(t,e,n){let r=function(t,e){const n=t.getTextContent(),r=e.transformersByTag["`"],o=[];let s=null;if(r){const t=st(n);for(const e of t)s||(s={content:e.content,endIndex:e.endIndex,startIndex:e.startIndex,tag:"`"}),o.push({end:e.endIndex,start:e.startIndex})}const i=function(t,e,n=[]){const r=[],o=new Set(Object.keys(e.transformersByTag).filter(t=>"`"!==t[0]).map(t=>t[0])),s=e=>{let n=0;for(let r=e-1;r>=0&&"\\"===t[r];r--)n++;return n%2==1},i=t=>n.some(e=>t>=e.start&&t<e.end);let l=0;for(;l<t.length;){const e=t[l];if(!o.has(e)||s(l)||i(l)){l++;continue}let n=1;for(;l+n<t.length&&t[l+n]===e;)n++;const c=it(e,t,l,n,!0),f=it(e,t,l,n,!1);(c||f)&&r.push({active:!0,canClose:f,canOpen:c,char:e,index:l,length:n}),l+=n}return r}(n,e,o),l=i.length>0?function(t,e,n){const r={};let o=0,s=null;for(;o<e.length;){const i=e[o];if(!i.active||!i.canClose||0===i.length){o++;continue}const l=`${i.char}${i.canOpen}${i.length%3}`,c=r[l]??-1;let f=!1;for(let r=o-1;r>c;r--){const l=e[r];if(!l.active||!l.canOpen||0===l.length||l.char!==i.char)continue;if((l.canClose||i.canOpen)&&(l.length+i.length)%3==0&&l.length%3!=0&&i.length%3!=0)continue;const c=Math.min(l.length,i.length),u=Object.keys(n.transformersByTag).filter(t=>t[0]===l.char&&t.length<=c).sort((t,e)=>e.length-t.length)[0];if(!u)continue;f=!0;const a=u.length,d={content:t.slice(l.index+l.length,i.index),endIndex:i.index+a,startIndex:l.index+(l.length-a),tag:u};(!s||d.startIndex<s.startIndex||d.startIndex===s.startIndex&&d.endIndex>s.endIndex)&&(s=d);for(let t=r+1;t<o;t++)e[t].active=!1;l.length-=a,i.length-=a,l.active=l.length>0,i.length>0?i.index+=a:(i.active=!1,o++);break}f||(r[l]=o-1,i.canOpen||(i.active=!1),o++)}return s}(n,i,e):null;let c=null,f=null;if(s&&l?l.startIndex<=s.startIndex&&l.endIndex>=s.endIndex?(c=l,f=e.transformersByTag[l.tag]):(c=s,f=r):s?(c=s,f=r):l&&(c=l,f=e.transformersByTag[l.tag]),!c||!f)return null;const u=[n.slice(c.startIndex,c.endIndex),c.tag,c.content];return u.index=c.startIndex,u.input=n,{endIndex:c.endIndex,isCodeSpan:f===r,match:u,startIndex:c.startIndex,transformer:f}}(t,e),o=function(t,e){const n=t;let r,o,s,i;for(const t of e){if(!t.replace||!t.importRegExp)continue;const e=n.getTextContent(),l=void 0!==te.importRegExp&&t.importRegExp.source===te.importRegExp.source?Ie(e,t.importRegExp):e.match(t.importRegExp);if(!l)continue;const c=l.index||0,f=t.getEndIndex?t.getEndIndex(n,l):c+l[0].length;!1!==f&&(void 0===r||void 0===o||c<r&&(f>o||f<=r))&&(r=c,o=f,s=t,i=l)}return void 0===r||void 0===o||void 0===s||void 0===i?null:{endIndex:o,match:i,startIndex:r,transformer:s}}(t,n);if(r&&o&&(r.isCodeSpan?o.startIndex<=r.startIndex&&o.endIndex>=r.endIndex?r=null:o=null:r.startIndex<=o.startIndex&&r.endIndex>=o.endIndex||o.startIndex>r.endIndex?o=null:r=null),r){const o=function(t,e,n,r,o){const s=t.getTextContent();let i,l,c;if(o[0]===s?i=t:0===e?[i,l]=t.splitText(n):[c,i,l]=t.splitText(e,n),i.setTextContent(o[2]),r)for(const t of r.format)i.hasFormat(t)||i.toggleFormat(t);return{nodeAfter:l,nodeBefore:c,transformedNode:i}}(t,r.startIndex,r.endIndex,r.transformer,r.match);Te(o.nodeAfter)&&ve(o.nodeAfter,e,n),Te(o.nodeBefore)&&ve(o.nodeBefore,e,n),Te(o.transformedNode)&&ve(o.transformedNode,e,n)}else if(o){const r=function(t,e,n,r,o){let s,i,l;return 0===e?[s,i]=t.splitText(n):[l,s,i]=t.splitText(e,n),r.replace?{matchedNode:s,nodeAfter:i,nodeBefore:l,transformedNode:r.replace(s,o)||void 0}:null}(t,o.startIndex,o.endIndex,o.transformer,o.match);if(!r)return;Te(r.nodeAfter)&&ve(r.nodeAfter,e,n),Te(r.nodeBefore)&&ve(r.nodeBefore,e,n),Te(r.transformedNode)?ve(r.transformedNode,e,n):void 0===r.transformedNode&&Te(r.matchedNode)&&null!==r.matchedNode.getParent()&&r.matchedNode.setTextContent(rt(r.matchedNode.getTextContent()))}if(!r&&!o){const e=rt(t.getTextContent());t.setTextContent(e)}}function Se(t,e,n,r=!1){const o=Q(n),s=function(t){const e={},n={},r=[];for(const o of t){const{tag:t}=o;e[t]=o;const s=t.replace(/(\*|\^|\+)/g,"\\$1");r.push(s),1===t.length?n[t]="`"===t?new RegExp("(^|[^\\\\`])(`)((?:\\\\`|[^`])+?)(`)(?!`)"):new RegExp(`(^|[^\\\\${s}])(${s})((\\\\${s})?.*?[^${s}\\s](\\\\${s})?)(${s})(?![\\\\${s}])`):n[t]=new RegExp(`(^|[^\\\\])(${s})((\\\\${s})?.*?[^\\s](\\\\${s})?)(${s})(?!\\\\)`)}return{fullMatchRegExpByTag:n,openTagsRegExp:new RegExp(`(${r.join("|")})`,"g"),transformersByTag:e}}(o.textFormat),i=t.split("\n"),l=i.length;!function(t){const n=Pt,c=Mt;Pt=[],Mt=t;try{return(()=>{for(let t=0;t<l;t++){const n=i[t],[l,c]=ye(i,t,o.multilineElement,e);l?t=c:Ee(n,e,o.element,s,o.textMatch,r)}})()}finally{Pt=n,Mt=c}}(!r);const c=e.getChildren();for(const t of c)if(!r&&nt(t)&&e.getChildrenSize()>1)t.remove();else if(a(t))for(const e of t.getAllTextNodes())$e(e)}function ye(t,e,n,r){for(const o of n){const{handleImportAfterStartMatch:n,regExpEnd:s,regExpStart:i,replace:l}=o,c=t[e].match(i);if(!c)continue;if(n){const s=n({lines:t,rootNode:r,startLineIndex:e,startMatch:c,transformer:o});if(null===s)continue;if(s)return s}const f="object"==typeof s&&"regExp"in s?s.regExp:s,u=s&&"object"==typeof s&&"optional"in s?s.optional:!s;let a=e;const d=t.length;for(;a<d;){const n=f?t[a].match(f):null;if(!n&&(!u||u&&a<d-1)){a++;continue}if(n&&e===a&&n.index===c.index){a++;continue}const o=[];if(n&&e===a)o.push(t[e].slice(c[0].length,-n[0].length));else for(let r=e;r<=a;r++)if(r===e){const e=t[r].slice(c[0].length);o.push(e)}else if(r===a&&n){const e=t[r].slice(0,-n[0].length);o.push(e)}else o.push(t[r]);if(!1!==l(r,null,c,n,o,!0))return[!0,a];break}}return[!1,e]}function Ee(e,n,o,i,l,c){const f=r(e),u=p();u.append(f),n.append(u);for(const{regExp:t,replace:n}of o){const r=e.match(t);if(r&&(f.setTextContent(e.slice(r[0].length)),!1!==n(u,[f],r,!0)))break}if(ve(f,i,l),null!==u.getParent()&&e.length>0){const e=u.getPreviousSibling();if(!c&&(t(e)||H(e)||z(e))){let t=e;if(z(e)){const n=e.getLastDescendant();t=null==n?null:s(n,U)}null!=t&&t.getTextContentSize()>0&&(t.splice(t.getChildrenSize(),0,[bt(t),...u.getChildren()]),u.remove())}}}function $e(t){if(g(t))return;const e=t.getTextContent();if(!e.includes("\t"))return;const n=t.getFormat(),o=t.getStyle(),s=[];let i=0;for(let t=e.indexOf("\t");-1!==t;t=e.indexOf("\t",t+1))t>i&&s.push(r(e.slice(i,t)).setFormat(n).setStyle(o)),s.push(h()),i=t+1;i<e.length&&s.push(r(e.slice(i)).setFormat(n).setStyle(o)),t.getParentOrThrow().splice(t.getIndexWithinParent(),1,s)}function be(t,...e){throw function(t,...e){const n=new URL("https://lexical.dev/docs/error"),r=new URLSearchParams;r.append("code",t);for(const t of e)r.append("v",t);return n.search=r.toString(),new Error(`Minified Lexical error #${t}; visit ${n.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}(t,...e)}function we(t,e,n,r,o){const s=t.getParent();if(!$(s)||t.getFirstChild()!==e)return!1;const i=e.getTextContent();if(!o&&" "!==i[n-1])return!1;for(const{regExp:s,replace:l}of r){const r=i.match(s),c=o||r&&r[0].endsWith(" ")?n:n-1;if(r&&r[0].length===c){const o=e.getNextSiblings(),[s,i]=e.splitText(n);if(!1!==l(t,i?[i,...o]:o,r,!1))return s.remove(),!0}}return!1}function Ne(t,e,n,r,o){const s=t.getParent();if(!$(s)||t.getFirstChild()!==e)return!1;const i=e.getTextContent();if(!o&&" "!==i[n-1])return!1;for(const{regExpStart:s,replace:l,regExpEnd:c}of r){if(c&&!("optional"in c)||c&&"optional"in c&&!c.optional)continue;const r=i.match(s);if(r){const s=o||r[0].endsWith(" ")?n:n-1;if(r[0].length!==s)continue;const i=e.getNextSiblings(),[c,f]=e.splitText(n);if(!1!==l(t,f?[f,...i]:i,r,null,null,!1))return c.remove(),!0}}return!1}function ke(t,e){let n=0;const r=t.getTextContent();for(let t=0;t<e;t++)"`"===r[t]&&n++;return n%2!=0}function Fe(t,e,n){const r=n.length;for(let o=e;o>=r;o--){const e=o-r;if(Pe(t,e,n,0,r)&&" "!==t[e+r])return e}return-1}function Oe(t){const n=t.getNode();let r=0;if(e(n))r=t.offset;else if(a(n))for(const e of n.getChildren().slice(0,t.offset))r+=e.getTextContentSize();for(let t=n.getPreviousSibling();null!==t;t=t.getPreviousSibling())r+=t.getTextContentSize();return r}function Pe(t,e,n,r,o){for(let s=0;s<o;s++)if(t[e+s]!==n[r+s])return!1;return!0}function Me(t,n=ie){const r=Q(n),o=r.element.filter(t=>t.triggerOnEnter),s=J(r.textFormat,({tag:t})=>t[t.length-1]),i=J(r.textMatch,({trigger:t})=>t),l=new Set([" "]);for(const t of r.textFormat)l.add(t.tag.slice(-1));for(const t of r.textMatch)void 0!==t.trigger&&l.add(t.trigger);for(const e of n){const n=e.type;if("element"===n||"text-match"===n||"multiline-element"===n){const n=e.dependencies;for(const e of n)t.hasNode(e)||be(173,e.getType())}}return x(t.registerUpdateListener(({tags:n,dirtyLeaves:o,editorState:u,prevEditorState:a})=>{if(n.has(m)||n.has(C))return;if(t.isComposing())return;const d=n.has(I),g=u.read(T),h=a.read(T);if(!f(h)||!f(g)||!g.isCollapsed()||g.is(h)&&!d)return;const p=g.anchor.key,x=g.anchor.offset,y=u._nodeMap.get(p);if(e(y)&&o.has(p)&&(d||1===x||!(u.read(()=>Oe(g.anchor))>a.read(()=>Oe(h.anchor))+1))){if(d){const t=u.read(()=>y.getTextContent())[x-1];if(!l.has(t))return}t.update(()=>{if(!Te(y))return;const t=y.getParent();null===t||M(t)||((t,n,o)=>!!(we(t,n,o,r.element)||Ne(t,n,o,r.multilineElement)||function(t,e,n){let r=t.getTextContent();const o=n[r[e-1]];if(null==o)return!1;e<r.length&&(r=r.slice(0,e));for(const e of o){if(!e.replace||!e.regExp)continue;const n=r.match(e.regExp);if(null===n)continue;const o=n.index||0,s=o+n[0].length;let i;return 0===o?[i]=t.splitText(s):[,i]=t.splitText(o,s),i.selectNext(0,0),e.replace(i,n),!0}return!1}(n,o,i)||function(t,n,r){const o=t.getTextContent(),s=n-1,i=o[s],l=r[i];if(!l)return!1;for(const n of l){const{tag:r}=n,l=r.length,u=s-l+1;if(l>1&&!Pe(o,u,r,0,l))continue;if(" "===o[u-1])continue;const a=o[s+1];if(!1===n.intraword&&a&&!V.test(a))continue;const d=t;let g=d,h=Fe(o,u,r),p=g;for(;h<0&&(p=p.getPreviousSibling())&&!c(p);)if(e(p)){if(p.hasFormat("code"))continue;const t=p.getTextContent();g=p,h=Fe(t,t.length,r)}if(h<0)continue;if(g===d&&h+l===u)continue;const x=g.getTextContent();if(h>0&&x[h-1]===i)continue;const m=x[h-1];if(!1===n.intraword&&m&&!V.test(m))continue;if(!n.format.includes("code")&&ke(g,h))continue;const C=d.getTextContent(),I=C.slice(0,u)+C.slice(s+1);d.setTextContent(I);const v=g===d?I:x;g.setTextContent(v.slice(0,h)+v.slice(h+l));const S=T(),y=b();w(y);const E=s-l*(g===d?2:1)+1;y.anchor.set(g.__key,h,"text"),y.focus.set(d.__key,E,"text");for(const t of n.format)y.formatText(t,N[t]);y.anchor.set(y.focus.key,y.focus.offset,y.focus.type);for(const t of n.format)y.hasFormat(t)&&y.toggleFormat(t);return f(S)&&(y.format=S.format),!0}return!1}(n,o,s)))(t,y,g.anchor.offset)&&v(S)})}}),t.registerCommand(y,t=>{if(null!==t&&t.shiftKey)return!1;const n=T();if(!f(n)||!n.isCollapsed())return!1;const s=n.anchor.offset,i=n.anchor.getNode();if(!e(i)||!Te(i))return!1;const l=i.getParent();return null!==l&&!M(l)&&!(s!==i.getTextContent().length||!Ne(l,i,s,r.multilineElement,!0)&&!we(l,i,s,o,!0)||(null!==t&&t.preventDefault(),0))},E))}function Re(t,e=ie,n,r=!1,o=!1){const s=r?t:le(t,o),i=n||u();i.clear(),Se(s,i,e,r),null!==T()&&i.selectStart()}function Be(t,e=ie,n=!1,r=!1){const o=n?t:le(t,r),s=new k;return Se(o,s,e,n),s.getChildren()}function _e(t=ie,e,n=!1){const r=function(t,e=!1){const n=Q(t),r=[...n.multilineElement,...n.element],o=!e,s=n.textFormat.filter(t=>1===t.format.length).sort((t,e)=>Number(t.format.includes("code"))-Number(e.format.includes("code")));return t=>{const i=[],l=(t||u()).getChildren();for(let t=0;t<l.length;t++){const c=l[t],f=ue(c,r,s,n.textMatch,e);null!=f&&i.push(o&&t>0&&!nt(c)&&!nt(l[t-1])?"\n".concat(f):f)}return i.join("\n")}}(t,n);return r(e)}function Le(t=ie,e,n=!1){if(!e||f(e)&&e.isCollapsed())return"";const r=function(t,e=!1){const n=Q(t),r=[...n.multilineElement,...n.element],o=!e,s=n.textFormat.filter(t=>1===t.format.length).sort((t,e)=>Number(t.format.includes("code"))-Number(e.format.includes("code")));return t=>{const i=t.getNodes(),l=t.clone();l.setCachedNodes(i),f(l)&&(l._cachedIsBackward=t.isBackward());const c=[];let a=null;for(const t of u().getChildren()){const{shouldInclude:i,markdown:f}=ce(t,l,r,s,n.textMatch,e);i&&null!=f&&(c.push(!o||null===a||nt(t)||nt(a)?f:"\n".concat(f)),a=t)}return c.join("\n")}}(t,n);return r(e)}export{Re as $convertFromMarkdownString,Le as $convertSelectionToMarkdownString,_e as $convertToMarkdownString,Be as $generateNodesFromMarkdownString,Xt as BOLD_ITALIC_STAR,Zt as BOLD_ITALIC_UNDERSCORE,Ht as BOLD_STAR,qt as BOLD_UNDERSCORE,Wt as CHECK_LIST,jt as CODE,ee as ELEMENT_TRANSFORMERS,Lt as HEADING,Dt as HIGHLIGHT,Ut as INLINE_CODE,Jt as ITALIC_STAR,Qt as ITALIC_UNDERSCORE,te as LINK,ne as MULTILINE_ELEMENT_TRANSFORMERS,Kt as ORDERED_LIST,At as QUOTE,Gt as STRIKETHROUGH,re as TEXT_FORMAT_TRANSFORMERS,oe as TEXT_MATCH_TRANSFORMERS,ie as TRANSFORMERS,zt as UNORDERED_LIST,mt as isTableRowDivider,Me as registerMarkdownShortcuts};
|
package/package.json
CHANGED
|
@@ -8,23 +8,23 @@
|
|
|
8
8
|
"markdown"
|
|
9
9
|
],
|
|
10
10
|
"license": "MIT",
|
|
11
|
-
"version": "0.53.0",
|
|
11
|
+
"version": "0.53.1-nightly.20261030.0",
|
|
12
12
|
"main": "./dist/LexicalMarkdown.js",
|
|
13
13
|
"types": "./dist/typescript-too-old.d.ts",
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@lexical/code-core": "0.53.0",
|
|
16
|
-
"@lexical/internal": "0.53.0",
|
|
17
|
-
"@lexical/link": "0.53.0",
|
|
18
|
-
"@lexical/list": "0.53.0",
|
|
19
|
-
"@lexical/rich-text": "0.53.0",
|
|
20
|
-
"@lexical/selection": "0.53.0",
|
|
21
|
-
"@lexical/text": "0.53.0",
|
|
22
|
-
"@lexical/utils": "0.53.0",
|
|
23
|
-
"lexical": "0.53.0"
|
|
15
|
+
"@lexical/code-core": "0.53.1-nightly.20261030.0",
|
|
16
|
+
"@lexical/internal": "0.53.1-nightly.20261030.0",
|
|
17
|
+
"@lexical/link": "0.53.1-nightly.20261030.0",
|
|
18
|
+
"@lexical/list": "0.53.1-nightly.20261030.0",
|
|
19
|
+
"@lexical/rich-text": "0.53.1-nightly.20261030.0",
|
|
20
|
+
"@lexical/selection": "0.53.1-nightly.20261030.0",
|
|
21
|
+
"@lexical/text": "0.53.1-nightly.20261030.0",
|
|
22
|
+
"@lexical/utils": "0.53.1-nightly.20261030.0",
|
|
23
|
+
"lexical": "0.53.1-nightly.20261030.0"
|
|
24
24
|
},
|
|
25
25
|
"repository": {
|
|
26
26
|
"type": "git",
|
|
27
|
-
"url": "git+https://github.com/
|
|
27
|
+
"url": "git+https://github.com/meta/lexical.git",
|
|
28
28
|
"directory": "packages/lexical-markdown"
|
|
29
29
|
},
|
|
30
30
|
"module": "./dist/LexicalMarkdown.js",
|
package/src/MarkdownExport.ts
CHANGED
|
@@ -13,11 +13,13 @@ import {
|
|
|
13
13
|
$isDecoratorNode,
|
|
14
14
|
$isElementNode,
|
|
15
15
|
$isLineBreakNode,
|
|
16
|
+
$isRangeSelection,
|
|
16
17
|
$isTextNode,
|
|
17
18
|
type BaseSelection,
|
|
18
19
|
type ElementNode,
|
|
19
20
|
type LexicalNode,
|
|
20
21
|
type LineBreakNode,
|
|
22
|
+
type NodeKey,
|
|
21
23
|
type TextFormatType,
|
|
22
24
|
type TextNode,
|
|
23
25
|
} from 'lexical';
|
|
@@ -111,7 +113,17 @@ export function createSelectionMarkdownExport(
|
|
|
111
113
|
);
|
|
112
114
|
});
|
|
113
115
|
|
|
114
|
-
return
|
|
116
|
+
return exportedSelection => {
|
|
117
|
+
// Every node asks whether it is selected, which reads the selection's
|
|
118
|
+
// nodes. A read-only selection doesn't cache them, so this works on a
|
|
119
|
+
// copy that does, instead of recomputing them for every node.
|
|
120
|
+
// Its direction is cached too, since slicing a node asks for it.
|
|
121
|
+
const nodes = exportedSelection.getNodes();
|
|
122
|
+
const selection = exportedSelection.clone();
|
|
123
|
+
selection.setCachedNodes(nodes);
|
|
124
|
+
if ($isRangeSelection(selection)) {
|
|
125
|
+
selection._cachedIsBackward = exportedSelection.isBackward();
|
|
126
|
+
}
|
|
115
127
|
const output = [];
|
|
116
128
|
// The separator depends on the previously *emitted* block, not on the
|
|
117
129
|
// previous root child: unselected children produce no output, so keying
|
|
@@ -212,14 +224,21 @@ function $processNodeForSelection(
|
|
|
212
224
|
}
|
|
213
225
|
}
|
|
214
226
|
|
|
227
|
+
interface OpenTag {
|
|
228
|
+
format: TextFormatType;
|
|
229
|
+
tag: string;
|
|
230
|
+
/** `$continuesTag`'s answers so far, by node key. */
|
|
231
|
+
answers: Map<NodeKey, boolean>;
|
|
232
|
+
}
|
|
233
|
+
|
|
215
234
|
function $exportChildrenForSelection(
|
|
216
235
|
node: ElementNode,
|
|
217
236
|
selection: BaseSelection,
|
|
218
237
|
textFormatTransformers: TextFormatTransformer[],
|
|
219
238
|
textMatchTransformers: TextMatchTransformer[],
|
|
220
239
|
shouldPreserveNewLines: boolean,
|
|
221
|
-
unclosedTags?:
|
|
222
|
-
unclosableTags?:
|
|
240
|
+
unclosedTags?: OpenTag[],
|
|
241
|
+
unclosableTags?: OpenTag[],
|
|
223
242
|
): {shouldInclude: boolean; markdown: string} {
|
|
224
243
|
const output = [];
|
|
225
244
|
const children = node.getChildren();
|
|
@@ -253,21 +272,16 @@ function $exportChildrenForSelection(
|
|
|
253
272
|
unclosedTags,
|
|
254
273
|
[...unclosableTags, ...unclosedTags],
|
|
255
274
|
).markdown,
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
selection,
|
|
259
|
-
textNode,
|
|
260
|
-
'clone',
|
|
261
|
-
);
|
|
262
|
-
return exportTextFormat(
|
|
275
|
+
textNode =>
|
|
276
|
+
$exportTextFormat(
|
|
263
277
|
textNode,
|
|
264
|
-
|
|
278
|
+
$exportedText(textNode, selection),
|
|
265
279
|
textFormatTransformers,
|
|
266
280
|
unclosedTags,
|
|
267
281
|
unclosableTags,
|
|
268
282
|
shouldPreserveNewLines,
|
|
269
|
-
|
|
270
|
-
|
|
283
|
+
selection,
|
|
284
|
+
),
|
|
271
285
|
);
|
|
272
286
|
|
|
273
287
|
if (result != null) {
|
|
@@ -295,15 +309,15 @@ function $exportChildrenForSelection(
|
|
|
295
309
|
}
|
|
296
310
|
} else if ($isTextNode(child)) {
|
|
297
311
|
if (childIncluded) {
|
|
298
|
-
const target = $sliceSelectedTextNodeContent(selection, child, 'clone');
|
|
299
312
|
output.push(
|
|
300
|
-
exportTextFormat(
|
|
313
|
+
$exportTextFormat(
|
|
301
314
|
child,
|
|
302
|
-
|
|
315
|
+
$exportedText(child, selection),
|
|
303
316
|
textFormatTransformers,
|
|
304
317
|
unclosedTags,
|
|
305
318
|
unclosableTags,
|
|
306
319
|
shouldPreserveNewLines,
|
|
320
|
+
selection,
|
|
307
321
|
),
|
|
308
322
|
);
|
|
309
323
|
anyChildIncluded = true;
|
|
@@ -390,8 +404,8 @@ function $exportChildren(
|
|
|
390
404
|
node: ElementNode,
|
|
391
405
|
textTransformersIndex: TextFormatTransformer[],
|
|
392
406
|
textMatchTransformers: TextMatchTransformer[],
|
|
393
|
-
unclosedTags?:
|
|
394
|
-
unclosableTags?:
|
|
407
|
+
unclosedTags?: OpenTag[],
|
|
408
|
+
unclosableTags?: OpenTag[],
|
|
395
409
|
shouldPreserveNewLines: boolean = false,
|
|
396
410
|
): string {
|
|
397
411
|
const output = [];
|
|
@@ -427,13 +441,14 @@ function $exportChildren(
|
|
|
427
441
|
shouldPreserveNewLines,
|
|
428
442
|
),
|
|
429
443
|
(textNode, textContent) =>
|
|
430
|
-
exportTextFormat(
|
|
444
|
+
$exportTextFormat(
|
|
431
445
|
textNode,
|
|
432
446
|
textContent,
|
|
433
447
|
textTransformersIndex,
|
|
434
448
|
unclosedTags,
|
|
435
449
|
unclosableTags,
|
|
436
450
|
shouldPreserveNewLines,
|
|
451
|
+
null,
|
|
437
452
|
),
|
|
438
453
|
);
|
|
439
454
|
|
|
@@ -447,13 +462,14 @@ function $exportChildren(
|
|
|
447
462
|
output.push($exportLineBreak(child));
|
|
448
463
|
} else if ($isTextNode(child)) {
|
|
449
464
|
output.push(
|
|
450
|
-
exportTextFormat(
|
|
465
|
+
$exportTextFormat(
|
|
451
466
|
child,
|
|
452
467
|
child.getTextContent(),
|
|
453
468
|
textTransformersIndex,
|
|
454
469
|
unclosedTags,
|
|
455
470
|
unclosableTags,
|
|
456
471
|
shouldPreserveNewLines,
|
|
472
|
+
null,
|
|
457
473
|
),
|
|
458
474
|
);
|
|
459
475
|
} else if ($isElementNode(child)) {
|
|
@@ -480,20 +496,20 @@ function $exportLineBreak(node: LineBreakNode): string {
|
|
|
480
496
|
return $getState(node, hardLineBreakState) + '\n';
|
|
481
497
|
}
|
|
482
498
|
|
|
483
|
-
function exportTextFormat(
|
|
499
|
+
function $exportTextFormat(
|
|
484
500
|
node: TextNode,
|
|
485
501
|
textContent: string,
|
|
486
502
|
textTransformers: TextFormatTransformer[],
|
|
487
503
|
// unclosed tags include the markdown tags that haven't been closed yet, and their associated formats
|
|
488
|
-
unclosedTags:
|
|
489
|
-
unclosableTags
|
|
490
|
-
shouldPreserveNewLines: boolean
|
|
504
|
+
unclosedTags: OpenTag[],
|
|
505
|
+
unclosableTags: OpenTag[],
|
|
506
|
+
shouldPreserveNewLines: boolean,
|
|
507
|
+
// the selection being exported, which ends the text a tag can extend over
|
|
508
|
+
selection: BaseSelection | null,
|
|
491
509
|
): string {
|
|
492
510
|
// This function handles the case of a string looking like this: " foo "
|
|
493
511
|
// Where it would be invalid markdown to generate: "** foo **"
|
|
494
|
-
//
|
|
495
|
-
// Otherwise, we escape leading and trailing whitespaces to their corresponding code points,
|
|
496
|
-
// ensuring the returned string maintains its original formatting, e.g., "**   foo   **".
|
|
512
|
+
// so the tags go inside the whitespace instead: " **foo** ".
|
|
497
513
|
|
|
498
514
|
const isCode = node.hasFormat('code');
|
|
499
515
|
|
|
@@ -512,28 +528,7 @@ function exportTextFormat(
|
|
|
512
528
|
);
|
|
513
529
|
}
|
|
514
530
|
|
|
515
|
-
|
|
516
|
-
let trimmedOutput: string;
|
|
517
|
-
let trailingSpace: string;
|
|
518
|
-
let isWhitespaceOnly: boolean;
|
|
519
|
-
|
|
520
|
-
if (isCode) {
|
|
521
|
-
// Inline code is an atomic literal span with a content-derived fence, so
|
|
522
|
-
// its whitespace stays inside the fence and other formats wrap around it.
|
|
523
|
-
const {fence, padded} = getCodeSpanDelimiter(textContent);
|
|
524
|
-
leadingSpace = '';
|
|
525
|
-
trailingSpace = '';
|
|
526
|
-
trimmedOutput = fence + padded + fence;
|
|
527
|
-
isWhitespaceOnly = false;
|
|
528
|
-
} else {
|
|
529
|
-
// Extract leading and trailing whitespaces.
|
|
530
|
-
// CommonMark flanking rules require formatting tags to be adjacent to non-whitespace characters.
|
|
531
|
-
const match = output.match(/^(\s*)(.*?)(\s*)$/s) || ['', '', output, ''];
|
|
532
|
-
leadingSpace = match[1];
|
|
533
|
-
trimmedOutput = match[2];
|
|
534
|
-
trailingSpace = match[3];
|
|
535
|
-
isWhitespaceOnly = trimmedOutput === '';
|
|
536
|
-
}
|
|
531
|
+
const holdsTag = canHoldTag(textContent);
|
|
537
532
|
|
|
538
533
|
// the opening tags to be added to the result
|
|
539
534
|
let openingTags = '';
|
|
@@ -542,7 +537,6 @@ function exportTextFormat(
|
|
|
542
537
|
let closingTagsAfter = '';
|
|
543
538
|
|
|
544
539
|
const prevNode = getTextSibling(node, true);
|
|
545
|
-
const nextNode = getTextSibling(node, false);
|
|
546
540
|
|
|
547
541
|
const applied = new Set();
|
|
548
542
|
|
|
@@ -550,32 +544,24 @@ function exportTextFormat(
|
|
|
550
544
|
const format = transformer.format[0];
|
|
551
545
|
const tag = transformer.tag;
|
|
552
546
|
|
|
553
|
-
// Inline code uses a content-derived fence handled
|
|
547
|
+
// Inline code uses a content-derived fence handled below, not a static tag.
|
|
554
548
|
if (format === 'code') {
|
|
555
549
|
continue;
|
|
556
550
|
}
|
|
557
551
|
|
|
558
552
|
// dedup applied formats
|
|
559
|
-
|
|
560
|
-
// exported may be a selection slice of it. When the slice is entirely
|
|
561
|
-
// whitespace the tags are dropped by the early return below, so
|
|
562
|
-
// registering them here would leave an unclosed tag for a later node to
|
|
563
|
-
// close. In the full-document path `checkHasFormat` already rejects
|
|
564
|
-
// whitespace-only nodes, so this guard only affects sliced content.
|
|
565
|
-
if (
|
|
566
|
-
!isWhitespaceOnly &&
|
|
567
|
-
checkHasFormat(node, format) &&
|
|
568
|
-
!applied.has(format)
|
|
569
|
-
) {
|
|
553
|
+
if (holdsTag && node.hasFormat(format) && !applied.has(format)) {
|
|
570
554
|
applied.add(format);
|
|
571
555
|
|
|
572
556
|
// append the tag to openingTags, if it's not applied to the previous nodes,
|
|
573
|
-
// or the nodes before that (which would result in an unclosed tag)
|
|
557
|
+
// or the nodes before that (which would result in an unclosed tag).
|
|
558
|
+
// A whitespace-only previous node with the format keeps the tag open
|
|
559
|
+
// without emitting it, so it counts as applied here.
|
|
574
560
|
if (
|
|
575
|
-
!
|
|
561
|
+
!hasFormat(prevNode, format) ||
|
|
576
562
|
!unclosedTags.find(element => element.tag === tag)
|
|
577
563
|
) {
|
|
578
|
-
unclosedTags.push({format, tag});
|
|
564
|
+
unclosedTags.push({answers: new Map(), format, tag});
|
|
579
565
|
openingTags += tag;
|
|
580
566
|
}
|
|
581
567
|
}
|
|
@@ -584,10 +570,8 @@ function exportTextFormat(
|
|
|
584
570
|
// close any tags in the same order they were applied, if necessary
|
|
585
571
|
for (let i = 0; i < unclosedTags.length; i++) {
|
|
586
572
|
const nodeHasFormat = hasFormat(node, unclosedTags[i].format);
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
// prevent adding closing tag if next sibling will do it
|
|
590
|
-
if (nodeHasFormat && nextNodeHasFormat) {
|
|
573
|
+
// prevent adding closing tag if later text with the format will do it
|
|
574
|
+
if (nodeHasFormat && $continuesTag(node, unclosedTags[i], selection)) {
|
|
591
575
|
continue;
|
|
592
576
|
}
|
|
593
577
|
|
|
@@ -599,7 +583,6 @@ function exportTextFormat(
|
|
|
599
583
|
// If tag is unclosable, don't close it and leave it in the original array,
|
|
600
584
|
// So that it can be closed when it's no longer unclosable
|
|
601
585
|
if (
|
|
602
|
-
unclosableTags &&
|
|
603
586
|
unclosedTag &&
|
|
604
587
|
unclosableTags.find(element => element.tag === unclosedTag.tag)
|
|
605
588
|
) {
|
|
@@ -611,7 +594,7 @@ function exportTextFormat(
|
|
|
611
594
|
// Handles cases where the tag has not been closed before, e.g. if the previous node
|
|
612
595
|
// was a text match transformer that did not account for closing tags of the next node (e.g. a link)
|
|
613
596
|
closingTagsBefore += unclosedTag.tag;
|
|
614
|
-
} else
|
|
597
|
+
} else {
|
|
615
598
|
closingTagsAfter += unclosedTag.tag;
|
|
616
599
|
}
|
|
617
600
|
}
|
|
@@ -620,13 +603,25 @@ function exportTextFormat(
|
|
|
620
603
|
}
|
|
621
604
|
break;
|
|
622
605
|
}
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
606
|
+
if (isCode && textContent !== '') {
|
|
607
|
+
// Inline code is an atomic literal span with a content-derived fence, so
|
|
608
|
+
// its whitespace stays inside the fence and other formats wrap around it.
|
|
609
|
+
const {fence, padded} = getCodeSpanDelimiter(textContent);
|
|
610
|
+
output = fence + padded + fence;
|
|
611
|
+
} else if (!holdsTag) {
|
|
612
|
+
// If the node is entirely whitespace, we don't apply opening/closing tags
|
|
613
|
+
// around it, but it must still output any closing tags.
|
|
614
|
+
return closingTagsBefore + closingTagsAfter + output;
|
|
627
615
|
}
|
|
628
616
|
|
|
629
|
-
// Flanking Compliance:
|
|
617
|
+
// Flanking Compliance: CommonMark flanking rules require formatting tags to be
|
|
618
|
+
// adjacent to non-whitespace characters, so openingTags and closingTagsAfter
|
|
619
|
+
// are placed INSIDE the whitespace boundaries!
|
|
620
|
+
// (Trimming rather than a regex keeps this linear in long whitespace runs.)
|
|
621
|
+
const trimmedStart = output.trimStart();
|
|
622
|
+
const trimmedOutput = trimmedStart.trimEnd();
|
|
623
|
+
const leadingSpace = output.slice(0, output.length - trimmedStart.length);
|
|
624
|
+
const trailingSpace = trimmedStart.slice(trimmedOutput.length);
|
|
630
625
|
return (
|
|
631
626
|
closingTagsBefore +
|
|
632
627
|
leadingSpace +
|
|
@@ -647,6 +642,64 @@ function getTextSibling(node: TextNode, backward: boolean): TextNode | null {
|
|
|
647
642
|
return null;
|
|
648
643
|
}
|
|
649
644
|
|
|
645
|
+
/**
|
|
646
|
+
* Whether `tag` carries on past `node`, which has its format, to exported
|
|
647
|
+
* text that can hold it. Whitespace-only siblings cannot (the tag must close
|
|
648
|
+
* before the space), so they are looked past while they keep the format.
|
|
649
|
+
* Text outside the exported selection does not count. Every whitespace node
|
|
650
|
+
* the walk passes over shares its answer, so that is remembered on the tag
|
|
651
|
+
* and each run is walked once, whatever order its nodes are asked in.
|
|
652
|
+
*/
|
|
653
|
+
function $continuesTag(
|
|
654
|
+
node: TextNode,
|
|
655
|
+
tag: OpenTag,
|
|
656
|
+
selection: BaseSelection | null,
|
|
657
|
+
): boolean {
|
|
658
|
+
const {answers} = tag;
|
|
659
|
+
const known = answers.get(node.getKey());
|
|
660
|
+
if (known !== undefined) {
|
|
661
|
+
return known;
|
|
662
|
+
}
|
|
663
|
+
const passed: TextNode[] = [];
|
|
664
|
+
let next = getTextSibling(node, false);
|
|
665
|
+
let result = false;
|
|
666
|
+
while (
|
|
667
|
+
next &&
|
|
668
|
+
next.hasFormat(tag.format) &&
|
|
669
|
+
(!selection || next.isSelected(selection))
|
|
670
|
+
) {
|
|
671
|
+
const text = $exportedText(next, selection);
|
|
672
|
+
if (canHoldTag(text)) {
|
|
673
|
+
result = true;
|
|
674
|
+
break;
|
|
675
|
+
}
|
|
676
|
+
// Markdown import matches a tag within one line.
|
|
677
|
+
if (text.includes('\n')) {
|
|
678
|
+
break;
|
|
679
|
+
}
|
|
680
|
+
// A whitespace node already answered for shares the answer.
|
|
681
|
+
const passedAnswer = answers.get(next.getKey());
|
|
682
|
+
if (passedAnswer !== undefined) {
|
|
683
|
+
result = passedAnswer;
|
|
684
|
+
break;
|
|
685
|
+
}
|
|
686
|
+
passed.push(next);
|
|
687
|
+
next = getTextSibling(next, false);
|
|
688
|
+
}
|
|
689
|
+
answers.set(node.getKey(), result);
|
|
690
|
+
for (const passedNode of passed) {
|
|
691
|
+
answers.set(passedNode.getKey(), result);
|
|
692
|
+
}
|
|
693
|
+
return result;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/** The text of `node` that the export emits: its selected slice, if any. */
|
|
697
|
+
function $exportedText(node: TextNode, selection: BaseSelection | null) {
|
|
698
|
+
return selection
|
|
699
|
+
? $sliceSelectedTextNodeContent(selection, node, 'clone').getTextContent()
|
|
700
|
+
: node.getTextContent();
|
|
701
|
+
}
|
|
702
|
+
|
|
650
703
|
function hasFormat(
|
|
651
704
|
node: LexicalNode | null | undefined,
|
|
652
705
|
format: TextFormatType,
|
|
@@ -654,15 +707,10 @@ function hasFormat(
|
|
|
654
707
|
return $isTextNode(node) && node.hasFormat(format);
|
|
655
708
|
}
|
|
656
709
|
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
}
|
|
664
|
-
if (n && /^\s*$/.test(n.getTextContent())) {
|
|
665
|
-
return false;
|
|
666
|
-
}
|
|
667
|
-
return true;
|
|
710
|
+
/**
|
|
711
|
+
* Whether exported text can carry a format's tag: CommonMark flanking rules
|
|
712
|
+
* keep tags off whitespace.
|
|
713
|
+
*/
|
|
714
|
+
function canHoldTag(text: string): boolean {
|
|
715
|
+
return /\S/.test(text);
|
|
668
716
|
}
|
|
@@ -1096,10 +1096,12 @@ export function getCodeSpanDelimiter(content: string): {
|
|
|
1096
1096
|
? Math.max(...backtickRuns.map(run => run.length))
|
|
1097
1097
|
: 0;
|
|
1098
1098
|
const fence = '`'.repeat(longestRun + 1);
|
|
1099
|
+
// A reader strips one space from each end only when the content is not all
|
|
1100
|
+
// spaces, so content made only of spaces goes out as it is.
|
|
1099
1101
|
const needsPadding =
|
|
1100
1102
|
content.length === 0 ||
|
|
1101
1103
|
content.includes('`') ||
|
|
1102
|
-
(/^\s/.test(content) && /\s$/.test(content));
|
|
1104
|
+
(/^\s/.test(content) && /\s$/.test(content) && /[^ ]/.test(content));
|
|
1103
1105
|
const padded = needsPadding ? ` ${content} ` : content;
|
|
1104
1106
|
return {fence, padded};
|
|
1105
1107
|
}
|
|
@@ -1155,17 +1157,40 @@ export const ITALIC_UNDERSCORE: TextFormatTransformer = {
|
|
|
1155
1157
|
type: 'text-format',
|
|
1156
1158
|
};
|
|
1157
1159
|
|
|
1158
|
-
//
|
|
1159
|
-
//
|
|
1160
|
-
//
|
|
1161
|
-
//
|
|
1162
|
-
//
|
|
1163
|
-
//
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1160
|
+
// A raw link destination cannot hold an ASCII control character or a space in
|
|
1161
|
+
// CommonMark, nor any Unicode whitespace in the raw branch of `LINK`'s import
|
|
1162
|
+
// patterns, so export writes a URL with any of them in the pointy form. Import
|
|
1163
|
+
// still reads control characters in a raw destination, as older exports wrote
|
|
1164
|
+
// them there. A NUL reads back as U+FFFD in a CommonMark reader whichever form
|
|
1165
|
+
// it is in, since no spelling of it avoids that.
|
|
1166
|
+
// eslint-disable-next-line no-control-regex
|
|
1167
|
+
const NOT_RAW_DESTINATION = /[\s\0-\x1f\x7f]/;
|
|
1168
|
+
|
|
1169
|
+
// A link destination or title is read back through `unescapeText`, which
|
|
1170
|
+
// decodes a numeric character reference, and a CommonMark reader decodes the
|
|
1171
|
+
// named ones too. So an `&` that begins one goes out as `&`, or the part
|
|
1172
|
+
// would come back as the character the reference names. An `&` that begins
|
|
1173
|
+
// nothing is an ordinary character and stays as it is, so a query string keeps
|
|
1174
|
+
// the separators it was written with.
|
|
1175
|
+
//
|
|
1176
|
+
// Then every match of `syntax`, a global regular expression for the characters
|
|
1177
|
+
// the part's shape treats as syntax, gets a backslash. So does a backtick: this
|
|
1178
|
+
// package's importer reads code spans before links, so one anywhere in the
|
|
1179
|
+
// link could pair with one in the text after it and swallow the link, although
|
|
1180
|
+
// a CommonMark reader would not let it.
|
|
1181
|
+
//
|
|
1182
|
+
// Neither part may hold a line ending either. CommonMark allows none in a
|
|
1183
|
+
// destination and no blank line in a title, where two CRs make one as surely
|
|
1184
|
+
// as two LFs, and the importer reads one LF-separated line at a time, so even
|
|
1185
|
+
// a single LF would split the link. Each goes out as the character reference
|
|
1186
|
+
// that `unescapeText` and a CommonMark reader both turn back into the line
|
|
1187
|
+
// ending, written after the `&` escape so that one leaves it alone.
|
|
1188
|
+
function escapeLinkPart(value: string, syntax: RegExp): string {
|
|
1189
|
+
return value
|
|
1190
|
+
.replace(/&(?=#\d+;|#[Xx][\dA-Fa-f]+;|[A-Za-z][\dA-Za-z]*;)/g, '&')
|
|
1191
|
+
.replace(syntax, '\\$&')
|
|
1192
|
+
.replace(/`/g, '\\`')
|
|
1193
|
+
.replace(/[\r\n]/g, lineEnding => `&#${lineEnding.charCodeAt(0)};`);
|
|
1169
1194
|
}
|
|
1170
1195
|
|
|
1171
1196
|
// Mask escaped/code brackets without changing source offsets, then find an inner
|
|
@@ -1223,43 +1248,24 @@ export const LINK: TextMatchTransformer = {
|
|
|
1223
1248
|
return null;
|
|
1224
1249
|
}
|
|
1225
1250
|
const textContent = exportChildren(node);
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
// A
|
|
1229
|
-
//
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
//
|
|
1235
|
-
// written in the pointy form, where only `<`, `>` and a backslash need an
|
|
1236
|
-
// escape. An empty URL goes there too, since the raw form has nothing left
|
|
1237
|
-
// to match. Everywhere else the destination is written raw, where a
|
|
1238
|
-
// parenthesis would close it early, a backslash would start an escape, and
|
|
1239
|
-
// only a `<` in first place turns it into the pointy form. An angle
|
|
1240
|
-
// bracket anywhere else is an ordinary character and goes out as it is.
|
|
1241
|
-
//
|
|
1242
|
-
// Neither shape may hold a line ending, so a literal one would leave a
|
|
1243
|
-
// destination that no reader can close and would split the paragraph in
|
|
1244
|
-
// two. It goes out as the character reference that `unescapeText` and a
|
|
1245
|
-
// CommonMark reader both turn back into the line ending.
|
|
1246
|
-
//
|
|
1247
|
-
// That spelling only survives because a reader decodes it, so an `&` that
|
|
1248
|
-
// already begins a character reference has to go out as one itself, or the
|
|
1249
|
-
// URL comes back as whatever the reference names. Escaping it first keeps
|
|
1250
|
-
// the references written for the line endings below out of its way.
|
|
1251
|
+
const title = node.getTitle();
|
|
1252
|
+
|
|
1253
|
+
// A URL that `NOT_RAW_DESTINATION` matches goes in the pointy form, where
|
|
1254
|
+
// `<`, `>` and a backslash are syntax. An empty URL goes there too, since
|
|
1255
|
+
// the raw form has nothing left to match. Everywhere else the destination
|
|
1256
|
+
// is written raw, where a parenthesis would close it early, a backslash
|
|
1257
|
+
// would start an escape, and only a `<` in first place turns it into the
|
|
1258
|
+
// pointy form. An angle bracket anywhere else is an ordinary character and
|
|
1259
|
+
// goes out as it is.
|
|
1251
1260
|
const rawUrl = node.getURL();
|
|
1252
|
-
const escapedUrl = escapeCharacterReferences(rawUrl);
|
|
1253
1261
|
const url =
|
|
1254
|
-
rawUrl === '' ||
|
|
1255
|
-
? `<${
|
|
1256
|
-
|
|
1257
|
-
.replace(/\r/g, ' ')
|
|
1258
|
-
.replace(/\n/g, ' ')}>`
|
|
1259
|
-
: escapedUrl.replace(/([\\()])/g, '\\$1').replace(/^</, '\\<');
|
|
1262
|
+
rawUrl === '' || NOT_RAW_DESTINATION.test(rawUrl)
|
|
1263
|
+
? `<${escapeLinkPart(rawUrl, /[\\<>]/g)}>`
|
|
1264
|
+
: escapeLinkPart(rawUrl, /[\\()]|^</g);
|
|
1260
1265
|
|
|
1266
|
+
// In the double-quoted title only `"` and a backslash are syntax.
|
|
1261
1267
|
const linkContent = title
|
|
1262
|
-
? `[${textContent}](${url} "${title}")`
|
|
1268
|
+
? `[${textContent}](${url} "${escapeLinkPart(title, /[\\"]/g)}")`
|
|
1263
1269
|
: `[${textContent}](${url})`;
|
|
1264
1270
|
|
|
1265
1271
|
return linkContent;
|
|
@@ -1292,9 +1298,9 @@ export const LINK: TextMatchTransformer = {
|
|
|
1292
1298
|
// are characters, which costs a quadratic walk of every run that never
|
|
1293
1299
|
// reaches the closing parenthesis.
|
|
1294
1300
|
importRegExp:
|
|
1295
|
-
/(?:\[(.+?)\])(?:\(\s*(?:(?:<((
|
|
1301
|
+
/(?:\[(.+?)\])(?:\(\s*(?:(?:<((?:\\[^\n\r]|[^<>\n\r\\])*)>|((?!<)(?:\\[^\s]|\\(?=\s)|\((?:\\[^\s]|[^\s()\\]|\((?:\\[^\s]|[^\s()\\]|\((?:\\[^\s]|[^\s()\\])*\))*\))*\)|[^\s()\\])+))(?:\s+(?:"((?:\\[\s\S]|[^"\\])*)"|'((?:\\[\s\S]|[^'\\])*)'|\(((?:\\[\s\S]|[^()\\])*)\)))?\s*)?\))/,
|
|
1296
1302
|
regExp:
|
|
1297
|
-
/(?:\[([^[\]]*(?:\[[^[\]]*\][^[\]]*)*)\])(?:\(\s*(?:(?:<((
|
|
1303
|
+
/(?:\[([^[\]]*(?:\[[^[\]]*\][^[\]]*)*)\])(?:\(\s*(?:(?:<((?:\\[^\n\r]|[^<>\n\r\\])*)>|((?!<)(?:\\[^\s]|\\(?=\s)|\((?:\\[^\s]|[^\s()\\]|\((?:\\[^\s]|[^\s()\\]|\((?:\\[^\s]|[^\s()\\])*\))*\))*\)|[^\s()\\])+))(?:\s+(?:"((?:\\[\s\S]|[^"\\])*)"|'((?:\\[\s\S]|[^'\\])*)'|\(((?:\\[\s\S]|[^()\\])*)\)))?\s*)?\))$/,
|
|
1298
1304
|
replace: (textNode, match) => {
|
|
1299
1305
|
// https://spec.commonmark.org/0.31.2/#inline-link
|
|
1300
1306
|
const source = match.input || '';
|
|
@@ -59,7 +59,7 @@ export function importTextTransformers(
|
|
|
59
59
|
// or links). A code span must never be partially consumed by a text
|
|
60
60
|
// match, so prefer the code format unless the text match fully wraps it
|
|
61
61
|
// (in which case the code span is part of the match's raw content).
|
|
62
|
-
// https://github.com/
|
|
62
|
+
// https://github.com/meta/lexical/issues/8687
|
|
63
63
|
if (
|
|
64
64
|
foundTextMatch.startIndex <= foundTextFormat.startIndex &&
|
|
65
65
|
foundTextMatch.endIndex >= foundTextFormat.endIndex
|