@lvce-editor/preview-worker 1.3.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/previewWorkerMain.js +486 -27
- package/package.json +1 -1
|
@@ -417,6 +417,100 @@ const IpcChildWithModuleWorkerAndMessagePort$1 = {
|
|
|
417
417
|
listen: listen$6,
|
|
418
418
|
wrap: wrap$e
|
|
419
419
|
};
|
|
420
|
+
const addListener = (emitter, type, callback) => {
|
|
421
|
+
if ('addEventListener' in emitter) {
|
|
422
|
+
emitter.addEventListener(type, callback);
|
|
423
|
+
} else {
|
|
424
|
+
emitter.on(type, callback);
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
const removeListener = (emitter, type, callback) => {
|
|
428
|
+
if ('removeEventListener' in emitter) {
|
|
429
|
+
emitter.removeEventListener(type, callback);
|
|
430
|
+
} else {
|
|
431
|
+
emitter.off(type, callback);
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
const getFirstEvent = (eventEmitter, eventMap) => {
|
|
435
|
+
const {
|
|
436
|
+
promise,
|
|
437
|
+
resolve
|
|
438
|
+
} = Promise.withResolvers();
|
|
439
|
+
const listenerMap = Object.create(null);
|
|
440
|
+
const cleanup = value => {
|
|
441
|
+
for (const event of Object.keys(eventMap)) {
|
|
442
|
+
removeListener(eventEmitter, event, listenerMap[event]);
|
|
443
|
+
}
|
|
444
|
+
resolve(value);
|
|
445
|
+
};
|
|
446
|
+
for (const [event, type] of Object.entries(eventMap)) {
|
|
447
|
+
const listener = event => {
|
|
448
|
+
cleanup({
|
|
449
|
+
event,
|
|
450
|
+
type
|
|
451
|
+
});
|
|
452
|
+
};
|
|
453
|
+
addListener(eventEmitter, event, listener);
|
|
454
|
+
listenerMap[event] = listener;
|
|
455
|
+
}
|
|
456
|
+
return promise;
|
|
457
|
+
};
|
|
458
|
+
const Message$1 = 3;
|
|
459
|
+
const create$5$1 = async ({
|
|
460
|
+
isMessagePortOpen,
|
|
461
|
+
messagePort
|
|
462
|
+
}) => {
|
|
463
|
+
if (!isMessagePort(messagePort)) {
|
|
464
|
+
throw new IpcError('port must be of type MessagePort');
|
|
465
|
+
}
|
|
466
|
+
if (isMessagePortOpen) {
|
|
467
|
+
return messagePort;
|
|
468
|
+
}
|
|
469
|
+
const eventPromise = getFirstEvent(messagePort, {
|
|
470
|
+
message: Message$1
|
|
471
|
+
});
|
|
472
|
+
messagePort.start();
|
|
473
|
+
const {
|
|
474
|
+
event,
|
|
475
|
+
type
|
|
476
|
+
} = await eventPromise;
|
|
477
|
+
if (type !== Message$1) {
|
|
478
|
+
throw new IpcError('Failed to wait for ipc message');
|
|
479
|
+
}
|
|
480
|
+
if (event.data !== readyMessage) {
|
|
481
|
+
throw new IpcError('unexpected first message');
|
|
482
|
+
}
|
|
483
|
+
return messagePort;
|
|
484
|
+
};
|
|
485
|
+
const signal$1 = messagePort => {
|
|
486
|
+
messagePort.start();
|
|
487
|
+
};
|
|
488
|
+
class IpcParentWithMessagePort extends Ipc {
|
|
489
|
+
getData = getData$2;
|
|
490
|
+
send(message) {
|
|
491
|
+
this._rawIpc.postMessage(message);
|
|
492
|
+
}
|
|
493
|
+
sendAndTransfer(message) {
|
|
494
|
+
const transfer = getTransferrables(message);
|
|
495
|
+
this._rawIpc.postMessage(message, transfer);
|
|
496
|
+
}
|
|
497
|
+
dispose() {
|
|
498
|
+
this._rawIpc.close();
|
|
499
|
+
}
|
|
500
|
+
onMessage(callback) {
|
|
501
|
+
this._rawIpc.addEventListener('message', callback);
|
|
502
|
+
}
|
|
503
|
+
onClose(callback) {}
|
|
504
|
+
}
|
|
505
|
+
const wrap$5 = messagePort => {
|
|
506
|
+
return new IpcParentWithMessagePort(messagePort);
|
|
507
|
+
};
|
|
508
|
+
const IpcParentWithMessagePort$1 = {
|
|
509
|
+
__proto__: null,
|
|
510
|
+
create: create$5$1,
|
|
511
|
+
signal: signal$1,
|
|
512
|
+
wrap: wrap$5
|
|
513
|
+
};
|
|
420
514
|
|
|
421
515
|
const Two$1 = '2.0';
|
|
422
516
|
const callbacks = Object.create(null);
|
|
@@ -632,7 +726,7 @@ const getErrorResponse = (id, error, preparePrettyError, logError) => {
|
|
|
632
726
|
const errorProperty = getErrorProperty(error, prettyError);
|
|
633
727
|
return create$1$1(id, errorProperty);
|
|
634
728
|
};
|
|
635
|
-
const create$
|
|
729
|
+
const create$4 = (message, result) => {
|
|
636
730
|
return {
|
|
637
731
|
jsonrpc: Two$1,
|
|
638
732
|
id: message.id,
|
|
@@ -641,7 +735,7 @@ const create$3 = (message, result) => {
|
|
|
641
735
|
};
|
|
642
736
|
const getSuccessResponse = (message, result) => {
|
|
643
737
|
const resultProperty = result ?? null;
|
|
644
|
-
return create$
|
|
738
|
+
return create$4(message, resultProperty);
|
|
645
739
|
};
|
|
646
740
|
const getErrorResponseSimple = (id, error) => {
|
|
647
741
|
return {
|
|
@@ -869,6 +963,86 @@ const listen$1 = async (module, options) => {
|
|
|
869
963
|
const ipc = module.wrap(rawIpc);
|
|
870
964
|
return ipc;
|
|
871
965
|
};
|
|
966
|
+
|
|
967
|
+
/* eslint-disable @typescript-eslint/no-misused-promises */
|
|
968
|
+
|
|
969
|
+
const createSharedLazyRpc = factory => {
|
|
970
|
+
let rpcPromise;
|
|
971
|
+
const getOrCreate = () => {
|
|
972
|
+
if (!rpcPromise) {
|
|
973
|
+
rpcPromise = factory();
|
|
974
|
+
}
|
|
975
|
+
return rpcPromise;
|
|
976
|
+
};
|
|
977
|
+
return {
|
|
978
|
+
async dispose() {
|
|
979
|
+
const rpc = await getOrCreate();
|
|
980
|
+
await rpc.dispose();
|
|
981
|
+
},
|
|
982
|
+
async invoke(method, ...params) {
|
|
983
|
+
const rpc = await getOrCreate();
|
|
984
|
+
return rpc.invoke(method, ...params);
|
|
985
|
+
},
|
|
986
|
+
async invokeAndTransfer(method, ...params) {
|
|
987
|
+
const rpc = await getOrCreate();
|
|
988
|
+
return rpc.invokeAndTransfer(method, ...params);
|
|
989
|
+
},
|
|
990
|
+
async send(method, ...params) {
|
|
991
|
+
const rpc = await getOrCreate();
|
|
992
|
+
rpc.send(method, ...params);
|
|
993
|
+
}
|
|
994
|
+
};
|
|
995
|
+
};
|
|
996
|
+
const create$j = async ({
|
|
997
|
+
commandMap,
|
|
998
|
+
isMessagePortOpen,
|
|
999
|
+
send
|
|
1000
|
+
}) => {
|
|
1001
|
+
return createSharedLazyRpc(() => {
|
|
1002
|
+
return create$3({
|
|
1003
|
+
commandMap,
|
|
1004
|
+
isMessagePortOpen,
|
|
1005
|
+
send
|
|
1006
|
+
});
|
|
1007
|
+
});
|
|
1008
|
+
};
|
|
1009
|
+
const LazyTransferMessagePortRpcParent = {
|
|
1010
|
+
__proto__: null,
|
|
1011
|
+
create: create$j
|
|
1012
|
+
};
|
|
1013
|
+
const create$5 = async ({
|
|
1014
|
+
commandMap,
|
|
1015
|
+
isMessagePortOpen = true,
|
|
1016
|
+
messagePort
|
|
1017
|
+
}) => {
|
|
1018
|
+
// TODO create a commandMap per rpc instance
|
|
1019
|
+
register(commandMap);
|
|
1020
|
+
const rawIpc = await IpcParentWithMessagePort$1.create({
|
|
1021
|
+
isMessagePortOpen,
|
|
1022
|
+
messagePort
|
|
1023
|
+
});
|
|
1024
|
+
const ipc = IpcParentWithMessagePort$1.wrap(rawIpc);
|
|
1025
|
+
handleIpc(ipc);
|
|
1026
|
+
const rpc = createRpc(ipc);
|
|
1027
|
+
messagePort.start();
|
|
1028
|
+
return rpc;
|
|
1029
|
+
};
|
|
1030
|
+
const create$3 = async ({
|
|
1031
|
+
commandMap,
|
|
1032
|
+
isMessagePortOpen,
|
|
1033
|
+
send
|
|
1034
|
+
}) => {
|
|
1035
|
+
const {
|
|
1036
|
+
port1,
|
|
1037
|
+
port2
|
|
1038
|
+
} = new MessageChannel();
|
|
1039
|
+
await send(port1);
|
|
1040
|
+
return create$5({
|
|
1041
|
+
commandMap,
|
|
1042
|
+
isMessagePortOpen,
|
|
1043
|
+
messagePort: port2
|
|
1044
|
+
});
|
|
1045
|
+
};
|
|
872
1046
|
const create$2$1 = async ({
|
|
873
1047
|
commandMap
|
|
874
1048
|
}) => {
|
|
@@ -903,15 +1077,25 @@ const createMockRpc = ({
|
|
|
903
1077
|
return mockRpc;
|
|
904
1078
|
};
|
|
905
1079
|
|
|
1080
|
+
const Button$1 = 1;
|
|
906
1081
|
const Div$1 = 4;
|
|
907
1082
|
const H1$1 = 5;
|
|
1083
|
+
const Input$1 = 6;
|
|
908
1084
|
const Span$1 = 8;
|
|
1085
|
+
const Table$1 = 9;
|
|
1086
|
+
const TBody$1 = 10;
|
|
1087
|
+
const Td$1 = 11;
|
|
909
1088
|
const Text$1 = 12;
|
|
1089
|
+
const Th$1 = 13;
|
|
1090
|
+
const THead$1 = 14;
|
|
1091
|
+
const Tr$1 = 15;
|
|
910
1092
|
const Img$1 = 17;
|
|
1093
|
+
const Del$1 = 21;
|
|
911
1094
|
const H2$1 = 22;
|
|
912
1095
|
const H3$1 = 23;
|
|
913
1096
|
const H4$1 = 24;
|
|
914
1097
|
const H5$1 = 25;
|
|
1098
|
+
const H6$1 = 26;
|
|
915
1099
|
const Article$1 = 27;
|
|
916
1100
|
const Aside$1 = 28;
|
|
917
1101
|
const Footer$1 = 29;
|
|
@@ -935,17 +1119,26 @@ const Cite$1 = 56;
|
|
|
935
1119
|
const Data$1 = 57;
|
|
936
1120
|
const Time$1 = 58;
|
|
937
1121
|
const Tfoot$1 = 59;
|
|
1122
|
+
const Ul$1 = 60;
|
|
1123
|
+
const TextArea$1 = 62;
|
|
1124
|
+
const Select$1 = 63;
|
|
1125
|
+
const Option$1 = 64;
|
|
1126
|
+
const Code$1 = 65;
|
|
1127
|
+
const Label$1 = 66;
|
|
1128
|
+
const Dt$1 = 67;
|
|
1129
|
+
const Iframe$1 = 68;
|
|
938
1130
|
const Reference = 100;
|
|
939
1131
|
|
|
940
1132
|
const TargetName = 'event.target.name';
|
|
941
1133
|
|
|
1134
|
+
const EditorWorker = 99;
|
|
942
1135
|
const RendererWorker = 1;
|
|
943
1136
|
|
|
944
1137
|
const SetDom2 = 'Viewlet.setDom2';
|
|
945
1138
|
const SetPatches = 'Viewlet.setPatches';
|
|
946
1139
|
|
|
947
1140
|
const rpcs = Object.create(null);
|
|
948
|
-
const set$
|
|
1141
|
+
const set$3 = (id, rpc) => {
|
|
949
1142
|
rpcs[id] = rpc;
|
|
950
1143
|
};
|
|
951
1144
|
const get$1 = id => {
|
|
@@ -978,7 +1171,7 @@ const create$2 = rpcId => {
|
|
|
978
1171
|
const mockRpc = createMockRpc({
|
|
979
1172
|
commandMap
|
|
980
1173
|
});
|
|
981
|
-
set$
|
|
1174
|
+
set$3(rpcId, mockRpc);
|
|
982
1175
|
// @ts-ignore
|
|
983
1176
|
mockRpc[Symbol.dispose] = () => {
|
|
984
1177
|
remove(rpcId);
|
|
@@ -987,15 +1180,25 @@ const create$2 = rpcId => {
|
|
|
987
1180
|
return mockRpc;
|
|
988
1181
|
},
|
|
989
1182
|
set(rpc) {
|
|
990
|
-
set$
|
|
1183
|
+
set$3(rpcId, rpc);
|
|
991
1184
|
}
|
|
992
1185
|
};
|
|
993
1186
|
};
|
|
994
1187
|
|
|
1188
|
+
const {
|
|
1189
|
+
invoke: invoke$1,
|
|
1190
|
+
set: set$2
|
|
1191
|
+
} = create$2(EditorWorker);
|
|
1192
|
+
|
|
995
1193
|
const {
|
|
996
1194
|
invoke,
|
|
1195
|
+
invokeAndTransfer,
|
|
997
1196
|
set: set$1
|
|
998
1197
|
} = create$2(RendererWorker);
|
|
1198
|
+
const sendMessagePortToEditorWorker = async (port, rpcId) => {
|
|
1199
|
+
const command = 'HandleMessagePort.handleMessagePort';
|
|
1200
|
+
await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToEditorWorker', port, command, rpcId);
|
|
1201
|
+
};
|
|
999
1202
|
const readFile = async uri => {
|
|
1000
1203
|
return invoke('FileSystem.readFile', uri);
|
|
1001
1204
|
};
|
|
@@ -1092,6 +1295,7 @@ const terminate = () => {
|
|
|
1092
1295
|
const {
|
|
1093
1296
|
get,
|
|
1094
1297
|
getCommandIds,
|
|
1298
|
+
getKeys: getKeys$1,
|
|
1095
1299
|
registerCommands,
|
|
1096
1300
|
set,
|
|
1097
1301
|
wrapCommand,
|
|
@@ -1106,6 +1310,7 @@ const create = (uid, uri, x, y, width, height, platform, assetDir) => {
|
|
|
1106
1310
|
errorMessage: '',
|
|
1107
1311
|
initial: true,
|
|
1108
1312
|
parsedDom: [],
|
|
1313
|
+
parsedNodesChildNodeCount: 0,
|
|
1109
1314
|
platform,
|
|
1110
1315
|
uid,
|
|
1111
1316
|
uri,
|
|
@@ -1115,7 +1320,7 @@ const create = (uid, uri, x, y, width, height, platform, assetDir) => {
|
|
|
1115
1320
|
};
|
|
1116
1321
|
|
|
1117
1322
|
const isEqual = (oldState, newState) => {
|
|
1118
|
-
return oldState.warningCount === newState.warningCount && oldState.initial === newState.initial && oldState.content === newState.content && oldState.parsedDom === newState.parsedDom;
|
|
1323
|
+
return oldState.warningCount === newState.warningCount && oldState.initial === newState.initial && oldState.content === newState.content && oldState.parsedDom === newState.parsedDom && oldState.parsedNodesChildNodeCount === newState.parsedNodesChildNodeCount;
|
|
1119
1324
|
};
|
|
1120
1325
|
|
|
1121
1326
|
const RenderItems = 4;
|
|
@@ -1471,6 +1676,25 @@ const Cite = 'cite';
|
|
|
1471
1676
|
const Data = 'data';
|
|
1472
1677
|
const Time = 'time';
|
|
1473
1678
|
const Tfoot = 'tfoot';
|
|
1679
|
+
const Button = 'button';
|
|
1680
|
+
const Input = 'input';
|
|
1681
|
+
const Code = 'code';
|
|
1682
|
+
const Form = 'form';
|
|
1683
|
+
const Table = 'table';
|
|
1684
|
+
const TBody = 'tbody';
|
|
1685
|
+
const THead = 'thead';
|
|
1686
|
+
const Tr = 'tr';
|
|
1687
|
+
const Td = 'td';
|
|
1688
|
+
const Th = 'th';
|
|
1689
|
+
const Ul = 'ul';
|
|
1690
|
+
const TextArea = 'textarea';
|
|
1691
|
+
const Select = 'select';
|
|
1692
|
+
const Option = 'option';
|
|
1693
|
+
const Label = 'label';
|
|
1694
|
+
const Dt = 'dt';
|
|
1695
|
+
const Iframe = 'iframe';
|
|
1696
|
+
const Del = 'del';
|
|
1697
|
+
const H6 = 'h6';
|
|
1474
1698
|
|
|
1475
1699
|
const getVirtualDomTag = text => {
|
|
1476
1700
|
switch (text) {
|
|
@@ -1484,22 +1708,32 @@ const getVirtualDomTag = text => {
|
|
|
1484
1708
|
return Aside$1;
|
|
1485
1709
|
case Br:
|
|
1486
1710
|
return Br$1;
|
|
1711
|
+
case Button:
|
|
1712
|
+
return Button$1;
|
|
1487
1713
|
case Cite:
|
|
1488
1714
|
return Cite$1;
|
|
1715
|
+
case Code:
|
|
1716
|
+
return Code$1;
|
|
1489
1717
|
case Data:
|
|
1490
1718
|
return Data$1;
|
|
1491
1719
|
case Dd:
|
|
1492
1720
|
return Dd$1;
|
|
1721
|
+
case Del:
|
|
1722
|
+
return Del$1;
|
|
1493
1723
|
case Div:
|
|
1494
1724
|
return Div$1;
|
|
1495
1725
|
case Dl:
|
|
1496
1726
|
return Dl$1;
|
|
1727
|
+
case Dt:
|
|
1728
|
+
return Dt$1;
|
|
1497
1729
|
case Figcaption:
|
|
1498
1730
|
return Figcaption$1;
|
|
1499
1731
|
case Figure:
|
|
1500
1732
|
return Figure$1;
|
|
1501
1733
|
case Footer:
|
|
1502
1734
|
return Footer$1;
|
|
1735
|
+
case Form:
|
|
1736
|
+
return Div$1;
|
|
1503
1737
|
case H1:
|
|
1504
1738
|
return H1$1;
|
|
1505
1739
|
case H2:
|
|
@@ -1510,18 +1744,28 @@ const getVirtualDomTag = text => {
|
|
|
1510
1744
|
return H4$1;
|
|
1511
1745
|
case H5:
|
|
1512
1746
|
return H5$1;
|
|
1747
|
+
case H6:
|
|
1748
|
+
return H6$1;
|
|
1513
1749
|
case Header:
|
|
1514
1750
|
return Header$1;
|
|
1515
1751
|
case Hr:
|
|
1516
1752
|
return Hr$1;
|
|
1753
|
+
case Iframe:
|
|
1754
|
+
return Iframe$1;
|
|
1517
1755
|
case Img:
|
|
1518
1756
|
return Img$1;
|
|
1757
|
+
case Input:
|
|
1758
|
+
return Input$1;
|
|
1759
|
+
case Label:
|
|
1760
|
+
return Label$1;
|
|
1519
1761
|
case Li:
|
|
1520
1762
|
return Li$1;
|
|
1521
1763
|
case Nav:
|
|
1522
1764
|
return Nav$1;
|
|
1523
1765
|
case Ol:
|
|
1524
1766
|
return Ol$1;
|
|
1767
|
+
case Option:
|
|
1768
|
+
return Option$1;
|
|
1525
1769
|
case P:
|
|
1526
1770
|
return P$1;
|
|
1527
1771
|
case Pre:
|
|
@@ -1530,12 +1774,30 @@ const getVirtualDomTag = text => {
|
|
|
1530
1774
|
return Search$1;
|
|
1531
1775
|
case Section:
|
|
1532
1776
|
return Section$1;
|
|
1777
|
+
case Select:
|
|
1778
|
+
return Select$1;
|
|
1533
1779
|
case Span:
|
|
1534
1780
|
return Span$1;
|
|
1781
|
+
case Table:
|
|
1782
|
+
return Table$1;
|
|
1783
|
+
case TBody:
|
|
1784
|
+
return TBody$1;
|
|
1785
|
+
case Td:
|
|
1786
|
+
return Td$1;
|
|
1787
|
+
case TextArea:
|
|
1788
|
+
return TextArea$1;
|
|
1535
1789
|
case Tfoot:
|
|
1536
1790
|
return Tfoot$1;
|
|
1791
|
+
case Th:
|
|
1792
|
+
return Th$1;
|
|
1793
|
+
case THead:
|
|
1794
|
+
return THead$1;
|
|
1537
1795
|
case Time:
|
|
1538
1796
|
return Time$1;
|
|
1797
|
+
case Tr:
|
|
1798
|
+
return Tr$1;
|
|
1799
|
+
case Ul:
|
|
1800
|
+
return Ul$1;
|
|
1539
1801
|
default:
|
|
1540
1802
|
return Div$1;
|
|
1541
1803
|
}
|
|
@@ -1564,9 +1826,29 @@ const EndCommentTag = 19;
|
|
|
1564
1826
|
const Text = 20;
|
|
1565
1827
|
const CommentStart = 21;
|
|
1566
1828
|
|
|
1829
|
+
const isDefaultAllowedAttribute = (attributeName, defaultAllowedAttributes) => {
|
|
1830
|
+
// Allow data-* attributes
|
|
1831
|
+
if (attributeName.startsWith('data-')) {
|
|
1832
|
+
return true;
|
|
1833
|
+
}
|
|
1834
|
+
// Allow aria-* attributes
|
|
1835
|
+
if (attributeName.startsWith('aria-')) {
|
|
1836
|
+
return true;
|
|
1837
|
+
}
|
|
1838
|
+
// Allow role attribute
|
|
1839
|
+
if (attributeName === 'role') {
|
|
1840
|
+
return true;
|
|
1841
|
+
}
|
|
1842
|
+
// Check if in default list
|
|
1843
|
+
return defaultAllowedAttributes.includes(attributeName);
|
|
1844
|
+
};
|
|
1845
|
+
|
|
1567
1846
|
const isSelfClosingTag = tag => {
|
|
1568
1847
|
switch (tag) {
|
|
1848
|
+
case Br:
|
|
1849
|
+
case Hr:
|
|
1569
1850
|
case Img:
|
|
1851
|
+
case Input:
|
|
1570
1852
|
return true;
|
|
1571
1853
|
default:
|
|
1572
1854
|
return false;
|
|
@@ -1835,9 +2117,14 @@ const tokenizeHtml = text => {
|
|
|
1835
2117
|
return tokens;
|
|
1836
2118
|
};
|
|
1837
2119
|
|
|
1838
|
-
const parseHtml = (html, allowedAttributes) => {
|
|
2120
|
+
const parseHtml = (html, allowedAttributes = [], defaultAllowedAttributes = []) => {
|
|
1839
2121
|
string(html);
|
|
1840
2122
|
array(allowedAttributes);
|
|
2123
|
+
array(defaultAllowedAttributes);
|
|
2124
|
+
|
|
2125
|
+
// Combine default allowed attributes with any additional ones provided
|
|
2126
|
+
const allAllowedAttributes = new Set([...defaultAllowedAttributes, ...allowedAttributes]);
|
|
2127
|
+
const useBuiltInDefaults = allowedAttributes.length === 0;
|
|
1841
2128
|
const tokens = tokenizeHtml(html);
|
|
1842
2129
|
const dom = [];
|
|
1843
2130
|
const root = {
|
|
@@ -1847,44 +2134,159 @@ const parseHtml = (html, allowedAttributes) => {
|
|
|
1847
2134
|
let current = root;
|
|
1848
2135
|
const stack = [root];
|
|
1849
2136
|
let attributeName = '';
|
|
2137
|
+
let lastTagWasSelfClosing = false;
|
|
1850
2138
|
for (const token of tokens) {
|
|
1851
2139
|
switch (token.type) {
|
|
1852
2140
|
case AttributeName:
|
|
1853
2141
|
attributeName = token.text;
|
|
1854
|
-
if (attributeName === 'class') {
|
|
1855
|
-
attributeName = 'className';
|
|
1856
|
-
}
|
|
1857
2142
|
break;
|
|
1858
2143
|
case AttributeValue:
|
|
1859
|
-
if (
|
|
1860
|
-
|
|
2144
|
+
if (allAllowedAttributes.has(attributeName) || useBuiltInDefaults && isDefaultAllowedAttribute(attributeName, defaultAllowedAttributes)) {
|
|
2145
|
+
const finalAttributeName = attributeName === 'class' ? 'className' : attributeName;
|
|
2146
|
+
current[finalAttributeName] = token.text;
|
|
1861
2147
|
}
|
|
1862
2148
|
attributeName = '';
|
|
1863
2149
|
break;
|
|
2150
|
+
case ClosingAngleBracket:
|
|
2151
|
+
// Handle boolean attributes (attributes without values)
|
|
2152
|
+
if (attributeName && (allAllowedAttributes.has(attributeName) || useBuiltInDefaults && isDefaultAllowedAttribute(attributeName, defaultAllowedAttributes))) {
|
|
2153
|
+
const finalAttributeName = attributeName === 'class' ? 'className' : attributeName;
|
|
2154
|
+
current[finalAttributeName] = attributeName;
|
|
2155
|
+
}
|
|
2156
|
+
attributeName = '';
|
|
2157
|
+
// Return to parent if the current tag is self-closing
|
|
2158
|
+
if (lastTagWasSelfClosing) {
|
|
2159
|
+
current = stack.at(-1) || root;
|
|
2160
|
+
lastTagWasSelfClosing = false;
|
|
2161
|
+
}
|
|
2162
|
+
break;
|
|
1864
2163
|
case Content:
|
|
1865
2164
|
current.childCount++;
|
|
1866
2165
|
dom.push(text(parseText(token.text)));
|
|
1867
2166
|
break;
|
|
1868
2167
|
case TagNameEnd:
|
|
1869
|
-
stack.
|
|
2168
|
+
if (stack.length > 1) {
|
|
2169
|
+
stack.pop();
|
|
2170
|
+
}
|
|
1870
2171
|
current = stack.at(-1) || root;
|
|
1871
2172
|
break;
|
|
1872
2173
|
case TagNameStart:
|
|
1873
2174
|
current.childCount++;
|
|
1874
|
-
|
|
2175
|
+
const newNode = {
|
|
1875
2176
|
childCount: 0,
|
|
1876
2177
|
type: getVirtualDomTag(token.text)
|
|
1877
2178
|
};
|
|
1878
|
-
dom.push(
|
|
1879
|
-
|
|
2179
|
+
dom.push(newNode);
|
|
2180
|
+
current = newNode;
|
|
2181
|
+
lastTagWasSelfClosing = isSelfClosingTag(token.text);
|
|
2182
|
+
if (!lastTagWasSelfClosing) {
|
|
1880
2183
|
stack.push(current);
|
|
1881
2184
|
}
|
|
1882
2185
|
break;
|
|
2186
|
+
case WhitespaceInsideOpeningTag:
|
|
2187
|
+
// Handle boolean attributes (attributes without values)
|
|
2188
|
+
if (attributeName && (allAllowedAttributes.has(attributeName) || useBuiltInDefaults && isDefaultAllowedAttribute(attributeName, defaultAllowedAttributes))) {
|
|
2189
|
+
const finalAttributeName = attributeName === 'class' ? 'className' : attributeName;
|
|
2190
|
+
current[finalAttributeName] = attributeName;
|
|
2191
|
+
}
|
|
2192
|
+
attributeName = '';
|
|
2193
|
+
break;
|
|
1883
2194
|
}
|
|
1884
2195
|
}
|
|
2196
|
+
try {
|
|
2197
|
+
Object.defineProperty(dom, 'rootChildCount', {
|
|
2198
|
+
configurable: true,
|
|
2199
|
+
enumerable: false,
|
|
2200
|
+
value: root.childCount
|
|
2201
|
+
});
|
|
2202
|
+
} catch {
|
|
2203
|
+
dom.rootChildCount = root.childCount;
|
|
2204
|
+
}
|
|
1885
2205
|
return dom;
|
|
1886
2206
|
};
|
|
1887
2207
|
|
|
2208
|
+
const handleEditorChanged = async () => {
|
|
2209
|
+
// Get all preview instance keys
|
|
2210
|
+
const previewKeys = getKeys$1();
|
|
2211
|
+
|
|
2212
|
+
// Get all editor keys from the editor worker
|
|
2213
|
+
const editorKeys = await invoke$1('Editor.getKeys');
|
|
2214
|
+
|
|
2215
|
+
// For each preview instance
|
|
2216
|
+
for (const previewUid of previewKeys) {
|
|
2217
|
+
const {
|
|
2218
|
+
newState: state
|
|
2219
|
+
} = get(previewUid);
|
|
2220
|
+
|
|
2221
|
+
// Skip if no URI is set
|
|
2222
|
+
if (!state.uri) {
|
|
2223
|
+
continue;
|
|
2224
|
+
}
|
|
2225
|
+
|
|
2226
|
+
// Find the editor that matches our preview's URI
|
|
2227
|
+
let matchingEditorUid = null;
|
|
2228
|
+
for (const editorKey of editorKeys) {
|
|
2229
|
+
const editorUid = Number.parseFloat(editorKey);
|
|
2230
|
+
const editorUri = await invoke$1('Editor.getUri', editorUid);
|
|
2231
|
+
if (editorUri === state.uri) {
|
|
2232
|
+
matchingEditorUid = editorUid;
|
|
2233
|
+
break;
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
|
|
2237
|
+
// If we found a matching editor, get its text and update the preview
|
|
2238
|
+
if (matchingEditorUid !== null) {
|
|
2239
|
+
try {
|
|
2240
|
+
const content = await invoke$1('Editor.getText', matchingEditorUid);
|
|
2241
|
+
const parsedDom = parseHtml(content, []);
|
|
2242
|
+
const updatedState = {
|
|
2243
|
+
...state,
|
|
2244
|
+
content,
|
|
2245
|
+
errorMessage: '',
|
|
2246
|
+
parsedDom
|
|
2247
|
+
};
|
|
2248
|
+
set(previewUid, state, updatedState);
|
|
2249
|
+
} catch (error) {
|
|
2250
|
+
// If getting text fails, update with error message
|
|
2251
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
2252
|
+
const updatedState = {
|
|
2253
|
+
...state,
|
|
2254
|
+
content: '',
|
|
2255
|
+
errorMessage,
|
|
2256
|
+
parsedDom: []
|
|
2257
|
+
};
|
|
2258
|
+
set(previewUid, state, updatedState);
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
}
|
|
2262
|
+
|
|
2263
|
+
// Rerender all previews after updates are complete
|
|
2264
|
+
await invoke('Preview.rerender');
|
|
2265
|
+
};
|
|
2266
|
+
|
|
2267
|
+
const getParsedNodesChildNodeCount = parsedDom => {
|
|
2268
|
+
array(parsedDom);
|
|
2269
|
+
const rootCountFromParse = parsedDom.rootChildCount;
|
|
2270
|
+
if (typeof rootCountFromParse === 'number') {
|
|
2271
|
+
return rootCountFromParse;
|
|
2272
|
+
}
|
|
2273
|
+
let rootChildCount = 0;
|
|
2274
|
+
let i = 0;
|
|
2275
|
+
while (i < parsedDom.length) {
|
|
2276
|
+
rootChildCount++;
|
|
2277
|
+
|
|
2278
|
+
// skip the entire subtree of the current node
|
|
2279
|
+
let toSkip = parsedDom[i].childCount;
|
|
2280
|
+
i++;
|
|
2281
|
+
while (toSkip > 0 && i < parsedDom.length) {
|
|
2282
|
+
toSkip -= 1;
|
|
2283
|
+
toSkip += parsedDom[i].childCount;
|
|
2284
|
+
i++;
|
|
2285
|
+
}
|
|
2286
|
+
}
|
|
2287
|
+
return rootChildCount;
|
|
2288
|
+
};
|
|
2289
|
+
|
|
1888
2290
|
const updateContent = async (state, uri) => {
|
|
1889
2291
|
try {
|
|
1890
2292
|
// Read the file content using RendererWorker RPC
|
|
@@ -1892,11 +2294,13 @@ const updateContent = async (state, uri) => {
|
|
|
1892
2294
|
const content = await readFile(uri);
|
|
1893
2295
|
|
|
1894
2296
|
// Parse the content into virtual DOM
|
|
1895
|
-
const parsedDom = parseHtml(content
|
|
2297
|
+
const parsedDom = parseHtml(content);
|
|
2298
|
+
const parsedNodesChildNodeCount = getParsedNodesChildNodeCount(parsedDom);
|
|
1896
2299
|
return {
|
|
1897
2300
|
content,
|
|
1898
2301
|
errorMessage: '',
|
|
1899
|
-
parsedDom
|
|
2302
|
+
parsedDom,
|
|
2303
|
+
parsedNodesChildNodeCount
|
|
1900
2304
|
};
|
|
1901
2305
|
} catch (error) {
|
|
1902
2306
|
// If file reading or parsing fails, return empty content and parsedDom with error message
|
|
@@ -1904,7 +2308,8 @@ const updateContent = async (state, uri) => {
|
|
|
1904
2308
|
return {
|
|
1905
2309
|
content: '',
|
|
1906
2310
|
errorMessage,
|
|
1907
|
-
parsedDom: []
|
|
2311
|
+
parsedDom: [],
|
|
2312
|
+
parsedNodesChildNodeCount: 0
|
|
1908
2313
|
};
|
|
1909
2314
|
}
|
|
1910
2315
|
};
|
|
@@ -1913,21 +2318,50 @@ const handleFileEdited = async state => {
|
|
|
1913
2318
|
const {
|
|
1914
2319
|
content,
|
|
1915
2320
|
errorMessage,
|
|
1916
|
-
parsedDom
|
|
2321
|
+
parsedDom,
|
|
2322
|
+
parsedNodesChildNodeCount
|
|
1917
2323
|
} = await updateContent(state, state.uri);
|
|
1918
2324
|
return {
|
|
1919
2325
|
...state,
|
|
1920
2326
|
content,
|
|
1921
2327
|
errorMessage,
|
|
1922
|
-
parsedDom
|
|
2328
|
+
parsedDom,
|
|
2329
|
+
parsedNodesChildNodeCount
|
|
1923
2330
|
};
|
|
1924
2331
|
};
|
|
1925
2332
|
|
|
1926
2333
|
const loadContent = async state => {
|
|
2334
|
+
// Try to register to receive editor change notifications from the editor worker.
|
|
2335
|
+
// Use dynamic access and ignore errors so this is safe in environments where
|
|
2336
|
+
// the EditorWorker / ListenerType are not available (e.g. unit tests).
|
|
2337
|
+
const EditorChange = 1;
|
|
2338
|
+
const rpcId = 9112;
|
|
2339
|
+
try {
|
|
2340
|
+
await invoke$1('Listener.register', EditorChange, rpcId);
|
|
2341
|
+
} catch (error) {
|
|
2342
|
+
console.error(error);
|
|
2343
|
+
}
|
|
2344
|
+
|
|
2345
|
+
// Read and parse file contents if we have a URI
|
|
2346
|
+
const {
|
|
2347
|
+
content,
|
|
2348
|
+
errorMessage,
|
|
2349
|
+
parsedDom,
|
|
2350
|
+
parsedNodesChildNodeCount
|
|
2351
|
+
} = state.uri ? await updateContent(state, state.uri) : {
|
|
2352
|
+
content: state.content,
|
|
2353
|
+
errorMessage: state.errorMessage,
|
|
2354
|
+
parsedDom: state.parsedDom,
|
|
2355
|
+
parsedNodesChildNodeCount: state.parsedNodesChildNodeCount
|
|
2356
|
+
};
|
|
1927
2357
|
return {
|
|
1928
2358
|
...state,
|
|
2359
|
+
content,
|
|
1929
2360
|
errorCount: 0,
|
|
2361
|
+
errorMessage,
|
|
1930
2362
|
initial: false,
|
|
2363
|
+
parsedDom,
|
|
2364
|
+
parsedNodesChildNodeCount,
|
|
1931
2365
|
warningCount: 1
|
|
1932
2366
|
};
|
|
1933
2367
|
};
|
|
@@ -1947,18 +2381,22 @@ const getEmptyPreviewDom = () => {
|
|
|
1947
2381
|
};
|
|
1948
2382
|
|
|
1949
2383
|
const getPreviewDom = state => {
|
|
1950
|
-
|
|
2384
|
+
const {
|
|
2385
|
+
parsedDom,
|
|
2386
|
+
parsedNodesChildNodeCount,
|
|
2387
|
+
uri
|
|
2388
|
+
} = state;
|
|
2389
|
+
if (!uri) {
|
|
1951
2390
|
return getEmptyPreviewDom();
|
|
1952
2391
|
}
|
|
1953
2392
|
|
|
1954
2393
|
// If parsedDom is available, render it as children of the wrapper
|
|
1955
|
-
if (
|
|
2394
|
+
if (parsedDom && parsedDom.length > 0) {
|
|
1956
2395
|
return [{
|
|
1957
|
-
childCount:
|
|
1958
|
-
// TODO
|
|
2396
|
+
childCount: parsedNodesChildNodeCount,
|
|
1959
2397
|
className: 'Viewlet Preview',
|
|
1960
2398
|
type: Div$1
|
|
1961
|
-
}, ...
|
|
2399
|
+
}, ...parsedDom];
|
|
1962
2400
|
}
|
|
1963
2401
|
return [{
|
|
1964
2402
|
childCount: 1,
|
|
@@ -2034,6 +2472,18 @@ const renderEventListeners = () => {
|
|
|
2034
2472
|
}];
|
|
2035
2473
|
};
|
|
2036
2474
|
|
|
2475
|
+
const rerender = state => {
|
|
2476
|
+
// Create a new copy of parsedDom array to trigger diff
|
|
2477
|
+
const parsedDom = [...state.parsedDom];
|
|
2478
|
+
|
|
2479
|
+
// Return a new state object with the copied parsedDom
|
|
2480
|
+
// This will cause DiffItems.isEqual to return false since parsedDom reference changed
|
|
2481
|
+
return {
|
|
2482
|
+
...state,
|
|
2483
|
+
parsedDom
|
|
2484
|
+
};
|
|
2485
|
+
};
|
|
2486
|
+
|
|
2037
2487
|
const resize = (state, dimensions) => {
|
|
2038
2488
|
return {
|
|
2039
2489
|
...state,
|
|
@@ -2051,18 +2501,21 @@ const setUri = async (state, uri) => {
|
|
|
2051
2501
|
const {
|
|
2052
2502
|
content,
|
|
2053
2503
|
errorMessage,
|
|
2054
|
-
parsedDom
|
|
2504
|
+
parsedDom,
|
|
2505
|
+
parsedNodesChildNodeCount
|
|
2055
2506
|
} = await updateContent(state, uri);
|
|
2056
2507
|
return {
|
|
2057
2508
|
...state,
|
|
2058
2509
|
content,
|
|
2059
2510
|
errorMessage,
|
|
2060
2511
|
parsedDom,
|
|
2512
|
+
parsedNodesChildNodeCount,
|
|
2061
2513
|
uri
|
|
2062
2514
|
};
|
|
2063
2515
|
};
|
|
2064
2516
|
|
|
2065
2517
|
const commandMap = {
|
|
2518
|
+
handleEditorChanged: handleEditorChanged,
|
|
2066
2519
|
'Preview.create': create,
|
|
2067
2520
|
'Preview.diff2': diff2,
|
|
2068
2521
|
'Preview.getCommandIds': getCommandIds,
|
|
@@ -2070,6 +2523,7 @@ const commandMap = {
|
|
|
2070
2523
|
'Preview.loadContent': wrapCommand(loadContent),
|
|
2071
2524
|
'Preview.render2': render2,
|
|
2072
2525
|
'Preview.renderEventListeners': renderEventListeners,
|
|
2526
|
+
'Preview.rerender': wrapCommand(rerender),
|
|
2073
2527
|
'Preview.resize': wrapCommand(resize),
|
|
2074
2528
|
'Preview.saveState': wrapGetter(saveState),
|
|
2075
2529
|
'Preview.setUri': wrapCommand(setUri),
|
|
@@ -2082,6 +2536,11 @@ const listen = async () => {
|
|
|
2082
2536
|
commandMap: commandMap
|
|
2083
2537
|
});
|
|
2084
2538
|
set$1(rpc);
|
|
2539
|
+
const editorRpc = await LazyTransferMessagePortRpcParent.create({
|
|
2540
|
+
commandMap: {},
|
|
2541
|
+
send: port => sendMessagePortToEditorWorker(port, 9112)
|
|
2542
|
+
});
|
|
2543
|
+
set$2(editorRpc);
|
|
2085
2544
|
};
|
|
2086
2545
|
|
|
2087
2546
|
const main = async () => {
|