onchain-lexical-markdown 0.0.13 → 0.0.15

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.
@@ -9,13 +9,15 @@
9
9
  import { $isListNode, $isListItemNode, ListNode, ListItemNode } from '@lexical/list';
10
10
  import { $isQuoteNode, QuoteNode, HeadingNode, $isHeadingNode } from '@lexical/rich-text';
11
11
  import { $findMatchingParent } from '@lexical/utils';
12
- import { $isParagraphNode, $isTextNode, $getRoot, $isRootNode, $getSelection, $createTextNode, $createLineBreakNode, $isElementNode, $isDecoratorNode, $isLineBreakNode, createEditor, exportNodeToJSON, COLLABORATION_TAG, HISTORIC_TAG, $isRangeSelection, $isRootOrShadowRoot, $createRangeSelection, $setSelection } from 'lexical';
13
- import { $createInstanceParagraphNode, $createInstanceListItemNode, $createInstanceListNode, $createInstanceHeadingNode, $createInstanceQuoteNode, $createInstanceCodeNode, InstanceEquationNode, $createInstanceEquationNode, $isInstanceEquationNode, $createInstanceHorizontalRuleNode, $isBarDecoratorNode, $isNumberDecoratorNode, $createInstanceTableNode, $createFragmentNode, ImageNode, $createImageNode, $isImageNode, InstanceNode, InstanceHeadingNode, InstanceTitleNode, InstanceParagraphNode, $createTitleOnlyInstanceNode, $isInstanceNode, correctedInstanceParagraph, $isInstanceParagraphNode, $isInstanceHeadingNode, $isInstanceTitleNode, PageBreakNode, $createPageBreakNode, $isPageBreakNode } from 'onchain-lexical-instance';
12
+ import { $isParagraphNode, $isTextNode, $getRoot, $isRootNode, $getSelection, $createTextNode, $createLineBreakNode, $isElementNode, $isDecoratorNode, $isLineBreakNode, TEXT_TYPE_TO_FORMAT, createEditor, exportNodeToJSON, COLLABORATION_TAG, HISTORIC_TAG, $isRangeSelection, $isRootOrShadowRoot, $createRangeSelection, $setSelection } from 'lexical';
13
+ import { $createInstanceParagraphNode, $createInstanceListItemNode, $createInstanceListNode, $createInstanceHeadingNode, $createInstanceQuoteNode, $createInstanceCodeNode, InstanceEquationNode, $createInstanceEquationNode, $isInstanceEquationNode, $createInstanceHorizontalRuleNode, $isBarDecoratorNode, $isNumberDecoratorNode, $createInstanceTableNode, $createCollapsibleContainerNode, $createCollapsibleTitleNode, $createCollapsibleContentNode, $createPageBreakNode, $createInternalLinkNode, $createParametersNode, $createFragmentNode, $createImageNode, $isImageNode, ImageNode, InstanceNode, InstanceHeadingNode, InstanceTitleNode, InstanceParagraphNode, $createTitleOnlyInstanceNode, $isInstanceNode, correctedInstanceParagraph, $isInstanceParagraphNode, $isInstanceHeadingNode, $isInstanceTitleNode, PageBreakNode, $isPageBreakNode } from 'onchain-lexical-instance';
14
14
  import { CodeNode, $isCodeNode } from '@lexical/code';
15
15
  import { LinkNode, $createLinkNode, $isLinkNode } from '@lexical/link';
16
16
  import { HorizontalRuleNode, $isHorizontalRuleNode } from '@lexical/react/LexicalHorizontalRuleNode';
17
17
  import { getStyleObjectFromCSS } from '@lexical/selection';
18
18
  import { $createTableRowNode, $createTableCellNode, TableCellHeaderStates, TableNode, TableRowNode, TableCellNode, $isTableNode, $isTableRowNode, $isTableCellNode } from '@lexical/table';
19
+ import { dfs } from 'onchain-utility';
20
+ import { fromBase64UTF8 } from 'onchain-utility/base64';
19
21
  import { $advanceParseSerializedNode } from '@lexical/file';
20
22
 
21
23
  /**
@@ -1181,6 +1183,80 @@ function $convertToMarkdownString(transformers = TransFormerGather.value, node,
1181
1183
  *
1182
1184
  */
1183
1185
 
1186
+ function getHtmlTagAttrValue(tagStart, attrName) {
1187
+ const match = tagStart.match(new RegExp(`${attrName}=("|')(.*?)\\1`)) || [];
1188
+ return match[2];
1189
+ }
1190
+ // 简化的解析器
1191
+ function parseHtmlToCustomStructure(htmlString) {
1192
+ const parser = new DOMParser();
1193
+ const doc = parser.parseFromString(htmlString, 'text/html');
1194
+ function processNode(node) {
1195
+ // 处理文本节点
1196
+ if (node.nodeType === Node.TEXT_NODE) {
1197
+ const text = node.textContent;
1198
+ return text ? {
1199
+ children: [],
1200
+ content: text,
1201
+ dom: node,
1202
+ tag: 'text'
1203
+ } : null;
1204
+ }
1205
+
1206
+ // 处理元素节点
1207
+ if (node.nodeType === Node.ELEMENT_NODE) {
1208
+ const tagName = node.tagName.toLowerCase();
1209
+ const children = [];
1210
+
1211
+ // 处理子节点
1212
+ for (const child of node.childNodes) {
1213
+ const childResult = processNode(child);
1214
+ if (childResult) {
1215
+ children.push(childResult);
1216
+ }
1217
+ }
1218
+
1219
+ // 获取元素内容(不包含子元素的纯文本内容)
1220
+ const textContent = Array.from(node.childNodes).filter(n => n.nodeType === Node.TEXT_NODE).map(n => n.textContent).filter(text => text.length > 0).join(' ');
1221
+ return {
1222
+ children: children,
1223
+ content: textContent || node.textContent || '',
1224
+ dom: node,
1225
+ tag: tagName
1226
+ };
1227
+ }
1228
+ return null;
1229
+ }
1230
+
1231
+ // 处理文档中的主要元素
1232
+ const result = [];
1233
+ const bodyChildren = Array.from(doc.body.children);
1234
+ for (const element of bodyChildren) {
1235
+ const processed = processNode(element);
1236
+ if (processed) {
1237
+ result.push(processed);
1238
+ }
1239
+ }
1240
+ return result;
1241
+ }
1242
+
1243
+ /** html 标签分块单行排列 */
1244
+ function htmlTagSingleLine(htmlString) {
1245
+ const parser = new DOMParser();
1246
+ const doc = parser.parseFromString(htmlString, 'text/html');
1247
+ return Array.from(doc.body.children).map(element => {
1248
+ return element.outerHTML.replace(/(>)\s+(<)/g, '$1$2');
1249
+ }).join('\n');
1250
+ }
1251
+
1252
+ /**
1253
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
1254
+ *
1255
+ * This source code is licensed under the MIT license found in the
1256
+ * LICENSE file in the root directory of this source tree.
1257
+ *
1258
+ */
1259
+ const interval = '{-|-}';
1184
1260
  const HTML_TABLE_START = /^[\u0020\t]*<table.*?>/;
1185
1261
  const HTML_TABLE_END = /[\u0020\t]*<\/table>$/;
1186
1262
  const SINGLE_LINE_ROW_STYLES = /<tr.*?style=(["|'](.+?)["|']).*?>/;
@@ -1264,10 +1340,10 @@ const HTML_TABLE = {
1264
1340
 
1265
1341
  const HTML_PARAGRAPH_TRANSFORMER = [{
1266
1342
  end: /[\u0020\t]*<\/p>$/,
1267
- start: /[\u0020\t]*<p.*?>/
1343
+ start: /^[\u0020\t]*<p[^a-z]+(?:[^>]*?)>/
1268
1344
  }, {
1269
1345
  end: /[\u0020\t]*<\/div>$/,
1270
- start: /[\u0020\t]*<div.*?>/
1346
+ start: /^[\u0020\t]*<div(?:[^>]*?)>/
1271
1347
  }].map(({
1272
1348
  start,
1273
1349
  end
@@ -1275,23 +1351,296 @@ const HTML_PARAGRAPH_TRANSFORMER = [{
1275
1351
  return {
1276
1352
  dependencies: [],
1277
1353
  regExpEnd: {
1354
+ optional: true,
1278
1355
  regExp: end
1279
1356
  },
1280
1357
  regExpStart: start,
1281
1358
  replace: (rootNode, children, startMatch, endMatch, linesInBetween) => {
1282
1359
  if (linesInBetween) {
1283
1360
  const context = linesInBetween.join('\n');
1284
- const paragraph = $createInstanceParagraphNode();
1285
- $convertFromMarkdownString(context, TransFormerGather.value, paragraph);
1361
+ // console.log('PARAGRAPH CONTEXT', context);
1362
+ const paragraph = optimizeNesting($createInstanceParagraphNode(), context);
1286
1363
  rootNode.append(paragraph);
1287
1364
  }
1288
1365
  },
1289
1366
  type: 'multiline-element'
1290
1367
  };
1291
1368
  });
1369
+ const HTML_LIST_TRANSFORMER = [...[{
1370
+ end: /[\u0020\t]*<\/ul>$/,
1371
+ start: /^[\u0020\t]*<ul(?:[^>]*?)>/
1372
+ }, {
1373
+ end: /[\u0020\t]*<\/ol>$/,
1374
+ start: /^[\u0020\t]*<ol(?:[^>]*?)>/
1375
+ }].map(({
1376
+ start,
1377
+ end
1378
+ }) => {
1379
+ const TRANSFORMER = {
1380
+ dependencies: [],
1381
+ regExpEnd: {
1382
+ optional: true,
1383
+ regExp: end
1384
+ },
1385
+ regExpStart: start,
1386
+ replace: (rootNode, children, startMatch, endMatch, linesInBetween) => {
1387
+ // console.log('LIST', linesInBetween);
1388
+ const type = getHtmlTagAttrValue(startMatch[0], 'list-type') || 'bullet';
1389
+ if (linesInBetween) {
1390
+ const context = linesInBetween.join('\n');
1391
+ const list = $createInstanceListNode(type);
1392
+ $convertFromMarkdownString(context, TransFormerGather.value, list);
1393
+ rootNode.append(list);
1394
+ }
1395
+ },
1396
+ type: 'multiline-element'
1397
+ };
1398
+ return TRANSFORMER;
1399
+ }), {
1400
+ dependencies: [],
1401
+ regExpEnd: {
1402
+ optional: true,
1403
+ regExp: /[\u0020\t]*<\/li>$/
1404
+ },
1405
+ regExpStart: /^[\u0020\t]*<li(?:[^>]*?)>/,
1406
+ replace: (rootNode, children, startMatch, endMatch, linesInBetween) => {
1407
+ const checked = getHtmlTagAttrValue(startMatch[0], 'aria-checked') || 'false';
1408
+ if (linesInBetween) {
1409
+ const context = linesInBetween.join('\n');
1410
+ const listItem = $createInstanceListItemNode(checked === 'true');
1411
+ const nodes = parseTagContent(context);
1412
+ listItem.append(...nodes);
1413
+ rootNode.append(listItem);
1414
+ }
1415
+ },
1416
+ type: 'multiline-element'
1417
+ }];
1418
+ const HTML_QUOTE_TRANSFORMER = [{
1419
+ end: /[\u0020\t]*<\/blockquote>$/,
1420
+ start: /^[\u0020\t]*<blockquote(?:[^>]*?)>/
1421
+ }].map(({
1422
+ start,
1423
+ end
1424
+ }) => {
1425
+ return {
1426
+ dependencies: [],
1427
+ regExpEnd: {
1428
+ optional: true,
1429
+ regExp: end
1430
+ },
1431
+ regExpStart: start,
1432
+ replace: (rootNode, children, startMatch, endMatch, linesInBetween) => {
1433
+ // console.log('QUOTE', linesInBetween);
1434
+ if (linesInBetween) {
1435
+ const context = linesInBetween.join('\n');
1436
+ const quote = $createInstanceQuoteNode();
1437
+ const nodes = parseTagContent(context);
1438
+ quote.append(...nodes);
1439
+ rootNode.append(quote);
1440
+ }
1441
+ },
1442
+ type: 'multiline-element'
1443
+ };
1444
+ });
1445
+ const HTML_CODE_TRANSFORMER = [{
1446
+ end: /[\u0020\t]*<\/pre>$/,
1447
+ start: /^[\u0020\t]*<pre(?:[^>]*?)>/
1448
+ }].map(({
1449
+ start,
1450
+ end
1451
+ }) => {
1452
+ return {
1453
+ dependencies: [],
1454
+ regExpEnd: {
1455
+ optional: true,
1456
+ regExp: end
1457
+ },
1458
+ regExpStart: start,
1459
+ replace: (rootNode, children, startMatch, endMatch, linesInBetween) => {
1460
+ // console.log('CODE', linesInBetween);
1461
+ const language = getHtmlTagAttrValue(startMatch[0], 'data-language') || 'text';
1462
+ if (linesInBetween) {
1463
+ const context = linesInBetween.join('\n');
1464
+ const code = $createInstanceCodeNode(language);
1465
+ const nodes = parseTagContent(context);
1466
+ code.append(...nodes);
1467
+ rootNode.append(code);
1468
+ }
1469
+ },
1470
+ type: 'multiline-element'
1471
+ };
1472
+ });
1473
+ const HTML_LINK_TRANSFORMER = [{
1474
+ end: /[\u0020\t]*<\/a>$/,
1475
+ start: /^[\u0020\t]*<a[^a-z]+(?:[^>]*?)>/
1476
+ }].map(({
1477
+ start,
1478
+ end
1479
+ }) => {
1480
+ return {
1481
+ dependencies: [],
1482
+ regExpEnd: {
1483
+ optional: true,
1484
+ regExp: end
1485
+ },
1486
+ regExpStart: start,
1487
+ replace: (rootNode, children, startMatch, endMatch, linesInBetween) => {
1488
+ // console.log('LINK', linesInBetween);
1489
+ const url = getHtmlTagAttrValue(startMatch[0], 'href') || '';
1490
+ if (linesInBetween) {
1491
+ const context = linesInBetween.join('\n');
1492
+ const link = $createLinkNode(url);
1493
+ const nodes = parseTagContent(context);
1494
+ link.append(...nodes);
1495
+ rootNode.append(link);
1496
+ }
1497
+ },
1498
+ type: 'multiline-element'
1499
+ };
1500
+ });
1501
+ const HTML_HEADING_TRANSFORMER = [{
1502
+ end: /[\u0020\t]*<\/h[1-6]{1}>$/,
1503
+ start: /^[\u0020\t]*<h[1-6]{1}(?:[^>]*?)>/
1504
+ }].map(({
1505
+ start,
1506
+ end
1507
+ }) => {
1508
+ return {
1509
+ dependencies: [],
1510
+ regExpEnd: {
1511
+ optional: true,
1512
+ regExp: end
1513
+ },
1514
+ regExpStart: start,
1515
+ replace: (rootNode, children, startMatch, endMatch, linesInBetween) => {
1516
+ // console.log('HEADING', linesInBetween);
1517
+ if (linesInBetween) {
1518
+ const tag = `h${(startMatch[0] || '11')[2]}`;
1519
+ const context = linesInBetween.join('\n');
1520
+ const heading = $createInstanceHeadingNode(tag);
1521
+ const nodes = parseTagContent(context);
1522
+ heading.append(...nodes);
1523
+ rootNode.append(heading);
1524
+ }
1525
+ },
1526
+ type: 'multiline-element'
1527
+ };
1528
+ });
1529
+ const HTML_EQUATION_TRANSFORMER = [{
1530
+ end: /[\u0020\t]*<\/equation>$/,
1531
+ start: /^[\u0020\t]*<equation(?:[^>]*?)>/
1532
+ }].map(({
1533
+ start,
1534
+ end
1535
+ }) => {
1536
+ return {
1537
+ dependencies: [],
1538
+ regExpEnd: {
1539
+ optional: true,
1540
+ regExp: end
1541
+ },
1542
+ regExpStart: start,
1543
+ replace: (rootNode, children, startMatch, endMatch, linesInBetween) => {
1544
+ const equation = getHtmlTagAttrValue(startMatch[0], 'data-lexical-equation') || '';
1545
+ const inline = getHtmlTagAttrValue(startMatch[0], 'data-lexical-inline') === 'true';
1546
+ const node = $createInstanceEquationNode(fromBase64UTF8(equation), inline);
1547
+ rootNode.append(node);
1548
+ },
1549
+ type: 'multiline-element'
1550
+ };
1551
+ });
1552
+
1553
+ // details
1554
+
1555
+ const HTML_COLLAPSIBLE_TRANSFORMER = [{
1556
+ end: /[\u0020\t]*<\/details>$/,
1557
+ start: /^[\u0020\t]*<details(?:[^>]*?)>/
1558
+ }].map(({
1559
+ start,
1560
+ end
1561
+ }) => {
1562
+ return {
1563
+ dependencies: [],
1564
+ regExpEnd: {
1565
+ optional: true,
1566
+ regExp: end
1567
+ },
1568
+ regExpStart: start,
1569
+ replace: (rootNode, children, startMatch, endMatch, linesInBetween) => {
1570
+ if (linesInBetween) {
1571
+ const [title, content] = linesInBetween.join('\n').replace(/<summary(?:[^>]*?)>((.|[\n])*)<\/summary>((.|[\n])*)/, `$1${interval}$3`).split(interval).map(part => parseTagContent(part)).flat(1);
1572
+ const isOpen = getHtmlTagAttrValue(startMatch[0], 'open') === 'true';
1573
+ const node = $createCollapsibleContainerNode(isOpen).append($createCollapsibleTitleNode().append(title), $createCollapsibleContentNode().append(content));
1574
+ rootNode.append(node);
1575
+ }
1576
+ },
1577
+ type: 'multiline-element'
1578
+ };
1579
+ });
1580
+ const HTML_FIGURE_TRANSFORMER = [{
1581
+ end: /[\u0020\t]*<\/figure>$/,
1582
+ start: /^[\u0020\t]*<figure(?:[^>]*?)>/
1583
+ }].map(({
1584
+ start,
1585
+ end
1586
+ }) => {
1587
+ return {
1588
+ dependencies: [],
1589
+ regExpEnd: {
1590
+ optional: true,
1591
+ regExp: end
1592
+ },
1593
+ regExpStart: start,
1594
+ replace: (rootNode, children, startMatch, endMatch, linesInBetween) => {
1595
+ if (linesInBetween) {
1596
+ const node = $createPageBreakNode();
1597
+ rootNode.append(node);
1598
+ }
1599
+ },
1600
+ type: 'multiline-element'
1601
+ };
1602
+ });
1603
+ const HTML_INTERNAL_LINK_TRANSFORMER = {
1604
+ dependencies: [],
1605
+ regExpEnd: {
1606
+ regExp: /[\u0020\t]*<\/section>$/
1607
+ },
1608
+ regExpStart: /^[\u0020\t]*<section internal-link(?:[^>]*?)>/,
1609
+ replace: (rootNode, children, startMatch, endMatch, linesInBetween) => {
1610
+ // console.log('INTERNAL LINK MATCH', linesInBetween);
1611
+ const number = getHtmlTagAttrValue(startMatch[0], 'data-internal-link-number');
1612
+ if (number) {
1613
+ const internalLinkNode = $createInternalLinkNode(number);
1614
+ rootNode.append(internalLinkNode);
1615
+ }
1616
+ },
1617
+ type: 'multiline-element'
1618
+ };
1619
+ const HTML_PARAMETERS_TRANSFORMER = {
1620
+ dependencies: [],
1621
+ regExpEnd: {
1622
+ regExp: /[\u0020\t]*<\/section>$/
1623
+ },
1624
+ regExpStart: /^[\u0020\t]*<section parameter(?:[^>]*?)>/,
1625
+ replace: (rootNode, children, startMatch, endMatch, linesInBetween) => {
1626
+ // console.log('INTERNAL PARAMETERS MATCH', linesInBetween);
1627
+ const parameter = JSON.parse(fromBase64UTF8(getHtmlTagAttrValue(startMatch[0], 'data-parameter') || ''));
1628
+ if (parameter) {
1629
+ const parameterNode = $createParametersNode(parameter);
1630
+ rootNode.append(parameterNode);
1631
+ }
1632
+ },
1633
+ type: 'multiline-element'
1634
+ };
1292
1635
  const HTML_TEXT_TRANSFORMER = [{
1293
1636
  end: /[\u0020\t]*<\/span>$/,
1294
- start: /[\u0020\t]*<span.*?>/
1637
+ start: /^[\u0020\t]*<span(?:[^>]*?)>/
1638
+ }, {
1639
+ end: /[\u0020\t]*<\/em>$/,
1640
+ start: /^[\u0020\t]*<em(?:[^>]*?)>/
1641
+ }, {
1642
+ end: /[\u0020\t]*<\/strong>$/,
1643
+ start: /^[\u0020\t]*<strong(?:[^>]*?)>/
1295
1644
  }].map(({
1296
1645
  start,
1297
1646
  end
@@ -1303,24 +1652,100 @@ const HTML_TEXT_TRANSFORMER = [{
1303
1652
  },
1304
1653
  regExpStart: start,
1305
1654
  replace: (rootNode, children, startMatch, endMatch, linesInBetween) => {
1655
+ const input = startMatch.input || '';
1656
+ const nodes = parseTagContent(input);
1657
+ rootNode.append(...nodes);
1658
+ },
1659
+ type: 'multiline-element'
1660
+ };
1661
+ });
1662
+ const HTML_TEXT_STYLES_TRANSFORMER = [{
1663
+ end: /[\u0020\t]*<\/b>$/,
1664
+ start: /^[\u0020\t]*<b>/
1665
+ }, {
1666
+ end: /[\u0020\t]*<\/i>$/,
1667
+ start: /^[\u0020\t]*<i>/
1668
+ }, {
1669
+ end: /[\u0020\t]*<\/u>$/,
1670
+ start: /^[\u0020\t]*<u>/
1671
+ }, {
1672
+ end: /[\u0020\t]*<\/s>$/,
1673
+ start: /^[\u0020\t]*<s>/
1674
+ }, {
1675
+ end: /[\u0020\t]*<\/code>$/,
1676
+ start: /^[\u0020\t]*<code(?:[^>]*?)>/
1677
+ }, {
1678
+ end: /[\u0020\t]*<\/sub>$/,
1679
+ start: /^[\u0020\t]*<sub(?:[^>]*?)>/
1680
+ }, {
1681
+ end: /[\u0020\t]*<\/sup>$/,
1682
+ start: /^[\u0020\t]*<sup(?:[^>]*?)>/
1683
+ }].map(({
1684
+ start,
1685
+ end
1686
+ }) => {
1687
+ return {
1688
+ dependencies: [],
1689
+ regExpEnd: {
1690
+ optional: true,
1691
+ regExp: end
1692
+ },
1693
+ regExpStart: start,
1694
+ replace: (rootNode, children, startMatch, endMatch, linesInBetween) => {
1695
+ // console.log('TEXT_STYLES', linesInBetween);
1306
1696
  if (linesInBetween) {
1307
- const context = linesInBetween.join('\n').replace(/<br.*?\/>/g, '\n');
1308
- if (/<([a-z]+).*?>(.*?)<\/\1>/g.test(context)) {
1309
- const fragment = $createFragmentNode();
1310
- $convertFromMarkdownString(context, TransFormerGather.value, fragment);
1311
- const children = fragment.getChildren();
1312
- rootNode.append(...children);
1313
- } else {
1314
- const text = $createTextNode();
1315
- text.setTextContent(context);
1316
- if ($isRootNode(rootNode)) {
1317
- const paragraph = $createInstanceParagraphNode();
1318
- paragraph.append(text);
1319
- rootNode.append(paragraph);
1320
- } else {
1321
- rootNode.append(text);
1697
+ const [isBold, isItalic, isUnderline, isStrikethrough, isCode, isSup, isSub] = [startMatch[0].includes('<b'), startMatch[0].includes('<i'), startMatch[0].includes('<u'), startMatch[0].includes('<s'), startMatch[0].includes('<code'), startMatch[0].includes('<sup'), startMatch[0].includes('<sub')];
1698
+ const context = linesInBetween.join('\n');
1699
+ const fragment = $createFragmentNode();
1700
+ $convertFromMarkdownString(context, TransFormerGather.value, fragment);
1701
+ const nodes = fragment.getChildren();
1702
+ nodes.forEach(node => {
1703
+ if ($isTextNode(node)) {
1704
+ if (isBold) {
1705
+ if (node.hasFormat('bold')) {
1706
+ return;
1707
+ }
1708
+ node.setFormat(node.getFormat() | TEXT_TYPE_TO_FORMAT.bold);
1709
+ }
1710
+ if (isItalic) {
1711
+ if (node.hasFormat('italic')) {
1712
+ return;
1713
+ }
1714
+ node.setFormat(node.getFormat() | TEXT_TYPE_TO_FORMAT.italic);
1715
+ }
1716
+ if (isUnderline) {
1717
+ if (node.hasFormat('underline')) {
1718
+ return;
1719
+ }
1720
+ node.setFormat(node.getFormat() | TEXT_TYPE_TO_FORMAT.underline);
1721
+ }
1722
+ if (isStrikethrough) {
1723
+ if (node.hasFormat('strikethrough')) {
1724
+ return;
1725
+ }
1726
+ node.setFormat(node.getFormat() | TEXT_TYPE_TO_FORMAT.strikethrough);
1727
+ }
1728
+ if (isCode) {
1729
+ if (node.hasFormat('code')) {
1730
+ return;
1731
+ }
1732
+ node.setFormat(node.getFormat() | TEXT_TYPE_TO_FORMAT.code);
1733
+ }
1734
+ if (isSup) {
1735
+ if (node.hasFormat('superscript')) {
1736
+ return;
1737
+ }
1738
+ node.setFormat(node.getFormat() | TEXT_TYPE_TO_FORMAT.superscript);
1739
+ }
1740
+ if (isSub) {
1741
+ if (node.hasFormat('subscript')) {
1742
+ return;
1743
+ }
1744
+ node.setFormat(node.getFormat() | TEXT_TYPE_TO_FORMAT.subscript);
1745
+ }
1322
1746
  }
1323
- }
1747
+ });
1748
+ rootNode.append(...nodes);
1324
1749
  }
1325
1750
  },
1326
1751
  type: 'multiline-element'
@@ -1334,28 +1759,103 @@ const HTML_BR = {
1334
1759
  }
1335
1760
  return null;
1336
1761
  },
1337
- regExp: /^<br.*?\/>$/,
1762
+ regExp: /^<br(?:[^>]*?)\/{0,1}>/,
1338
1763
  replace: (parentNode, _1, _2, isImport) => {
1339
1764
  const line = $createLineBreakNode();
1340
- const paragraph = $createInstanceParagraphNode();
1341
- paragraph.append(line);
1342
1765
  if (isImport || parentNode.getNextSibling() != null) {
1343
- if ($isRootNode(parentNode.getParent())) {
1344
- parentNode.replace(paragraph);
1345
- } else {
1346
- parentNode.replace(line);
1347
- }
1766
+ parentNode.replace(line);
1348
1767
  } else {
1349
- if ($isRootNode(parentNode.getParent())) {
1350
- parentNode.insertBefore(paragraph);
1351
- } else {
1352
- parentNode.insertBefore(line);
1353
- }
1768
+ parentNode.insertBefore(line);
1354
1769
  }
1355
- line.selectNext();
1356
1770
  },
1357
1771
  type: 'element'
1358
1772
  };
1773
+ const HTML_IMAGE = {
1774
+ dependencies: [],
1775
+ export: node => {
1776
+ if ($isImageNode(node)) {
1777
+ return `![${node.getAltText()}](${node.getSrc()})`;
1778
+ }
1779
+ return null;
1780
+ },
1781
+ regExp: /^<img(?:[^>]*?)\/{0,1}>/,
1782
+ replace: (parentNode, _1, match, isImport) => {
1783
+ const input = match.input || '';
1784
+ const url = getHtmlTagAttrValue(input, 'src') || '';
1785
+ const alt = getHtmlTagAttrValue(input, 'alt') || '';
1786
+ const image = $createImageNode({
1787
+ altText: alt,
1788
+ src: url
1789
+ });
1790
+ if (isImport || parentNode.getNextSibling() != null) {
1791
+ parentNode.replace(image);
1792
+ } else {
1793
+ parentNode.insertBefore(image);
1794
+ }
1795
+ },
1796
+ type: 'element'
1797
+ };
1798
+ const HTML_HR = {
1799
+ dependencies: [],
1800
+ export: node => {
1801
+ if ($isHorizontalRuleNode(node)) {
1802
+ return '***';
1803
+ }
1804
+ return null;
1805
+ },
1806
+ regExp: /^<hr(?:[^>]*?)\/{0,1}>/,
1807
+ replace: (parentNode, _1, match, isImport) => {
1808
+ const horizontal = $createInstanceHorizontalRuleNode();
1809
+ if (isImport || parentNode.getNextSibling() != null) {
1810
+ parentNode.replace(horizontal);
1811
+ } else {
1812
+ parentNode.insertBefore(horizontal);
1813
+ }
1814
+ },
1815
+ type: 'element'
1816
+ };
1817
+ function optimizeNesting(node, context) {
1818
+ const nodes = parseTagContent(context);
1819
+ if (nodes.length === 1 && nodes[0] instanceof node.constructor) {
1820
+ node = nodes[0];
1821
+ } else {
1822
+ node.append(...nodes);
1823
+ }
1824
+ return node;
1825
+ }
1826
+ function parseTagContent(input) {
1827
+ // console.log(input, 'PARSE TAG CONTENT');
1828
+ const structure = parseHtmlToCustomStructure(input);
1829
+ let htmlFragment = document.createElement('div');
1830
+ dfs(structure, (object, parent) => {
1831
+ if (['span', 'em', 'strong'].includes(object.tag)) {
1832
+ const text = $createTextNode();
1833
+ object.node = text;
1834
+ } else if (object.tag === 'text') {
1835
+ if (parent && parent.node) {
1836
+ if ($isElementNode(parent.node)) {
1837
+ const text = $createTextNode();
1838
+ text.setTextContent(object.content);
1839
+ parent.node.append(text);
1840
+ } else {
1841
+ if ($isTextNode(parent.node)) {
1842
+ parent.node.setTextContent(object.content);
1843
+ }
1844
+ }
1845
+ }
1846
+ } else {
1847
+ htmlFragment.childNodes.forEach(element => element.remove());
1848
+ htmlFragment.append(object.dom);
1849
+ const fragment = $createFragmentNode();
1850
+ $convertFromMarkdownString(htmlFragment.innerHTML, TransFormerGather.value, fragment);
1851
+ object.node = fragment.getChildren()[0];
1852
+ object.dom = null;
1853
+ }
1854
+ return object.children;
1855
+ });
1856
+ htmlFragment = null;
1857
+ return structure.map(object => object.node).filter(Boolean);
1858
+ }
1359
1859
 
1360
1860
  /**
1361
1861
  * Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -1682,7 +2182,7 @@ TransFormerGather.register(BLOCK_EQUATION);
1682
2182
  TransFormerGather.register(IMAGE);
1683
2183
  TransFormerGather.register(PAGE_BREAK);
1684
2184
  TransFormerGather.register(PAGE_BREAK);
1685
- [...HTML_PARAGRAPH_TRANSFORMER, ...HTML_TEXT_TRANSFORMER, HTML_BR].forEach(item => {
2185
+ [...HTML_CODE_TRANSFORMER, ...HTML_QUOTE_TRANSFORMER, ...HTML_LIST_TRANSFORMER, ...HTML_HEADING_TRANSFORMER, ...HTML_LINK_TRANSFORMER, ...HTML_EQUATION_TRANSFORMER, ...HTML_COLLAPSIBLE_TRANSFORMER, ...HTML_FIGURE_TRANSFORMER, ...HTML_PARAGRAPH_TRANSFORMER, HTML_INTERNAL_LINK_TRANSFORMER, HTML_PARAMETERS_TRANSFORMER, ...HTML_TEXT_STYLES_TRANSFORMER, ...HTML_TEXT_TRANSFORMER, HTML_BR, HTML_IMAGE, HTML_HR].forEach(item => {
1686
2186
  TransFormerGather.register(item);
1687
2187
  });
1688
2188
  function getInstanceTransformers() {
@@ -1719,6 +2219,14 @@ function $convertFromMarkdownString(markdown, transformers = TransFormerGather.v
1719
2219
  */
1720
2220
  /* eslint-disable @typescript-eslint/no-explicit-any */
1721
2221
 
2222
+ /** reqIf xmlns 子标签单行排列 */
2223
+ function xmlnsSingleLine(markdown) {
2224
+ if (/^<div xmlns(?:[^>]*?)>/.test(markdown)) {
2225
+ const mks = markdown.split('\n');
2226
+ markdown = htmlTagSingleLine(mks.slice(1, mks.length - 1).join('\n'));
2227
+ }
2228
+ return markdown;
2229
+ }
1722
2230
  const markdownToSerializedNode = async ({
1723
2231
  nodes,
1724
2232
  markdown
@@ -1729,8 +2237,10 @@ const markdownToSerializedNode = async ({
1729
2237
  namespace: 'temporary',
1730
2238
  nodes
1731
2239
  }).update(() => {
1732
- $convertFromMarkdownString(markdown, getInstanceTransformers());
1733
- resolve(exportNodeToJSON($getRoot()).children || []);
2240
+ const fragment = $createFragmentNode();
2241
+ markdown = xmlnsSingleLine(markdown);
2242
+ $convertFromMarkdownString(markdown, getInstanceTransformers(), fragment);
2243
+ resolve(exportNodeToJSON(fragment).children || []);
1734
2244
  });
1735
2245
  } catch (e) {
1736
2246
  const _console = console;
@@ -1831,6 +2341,7 @@ async function _textToSerializedNode(nodes, childrenText) {
1831
2341
  if (jsonRegExp.test(childrenText)) {
1832
2342
  return JSON.parse(childrenText.replace(jsonRegExp, '$1'));
1833
2343
  } else {
2344
+ childrenText = xmlnsSingleLine(childrenText);
1834
2345
  return await markdownToSerializedNode({
1835
2346
  markdown: childrenText,
1836
2347
  nodes
@@ -1844,6 +2355,7 @@ function $textToRichNodes(node, childrenText) {
1844
2355
  const serializedNodeList = [JSON.parse(childrenText.replace(jsonRegExp, '$1'))];
1845
2356
  return node.append(...serializedNodeList.flat(1).map(serializedNode => $advanceParseSerializedNode(serializedNode)));
1846
2357
  } else {
2358
+ childrenText = xmlnsSingleLine(childrenText);
1847
2359
  return $convertFromMarkdownString(childrenText, getInstanceTransformers(), node);
1848
2360
  }
1849
2361
  }