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.
- package/dist/OnchainLexicalMarkdown.js +550 -38
- package/dist/OnchainLexicalMarkdown.mjs +552 -40
- package/package.json +3 -3
- package/src/instanceToSerializeNode.ts +25 -4
- package/src/transformer/html.ts +556 -41
- package/src/transformer/index.ts +40 -12
- package/src/transformer/utils.ts +84 -0
|
@@ -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:
|
|
1345
|
+
start: /^[\u0020\t]*<p[^a-z]+(?:[^>]*?)>/
|
|
1270
1346
|
}, {
|
|
1271
1347
|
end: /[\u0020\t]*<\/div>$/,
|
|
1272
|
-
start:
|
|
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
|
-
|
|
1287
|
-
|
|
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:
|
|
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
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
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
|
-
|
|
1346
|
-
parentNode.replace(paragraph);
|
|
1347
|
-
} else {
|
|
1348
|
-
parentNode.replace(line);
|
|
1349
|
-
}
|
|
1768
|
+
parentNode.replace(line);
|
|
1350
1769
|
} else {
|
|
1351
|
-
|
|
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 `})`;
|
|
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
|
-
|
|
1735
|
-
|
|
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
|
}
|