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.
- 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 +33 -5
- package/src/transformer/utils.ts +86 -0
|
@@ -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, $
|
|
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:
|
|
1343
|
+
start: /^[\u0020\t]*<p[^a-z]+(?:[^>]*?)>/
|
|
1268
1344
|
}, {
|
|
1269
1345
|
end: /[\u0020\t]*<\/div>$/,
|
|
1270
|
-
start:
|
|
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
|
-
|
|
1285
|
-
$
|
|
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:
|
|
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
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
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
|
-
|
|
1344
|
-
parentNode.replace(paragraph);
|
|
1345
|
-
} else {
|
|
1346
|
-
parentNode.replace(line);
|
|
1347
|
-
}
|
|
1766
|
+
parentNode.replace(line);
|
|
1348
1767
|
} else {
|
|
1349
|
-
|
|
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 `})`;
|
|
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
|
-
$
|
|
1733
|
-
|
|
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
|
}
|