onchain-lexical-markdown 0.0.13 → 0.0.14

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