@lvce-editor/preview-worker 1.2.0 → 1.4.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.
@@ -54,6 +54,55 @@ class VError extends Error {
54
54
  }
55
55
  }
56
56
 
57
+ class AssertionError extends Error {
58
+ constructor(message) {
59
+ super(message);
60
+ this.name = 'AssertionError';
61
+ }
62
+ }
63
+ const Object$1 = 1;
64
+ const Number$1 = 2;
65
+ const Array$1 = 3;
66
+ const String = 4;
67
+ const Boolean = 5;
68
+ const Function = 6;
69
+ const Null = 7;
70
+ const Unknown = 8;
71
+ const getType = value => {
72
+ switch (typeof value) {
73
+ case 'number':
74
+ return Number$1;
75
+ case 'function':
76
+ return Function;
77
+ case 'string':
78
+ return String;
79
+ case 'object':
80
+ if (value === null) {
81
+ return Null;
82
+ }
83
+ if (Array.isArray(value)) {
84
+ return Array$1;
85
+ }
86
+ return Object$1;
87
+ case 'boolean':
88
+ return Boolean;
89
+ default:
90
+ return Unknown;
91
+ }
92
+ };
93
+ const array = value => {
94
+ const type = getType(value);
95
+ if (type !== Array$1) {
96
+ throw new AssertionError('expected value to be of type array');
97
+ }
98
+ };
99
+ const string = value => {
100
+ const type = getType(value);
101
+ if (type !== String) {
102
+ throw new AssertionError('expected value to be of type string');
103
+ }
104
+ };
105
+
57
106
  const isMessagePort = value => {
58
107
  return value && value instanceof MessagePort;
59
108
  };
@@ -368,6 +417,100 @@ const IpcChildWithModuleWorkerAndMessagePort$1 = {
368
417
  listen: listen$6,
369
418
  wrap: wrap$e
370
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
+ };
371
514
 
372
515
  const Two$1 = '2.0';
373
516
  const callbacks = Object.create(null);
@@ -583,7 +726,7 @@ const getErrorResponse = (id, error, preparePrettyError, logError) => {
583
726
  const errorProperty = getErrorProperty(error, prettyError);
584
727
  return create$1$1(id, errorProperty);
585
728
  };
586
- const create$3 = (message, result) => {
729
+ const create$4 = (message, result) => {
587
730
  return {
588
731
  jsonrpc: Two$1,
589
732
  id: message.id,
@@ -592,7 +735,7 @@ const create$3 = (message, result) => {
592
735
  };
593
736
  const getSuccessResponse = (message, result) => {
594
737
  const resultProperty = result ?? null;
595
- return create$3(message, resultProperty);
738
+ return create$4(message, resultProperty);
596
739
  };
597
740
  const getErrorResponseSimple = (id, error) => {
598
741
  return {
@@ -820,6 +963,86 @@ const listen$1 = async (module, options) => {
820
963
  const ipc = module.wrap(rawIpc);
821
964
  return ipc;
822
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
+ };
823
1046
  const create$2$1 = async ({
824
1047
  commandMap
825
1048
  }) => {
@@ -854,20 +1077,68 @@ const createMockRpc = ({
854
1077
  return mockRpc;
855
1078
  };
856
1079
 
857
- const Div = 4;
858
- const H1 = 5;
859
- const Text = 12;
1080
+ const Button$1 = 1;
1081
+ const Div$1 = 4;
1082
+ const H1$1 = 5;
1083
+ const Input$1 = 6;
1084
+ const Span$1 = 8;
1085
+ const Table$1 = 9;
1086
+ const TBody$1 = 10;
1087
+ const Td$1 = 11;
1088
+ const Text$1 = 12;
1089
+ const Th$1 = 13;
1090
+ const THead$1 = 14;
1091
+ const Tr$1 = 15;
1092
+ const Img$1 = 17;
1093
+ const Del$1 = 21;
1094
+ const H2$1 = 22;
1095
+ const H3$1 = 23;
1096
+ const H4$1 = 24;
1097
+ const H5$1 = 25;
1098
+ const H6$1 = 26;
1099
+ const Article$1 = 27;
1100
+ const Aside$1 = 28;
1101
+ const Footer$1 = 29;
1102
+ const Header$1 = 30;
1103
+ const Nav$1 = 40;
1104
+ const Section$1 = 41;
1105
+ const Search$1 = 42;
1106
+ const Dd$1 = 43;
1107
+ const Dl$1 = 44;
1108
+ const Figcaption$1 = 45;
1109
+ const Figure$1 = 46;
1110
+ const Hr$1 = 47;
1111
+ const Li$1 = 48;
1112
+ const Ol$1 = 49;
1113
+ const P$1 = 50;
1114
+ const Pre$1 = 51;
1115
+ const A$1 = 53;
1116
+ const Abbr$1 = 54;
1117
+ const Br$1 = 55;
1118
+ const Cite$1 = 56;
1119
+ const Data$1 = 57;
1120
+ const Time$1 = 58;
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;
860
1130
  const Reference = 100;
861
1131
 
862
1132
  const TargetName = 'event.target.name';
863
1133
 
1134
+ const EditorWorker = 99;
864
1135
  const RendererWorker = 1;
865
1136
 
866
1137
  const SetDom2 = 'Viewlet.setDom2';
867
1138
  const SetPatches = 'Viewlet.setPatches';
868
1139
 
869
1140
  const rpcs = Object.create(null);
870
- const set$2 = (id, rpc) => {
1141
+ const set$3 = (id, rpc) => {
871
1142
  rpcs[id] = rpc;
872
1143
  };
873
1144
  const get$1 = id => {
@@ -900,7 +1171,7 @@ const create$2 = rpcId => {
900
1171
  const mockRpc = createMockRpc({
901
1172
  commandMap
902
1173
  });
903
- set$2(rpcId, mockRpc);
1174
+ set$3(rpcId, mockRpc);
904
1175
  // @ts-ignore
905
1176
  mockRpc[Symbol.dispose] = () => {
906
1177
  remove(rpcId);
@@ -909,14 +1180,28 @@ const create$2 = rpcId => {
909
1180
  return mockRpc;
910
1181
  },
911
1182
  set(rpc) {
912
- set$2(rpcId, rpc);
1183
+ set$3(rpcId, rpc);
913
1184
  }
914
1185
  };
915
1186
  };
916
1187
 
917
1188
  const {
1189
+ invoke: invoke$1,
1190
+ set: set$2
1191
+ } = create$2(EditorWorker);
1192
+
1193
+ const {
1194
+ invoke,
1195
+ invokeAndTransfer,
918
1196
  set: set$1
919
1197
  } = create$2(RendererWorker);
1198
+ const sendMessagePortToEditorWorker = async (port, rpcId) => {
1199
+ const command = 'HandleMessagePort.handleMessagePort';
1200
+ await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToEditorWorker', port, command, rpcId);
1201
+ };
1202
+ const readFile = async uri => {
1203
+ return invoke('FileSystem.readFile', uri);
1204
+ };
920
1205
 
921
1206
  const toCommandId = key => {
922
1207
  const dotIndex = key.indexOf('.');
@@ -1010,6 +1295,7 @@ const terminate = () => {
1010
1295
  const {
1011
1296
  get,
1012
1297
  getCommandIds,
1298
+ getKeys: getKeys$1,
1013
1299
  registerCommands,
1014
1300
  set,
1015
1301
  wrapCommand,
@@ -1021,8 +1307,10 @@ const create = (uid, uri, x, y, width, height, platform, assetDir) => {
1021
1307
  assetDir,
1022
1308
  content: '',
1023
1309
  errorCount: 0,
1310
+ errorMessage: '',
1024
1311
  initial: true,
1025
1312
  parsedDom: [],
1313
+ parsedNodesChildNodeCount: 0,
1026
1314
  platform,
1027
1315
  uid,
1028
1316
  uri,
@@ -1032,7 +1320,7 @@ const create = (uid, uri, x, y, width, height, platform, assetDir) => {
1032
1320
  };
1033
1321
 
1034
1322
  const isEqual = (oldState, newState) => {
1035
- return oldState.warningCount === newState.warningCount && oldState.initial === newState.initial;
1323
+ return oldState.warningCount === newState.warningCount && oldState.initial === newState.initial && oldState.content === newState.content && oldState.parsedDom === newState.parsedDom && oldState.parsedNodesChildNodeCount === newState.parsedNodesChildNodeCount;
1036
1324
  };
1037
1325
 
1038
1326
  const RenderItems = 4;
@@ -1061,12 +1349,11 @@ const diff2 = uid => {
1061
1349
  return result;
1062
1350
  };
1063
1351
 
1064
- const loadContent = async state => {
1352
+ const text = data => {
1065
1353
  return {
1066
- ...state,
1067
- errorCount: 0,
1068
- initial: false,
1069
- warningCount: 1
1354
+ childCount: 0,
1355
+ text: data,
1356
+ type: Text$1
1070
1357
  };
1071
1358
  };
1072
1359
 
@@ -1158,7 +1445,7 @@ const compareNodes = (oldNode, newNode) => {
1158
1445
  return patches;
1159
1446
  }
1160
1447
  // Handle text nodes
1161
- if (oldNode.type === Text && newNode.type === Text) {
1448
+ if (oldNode.type === Text$1 && newNode.type === Text$1) {
1162
1449
  if (oldNode.text !== newNode.text) {
1163
1450
  patches.push({
1164
1451
  type: SetText,
@@ -1358,33 +1645,747 @@ const diffTree = (oldNodes, newNodes) => {
1358
1645
  return removeTrailingNavigationPatches(patches);
1359
1646
  };
1360
1647
 
1648
+ const Div = 'div';
1649
+ const H1 = 'h1';
1650
+ const H2 = 'h2';
1651
+ const H3 = 'h3';
1652
+ const H4 = 'h4';
1653
+ const H5 = 'h5';
1654
+ const Img = 'img';
1655
+ const Span = 'span';
1656
+ const Article = 'article';
1657
+ const Aside = 'aside';
1658
+ const Footer = 'footer';
1659
+ const Header = 'header';
1660
+ const Nav = 'nav';
1661
+ const Section = 'section';
1662
+ const Search = 'search';
1663
+ const Dd = 'dd';
1664
+ const Dl = 'dl';
1665
+ const Figcaption = 'figcaption';
1666
+ const Figure = 'figure';
1667
+ const Hr = 'hr';
1668
+ const Li = 'li';
1669
+ const Ol = 'ol';
1670
+ const P = 'p';
1671
+ const Pre = 'pre';
1672
+ const A = 'a';
1673
+ const Abbr = 'abbr';
1674
+ const Br = 'br';
1675
+ const Cite = 'cite';
1676
+ const Data = 'data';
1677
+ const Time = 'time';
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';
1698
+
1699
+ const getVirtualDomTag = text => {
1700
+ switch (text) {
1701
+ case A:
1702
+ return A$1;
1703
+ case Abbr:
1704
+ return Abbr$1;
1705
+ case Article:
1706
+ return Article$1;
1707
+ case Aside:
1708
+ return Aside$1;
1709
+ case Br:
1710
+ return Br$1;
1711
+ case Button:
1712
+ return Button$1;
1713
+ case Cite:
1714
+ return Cite$1;
1715
+ case Code:
1716
+ return Code$1;
1717
+ case Data:
1718
+ return Data$1;
1719
+ case Dd:
1720
+ return Dd$1;
1721
+ case Del:
1722
+ return Del$1;
1723
+ case Div:
1724
+ return Div$1;
1725
+ case Dl:
1726
+ return Dl$1;
1727
+ case Dt:
1728
+ return Dt$1;
1729
+ case Figcaption:
1730
+ return Figcaption$1;
1731
+ case Figure:
1732
+ return Figure$1;
1733
+ case Footer:
1734
+ return Footer$1;
1735
+ case Form:
1736
+ return Div$1;
1737
+ case H1:
1738
+ return H1$1;
1739
+ case H2:
1740
+ return H2$1;
1741
+ case H3:
1742
+ return H3$1;
1743
+ case H4:
1744
+ return H4$1;
1745
+ case H5:
1746
+ return H5$1;
1747
+ case H6:
1748
+ return H6$1;
1749
+ case Header:
1750
+ return Header$1;
1751
+ case Hr:
1752
+ return Hr$1;
1753
+ case Iframe:
1754
+ return Iframe$1;
1755
+ case Img:
1756
+ return Img$1;
1757
+ case Input:
1758
+ return Input$1;
1759
+ case Label:
1760
+ return Label$1;
1761
+ case Li:
1762
+ return Li$1;
1763
+ case Nav:
1764
+ return Nav$1;
1765
+ case Ol:
1766
+ return Ol$1;
1767
+ case Option:
1768
+ return Option$1;
1769
+ case P:
1770
+ return P$1;
1771
+ case Pre:
1772
+ return Pre$1;
1773
+ case Search:
1774
+ return Search$1;
1775
+ case Section:
1776
+ return Section$1;
1777
+ case Select:
1778
+ return Select$1;
1779
+ case Span:
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;
1789
+ case Tfoot:
1790
+ return Tfoot$1;
1791
+ case Th:
1792
+ return Th$1;
1793
+ case THead:
1794
+ return THead$1;
1795
+ case Time:
1796
+ return Time$1;
1797
+ case Tr:
1798
+ return Tr$1;
1799
+ case Ul:
1800
+ return Ul$1;
1801
+ default:
1802
+ return Div$1;
1803
+ }
1804
+ };
1805
+
1806
+ const None = 0;
1807
+ const OpeningAngleBracket = 1;
1808
+ const ClosingAngleBracket = 2;
1809
+ const TagNameStart = 3;
1810
+ const TagNameEnd = 4;
1811
+ const Content = 5;
1812
+ const ClosingTagSlash = 6;
1813
+ const WhitespaceInsideOpeningTag = 7;
1814
+ const AttributeName = 8;
1815
+ const AttributeEqualSign = 9;
1816
+ const AttributeQuoteStart = 10;
1817
+ const AttributeValue = 11;
1818
+ const AttributeQuoteEnd = 12;
1819
+ const WhitespaceAfterClosingTagSlash = 13;
1820
+ const WhitespaceAfterOpeningTagOpenAngleBracket = 14;
1821
+ const ExclamationMark = 15;
1822
+ const Doctype = 16;
1823
+ const StartCommentDashes = 17;
1824
+ const Comment = 18;
1825
+ const EndCommentTag = 19;
1826
+ const Text = 20;
1827
+ const CommentStart = 21;
1828
+
1829
+ const isSelfClosingTag = tag => {
1830
+ switch (tag) {
1831
+ case Br:
1832
+ case Hr:
1833
+ case Img:
1834
+ case Input:
1835
+ return true;
1836
+ default:
1837
+ return false;
1838
+ }
1839
+ };
1840
+
1841
+ const parseText = text => {
1842
+ return text.replaceAll('&gt;', '>').replaceAll('&lt;', '<').replaceAll('&amp;', '&');
1843
+ };
1844
+
1845
+ class UnexpectedTokenError extends Error {
1846
+ constructor() {
1847
+ super('Unexpected token');
1848
+ this.name = 'UnexpectedTokenError';
1849
+ }
1850
+ }
1851
+
1852
+ const State = {
1853
+ AfterAttributeEqualSign: 8,
1854
+ AfterAttributeName: 7,
1855
+ AfterAttributeValueClosingQuote: 11,
1856
+ AfterAttributeValueInsideDoubleQuote: 10,
1857
+ AfterClosingTagName: 5,
1858
+ AfterClosingTagSlash: 4,
1859
+ AfterExclamationMark: 16,
1860
+ AfterOpeningAngleBracket: 2,
1861
+ InsideAttributeAfterDoubleQuote: 9,
1862
+ InsideComment: 17,
1863
+ InsideOpeningTag: 3,
1864
+ InsideOpeningTagAfterWhitespace: 6,
1865
+ TopLevelContent: 1
1866
+ };
1867
+ const RE_ANGLE_BRACKET_OPEN = /^</;
1868
+ const RE_ANGLE_BRACKET_OPEN_TAG = /^<(?![\s!%])/;
1869
+ const RE_ANGLE_BRACKET_CLOSE = /^>/;
1870
+ const RE_SLASH = /^\//;
1871
+ const RE_TAGNAME = /^[a-zA-Z\d$]+/;
1872
+ const RE_CONTENT = /^[^<>]+/;
1873
+ const RE_WHITESPACE = /^\s+/;
1874
+ const RE_ATTRIBUTE_NAME = /^[a-zA-Z\d-]+/;
1875
+ const RE_EQUAL_SIGN = /^=/;
1876
+ const RE_DOUBLE_QUOTE = /^"/;
1877
+ const RE_ATTRIBUTE_VALUE_INSIDE_DOUBLE_QUOTE = /^[^"\n]+/;
1878
+ const RE_TEXT = /^[^<>]+/;
1879
+ const RE_EXCLAMATION_MARK = /^!/;
1880
+ const RE_DASH_DASH = /^--/;
1881
+ const RE_DOCTYPE = /^doctype/i;
1882
+ const RE_BLOCK_COMMENT_CONTENT = /^[a-zA-Z\s]+/;
1883
+ const RE_COMMENT_END = /^-->/;
1884
+ const RE_TAG_TEXT = /^[^\s>]+/;
1885
+ const RE_ANY_TEXT = /^[^\n]+/;
1886
+ const RE_ATTRIBUTE_TEXT = /^[^\n<>/\s]+/;
1887
+ const RE_BLOCK_COMMENT_START = /^<!--/;
1888
+ const RE_SELF_CLOSING = /^\/>/;
1889
+ const tokenizeHtml = text => {
1890
+ string(text);
1891
+ let state = State.TopLevelContent;
1892
+ let index = 0;
1893
+ let next;
1894
+ const tokens = [];
1895
+ let token = None;
1896
+ while (index < text.length) {
1897
+ const part = text.slice(index);
1898
+ switch (state) {
1899
+ case State.AfterAttributeEqualSign:
1900
+ if (next = part.match(RE_DOUBLE_QUOTE)) {
1901
+ token = AttributeQuoteStart;
1902
+ state = State.InsideAttributeAfterDoubleQuote;
1903
+ } else if (next = part.match(RE_ANGLE_BRACKET_CLOSE)) {
1904
+ token = ClosingAngleBracket;
1905
+ state = State.TopLevelContent;
1906
+ } else if (next = part.match(RE_ATTRIBUTE_TEXT)) {
1907
+ token = AttributeValue;
1908
+ state = State.InsideOpeningTag;
1909
+ } else {
1910
+ throw new UnexpectedTokenError();
1911
+ }
1912
+ break;
1913
+ case State.AfterAttributeName:
1914
+ if (next = part.match(RE_EQUAL_SIGN)) {
1915
+ token = AttributeEqualSign;
1916
+ state = State.AfterAttributeEqualSign;
1917
+ } else if (next = part.match(RE_ANGLE_BRACKET_CLOSE)) {
1918
+ token = ClosingAngleBracket;
1919
+ state = State.TopLevelContent;
1920
+ } else if (next = part.match(RE_WHITESPACE)) {
1921
+ token = WhitespaceInsideOpeningTag;
1922
+ state = State.InsideOpeningTagAfterWhitespace;
1923
+ } else if (next = part.match(RE_ANGLE_BRACKET_OPEN)) {
1924
+ token = OpeningAngleBracket;
1925
+ state = State.AfterOpeningAngleBracket;
1926
+ } else {
1927
+ text.slice(index); // ?
1928
+ throw new UnexpectedTokenError();
1929
+ }
1930
+ break;
1931
+ case State.AfterAttributeValueClosingQuote:
1932
+ if (next = part.match(RE_ANGLE_BRACKET_CLOSE)) {
1933
+ token = ClosingAngleBracket;
1934
+ state = State.TopLevelContent;
1935
+ } else if (next = part.match(RE_WHITESPACE)) {
1936
+ token = WhitespaceInsideOpeningTag;
1937
+ state = State.InsideOpeningTagAfterWhitespace;
1938
+ } else if (next = part.match(RE_SELF_CLOSING)) {
1939
+ token = ClosingAngleBracket;
1940
+ state = State.TopLevelContent;
1941
+ } else {
1942
+ throw new UnexpectedTokenError();
1943
+ }
1944
+ break;
1945
+ case State.AfterAttributeValueInsideDoubleQuote:
1946
+ if (next = part.match(RE_DOUBLE_QUOTE)) {
1947
+ token = AttributeQuoteEnd;
1948
+ state = State.AfterAttributeValueClosingQuote;
1949
+ } else {
1950
+ throw new UnexpectedTokenError();
1951
+ }
1952
+ break;
1953
+ case State.AfterClosingTagName:
1954
+ if (next = part.match(RE_ANGLE_BRACKET_CLOSE)) {
1955
+ token = ClosingAngleBracket;
1956
+ state = State.TopLevelContent;
1957
+ } else if (next = part.match(RE_WHITESPACE)) {
1958
+ token = Content;
1959
+ state = State.TopLevelContent;
1960
+ } else {
1961
+ throw new UnexpectedTokenError();
1962
+ }
1963
+ break;
1964
+ case State.AfterClosingTagSlash:
1965
+ if (next = part.match(RE_TAGNAME)) {
1966
+ token = TagNameEnd;
1967
+ state = State.AfterClosingTagName;
1968
+ } else if (next = part.match(RE_WHITESPACE)) {
1969
+ token = WhitespaceAfterClosingTagSlash;
1970
+ state = State.TopLevelContent;
1971
+ } else if (next = part.match(RE_ANGLE_BRACKET_CLOSE)) {
1972
+ token = ClosingAngleBracket;
1973
+ state = State.TopLevelContent;
1974
+ } else {
1975
+ throw new UnexpectedTokenError();
1976
+ }
1977
+ break;
1978
+ case State.AfterExclamationMark:
1979
+ if (next = part.match(RE_DASH_DASH)) {
1980
+ token = StartCommentDashes;
1981
+ state = State.InsideComment;
1982
+ } else if (next = part.match(RE_DOCTYPE)) {
1983
+ token = Doctype;
1984
+ state = State.InsideOpeningTag;
1985
+ } else {
1986
+ text.slice(index); // ?
1987
+ throw new UnexpectedTokenError();
1988
+ }
1989
+ break;
1990
+ case State.AfterOpeningAngleBracket:
1991
+ if (next = part.match(RE_TAGNAME)) {
1992
+ token = TagNameStart;
1993
+ state = State.InsideOpeningTag;
1994
+ } else if (next = part.match(RE_SLASH)) {
1995
+ token = ClosingTagSlash;
1996
+ state = State.AfterClosingTagSlash;
1997
+ } else if (next = part.match(RE_WHITESPACE)) {
1998
+ token = WhitespaceAfterOpeningTagOpenAngleBracket;
1999
+ state = State.TopLevelContent;
2000
+ } else if (next = part.match(RE_ANGLE_BRACKET_CLOSE)) {
2001
+ token = ClosingAngleBracket;
2002
+ state = State.TopLevelContent;
2003
+ } else if (next = part.match(RE_EXCLAMATION_MARK)) {
2004
+ token = ExclamationMark;
2005
+ state = State.AfterExclamationMark;
2006
+ } else if (next = part.match(RE_ANY_TEXT)) {
2007
+ token = Text;
2008
+ state = State.TopLevelContent;
2009
+ } else {
2010
+ text.slice(index); // ?
2011
+ throw new UnexpectedTokenError();
2012
+ }
2013
+ break;
2014
+ case State.InsideAttributeAfterDoubleQuote:
2015
+ if (next = text.slice(index).match(RE_ATTRIBUTE_VALUE_INSIDE_DOUBLE_QUOTE)) {
2016
+ token = AttributeValue;
2017
+ state = State.AfterAttributeValueInsideDoubleQuote;
2018
+ } else if (next = part.match(RE_DOUBLE_QUOTE)) {
2019
+ token = AttributeQuoteEnd;
2020
+ state = State.AfterAttributeValueClosingQuote;
2021
+ } else {
2022
+ throw new UnexpectedTokenError();
2023
+ }
2024
+ break;
2025
+ case State.InsideComment:
2026
+ if (next = part.match(RE_BLOCK_COMMENT_CONTENT)) {
2027
+ token = Comment;
2028
+ state = State.InsideComment;
2029
+ } else if (next = part.match(RE_COMMENT_END)) {
2030
+ token = EndCommentTag;
2031
+ state = State.TopLevelContent;
2032
+ } else {
2033
+ text.slice(index); // ?
2034
+ throw new UnexpectedTokenError();
2035
+ }
2036
+ break;
2037
+ case State.InsideOpeningTag:
2038
+ if (next = part.match(RE_ANGLE_BRACKET_CLOSE)) {
2039
+ token = ClosingAngleBracket;
2040
+ state = State.TopLevelContent;
2041
+ } else if (next = part.match(RE_WHITESPACE)) {
2042
+ token = WhitespaceInsideOpeningTag;
2043
+ state = State.InsideOpeningTagAfterWhitespace;
2044
+ } else if (next = part.match(RE_TAG_TEXT)) {
2045
+ token = Text;
2046
+ state = State.TopLevelContent;
2047
+ } else {
2048
+ throw new UnexpectedTokenError();
2049
+ }
2050
+ break;
2051
+ case State.InsideOpeningTagAfterWhitespace:
2052
+ if (next = part.match(RE_ATTRIBUTE_NAME)) {
2053
+ token = AttributeName;
2054
+ state = State.AfterAttributeName;
2055
+ } else if (next = part.match(RE_ANGLE_BRACKET_CLOSE)) {
2056
+ token = ClosingAngleBracket;
2057
+ state = State.TopLevelContent;
2058
+ } else if (next = part.match(RE_SELF_CLOSING)) {
2059
+ token = ClosingAngleBracket;
2060
+ state = State.TopLevelContent;
2061
+ } else if (next = part.match(RE_TEXT)) {
2062
+ token = AttributeName;
2063
+ state = State.AfterAttributeName;
2064
+ } else {
2065
+ text.slice(index).match(RE_TEXT); // ?
2066
+ text.slice(index); // ?
2067
+ throw new UnexpectedTokenError();
2068
+ }
2069
+ break;
2070
+ case State.TopLevelContent:
2071
+ if (next = part.match(RE_ANGLE_BRACKET_OPEN_TAG)) {
2072
+ token = OpeningAngleBracket;
2073
+ state = State.AfterOpeningAngleBracket;
2074
+ } else if (next = part.match(RE_CONTENT)) {
2075
+ token = Content;
2076
+ state = State.TopLevelContent;
2077
+ } else if (next = part.match(RE_BLOCK_COMMENT_START)) {
2078
+ token = CommentStart;
2079
+ state = State.InsideComment;
2080
+ } else if (next = part.match(RE_ANGLE_BRACKET_CLOSE)) {
2081
+ token = Content;
2082
+ state = State.TopLevelContent;
2083
+ } else if (next = part.match(RE_ANGLE_BRACKET_OPEN)) {
2084
+ token = Text;
2085
+ state = State.TopLevelContent;
2086
+ } else {
2087
+ throw new UnexpectedTokenError();
2088
+ }
2089
+ break;
2090
+ default:
2091
+ throw new UnexpectedTokenError();
2092
+ }
2093
+ const tokenText = next[0];
2094
+ tokens.push({
2095
+ text: tokenText,
2096
+ type: token
2097
+ });
2098
+ index += tokenText.length;
2099
+ }
2100
+ return tokens;
2101
+ };
2102
+
2103
+ const parseHtml = (html, allowedAttributes) => {
2104
+ string(html);
2105
+ array(allowedAttributes);
2106
+ const tokens = tokenizeHtml(html);
2107
+ const dom = [];
2108
+ const root = {
2109
+ childCount: 0,
2110
+ type: 0
2111
+ };
2112
+ let current = root;
2113
+ const stack = [root];
2114
+ let attributeName = '';
2115
+ let lastTagWasSelfClosing = false;
2116
+ for (const token of tokens) {
2117
+ switch (token.type) {
2118
+ case AttributeName:
2119
+ attributeName = token.text;
2120
+ break;
2121
+ case AttributeValue:
2122
+ if (allowedAttributes.includes(attributeName)) {
2123
+ const finalAttributeName = attributeName === 'class' ? 'className' : attributeName;
2124
+ current[finalAttributeName] = token.text;
2125
+ }
2126
+ attributeName = '';
2127
+ break;
2128
+ case ClosingAngleBracket:
2129
+ // Handle boolean attributes (attributes without values)
2130
+ if (attributeName && allowedAttributes.includes(attributeName)) {
2131
+ const finalAttributeName = attributeName === 'class' ? 'className' : attributeName;
2132
+ current[finalAttributeName] = attributeName;
2133
+ }
2134
+ attributeName = '';
2135
+ // Return to parent if the current tag is self-closing
2136
+ if (lastTagWasSelfClosing) {
2137
+ current = stack.at(-1) || root;
2138
+ lastTagWasSelfClosing = false;
2139
+ }
2140
+ break;
2141
+ case Content:
2142
+ current.childCount++;
2143
+ dom.push(text(parseText(token.text)));
2144
+ break;
2145
+ case TagNameEnd:
2146
+ if (stack.length > 1) {
2147
+ stack.pop();
2148
+ }
2149
+ current = stack.at(-1) || root;
2150
+ break;
2151
+ case TagNameStart:
2152
+ current.childCount++;
2153
+ const newNode = {
2154
+ childCount: 0,
2155
+ type: getVirtualDomTag(token.text)
2156
+ };
2157
+ dom.push(newNode);
2158
+ current = newNode;
2159
+ lastTagWasSelfClosing = isSelfClosingTag(token.text);
2160
+ if (!lastTagWasSelfClosing) {
2161
+ stack.push(current);
2162
+ }
2163
+ break;
2164
+ case WhitespaceInsideOpeningTag:
2165
+ // Handle boolean attributes (attributes without values)
2166
+ if (attributeName && allowedAttributes.includes(attributeName)) {
2167
+ const finalAttributeName = attributeName === 'class' ? 'className' : attributeName;
2168
+ current[finalAttributeName] = attributeName;
2169
+ }
2170
+ attributeName = '';
2171
+ break;
2172
+ }
2173
+ }
2174
+ try {
2175
+ Object.defineProperty(dom, 'rootChildCount', {
2176
+ configurable: true,
2177
+ enumerable: false,
2178
+ value: root.childCount
2179
+ });
2180
+ } catch {
2181
+ dom.rootChildCount = root.childCount;
2182
+ }
2183
+ return dom;
2184
+ };
2185
+
2186
+ const handleEditorChanged = async () => {
2187
+ // Get all preview instance keys
2188
+ const previewKeys = getKeys$1();
2189
+
2190
+ // Get all editor keys from the editor worker
2191
+ const editorKeys = await invoke$1('Editor.getKeys');
2192
+
2193
+ // For each preview instance
2194
+ for (const previewUid of previewKeys) {
2195
+ const {
2196
+ newState: state
2197
+ } = get(previewUid);
2198
+
2199
+ // Skip if no URI is set
2200
+ if (!state.uri) {
2201
+ continue;
2202
+ }
2203
+
2204
+ // Find the editor that matches our preview's URI
2205
+ let matchingEditorUid = null;
2206
+ for (const editorKey of editorKeys) {
2207
+ const editorUid = Number.parseFloat(editorKey);
2208
+ const editorUri = await invoke$1('Editor.getUri', editorUid);
2209
+ if (editorUri === state.uri) {
2210
+ matchingEditorUid = editorUid;
2211
+ break;
2212
+ }
2213
+ }
2214
+
2215
+ // If we found a matching editor, get its text and update the preview
2216
+ if (matchingEditorUid !== null) {
2217
+ try {
2218
+ const content = await invoke$1('Editor.getText', matchingEditorUid);
2219
+ const parsedDom = parseHtml(content, []);
2220
+ const updatedState = {
2221
+ ...state,
2222
+ content,
2223
+ errorMessage: '',
2224
+ parsedDom
2225
+ };
2226
+ set(previewUid, state, updatedState);
2227
+ } catch (error) {
2228
+ // If getting text fails, update with error message
2229
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
2230
+ const updatedState = {
2231
+ ...state,
2232
+ content: '',
2233
+ errorMessage,
2234
+ parsedDom: []
2235
+ };
2236
+ set(previewUid, state, updatedState);
2237
+ }
2238
+ }
2239
+ }
2240
+
2241
+ // Rerender all previews after updates are complete
2242
+ await invoke('Preview.rerender');
2243
+ };
2244
+
2245
+ const getParsedNodesChildNodeCount = parsedDom => {
2246
+ array(parsedDom);
2247
+ const rootCountFromParse = parsedDom.rootChildCount;
2248
+ if (typeof rootCountFromParse === 'number') {
2249
+ return rootCountFromParse;
2250
+ }
2251
+ let rootChildCount = 0;
2252
+ let i = 0;
2253
+ while (i < parsedDom.length) {
2254
+ rootChildCount++;
2255
+
2256
+ // skip the entire subtree of the current node
2257
+ let toSkip = parsedDom[i].childCount;
2258
+ i++;
2259
+ while (toSkip > 0 && i < parsedDom.length) {
2260
+ toSkip -= 1;
2261
+ toSkip += parsedDom[i].childCount;
2262
+ i++;
2263
+ }
2264
+ }
2265
+ return rootChildCount;
2266
+ };
2267
+
2268
+ const updateContent = async (state, uri) => {
2269
+ try {
2270
+ // Read the file content using RendererWorker RPC
2271
+ // @ts-ignore
2272
+ const content = await readFile(uri);
2273
+
2274
+ // Parse the content into virtual DOM
2275
+ const parsedDom = parseHtml(content, []);
2276
+ const parsedNodesChildNodeCount = getParsedNodesChildNodeCount(parsedDom);
2277
+ return {
2278
+ content,
2279
+ errorMessage: '',
2280
+ parsedDom,
2281
+ parsedNodesChildNodeCount
2282
+ };
2283
+ } catch (error) {
2284
+ // If file reading or parsing fails, return empty content and parsedDom with error message
2285
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
2286
+ return {
2287
+ content: '',
2288
+ errorMessage,
2289
+ parsedDom: [],
2290
+ parsedNodesChildNodeCount: 0
2291
+ };
2292
+ }
2293
+ };
2294
+
2295
+ const handleFileEdited = async state => {
2296
+ const {
2297
+ content,
2298
+ errorMessage,
2299
+ parsedDom,
2300
+ parsedNodesChildNodeCount
2301
+ } = await updateContent(state, state.uri);
2302
+ return {
2303
+ ...state,
2304
+ content,
2305
+ errorMessage,
2306
+ parsedDom,
2307
+ parsedNodesChildNodeCount
2308
+ };
2309
+ };
2310
+
2311
+ const loadContent = async state => {
2312
+ // Try to register to receive editor change notifications from the editor worker.
2313
+ // Use dynamic access and ignore errors so this is safe in environments where
2314
+ // the EditorWorker / ListenerType are not available (e.g. unit tests).
2315
+ const EditorChange = 1;
2316
+ const rpcId = 9112;
2317
+ try {
2318
+ await invoke$1('Listener.register', EditorChange, rpcId);
2319
+ } catch (error) {
2320
+ console.error(error);
2321
+ }
2322
+
2323
+ // Read and parse file contents if we have a URI
2324
+ const {
2325
+ content,
2326
+ errorMessage,
2327
+ parsedDom,
2328
+ parsedNodesChildNodeCount
2329
+ } = state.uri ? await updateContent(state, state.uri) : {
2330
+ content: state.content,
2331
+ errorMessage: state.errorMessage,
2332
+ parsedDom: state.parsedDom,
2333
+ parsedNodesChildNodeCount: state.parsedNodesChildNodeCount
2334
+ };
2335
+ return {
2336
+ ...state,
2337
+ content,
2338
+ errorCount: 0,
2339
+ errorMessage,
2340
+ initial: false,
2341
+ parsedDom,
2342
+ parsedNodesChildNodeCount,
2343
+ warningCount: 1
2344
+ };
2345
+ };
2346
+
1361
2347
  const getEmptyPreviewDom = () => {
1362
2348
  return [{
1363
2349
  childCount: 1,
1364
2350
  className: 'Viewlet Preview',
1365
- type: Div
2351
+ type: Div$1
1366
2352
  }, {
1367
2353
  childCount: 1,
1368
- type: H1
2354
+ type: H1$1
1369
2355
  }, {
1370
2356
  text: 'No URI has been specified',
1371
- type: Text
2357
+ type: Text$1
1372
2358
  }];
1373
2359
  };
2360
+
1374
2361
  const getPreviewDom = state => {
1375
- if (!state.uri) {
2362
+ const {
2363
+ parsedDom,
2364
+ parsedNodesChildNodeCount,
2365
+ uri
2366
+ } = state;
2367
+ if (!uri) {
1376
2368
  return getEmptyPreviewDom();
1377
2369
  }
2370
+
2371
+ // If parsedDom is available, render it as children of the wrapper
2372
+ if (parsedDom && parsedDom.length > 0) {
2373
+ return [{
2374
+ childCount: parsedNodesChildNodeCount,
2375
+ className: 'Viewlet Preview',
2376
+ type: Div$1
2377
+ }, ...parsedDom];
2378
+ }
1378
2379
  return [{
1379
2380
  childCount: 1,
1380
2381
  className: 'Viewlet Preview',
1381
- type: Div
2382
+ type: Div$1
1382
2383
  }, {
1383
2384
  childCount: 1,
1384
- type: H1
2385
+ type: H1$1
1385
2386
  }, {
1386
2387
  text: 'hello from preview',
1387
- type: Text
2388
+ type: Text$1
1388
2389
  }];
1389
2390
  };
1390
2391
 
@@ -1449,6 +2450,18 @@ const renderEventListeners = () => {
1449
2450
  }];
1450
2451
  };
1451
2452
 
2453
+ const rerender = state => {
2454
+ // Create a new copy of parsedDom array to trigger diff
2455
+ const parsedDom = [...state.parsedDom];
2456
+
2457
+ // Return a new state object with the copied parsedDom
2458
+ // This will cause DiffItems.isEqual to return false since parsedDom reference changed
2459
+ return {
2460
+ ...state,
2461
+ parsedDom
2462
+ };
2463
+ };
2464
+
1452
2465
  const resize = (state, dimensions) => {
1453
2466
  return {
1454
2467
  ...state,
@@ -1462,20 +2475,33 @@ const saveState = state => {
1462
2475
  };
1463
2476
  };
1464
2477
 
1465
- const setUri = (state, uri) => {
2478
+ const setUri = async (state, uri) => {
2479
+ const {
2480
+ content,
2481
+ errorMessage,
2482
+ parsedDom,
2483
+ parsedNodesChildNodeCount
2484
+ } = await updateContent(state, uri);
1466
2485
  return {
1467
2486
  ...state,
2487
+ content,
2488
+ errorMessage,
2489
+ parsedDom,
2490
+ parsedNodesChildNodeCount,
1468
2491
  uri
1469
2492
  };
1470
2493
  };
1471
2494
 
1472
2495
  const commandMap = {
2496
+ handleEditorChanged: handleEditorChanged,
1473
2497
  'Preview.create': create,
1474
2498
  'Preview.diff2': diff2,
1475
2499
  'Preview.getCommandIds': getCommandIds,
2500
+ 'Preview.handleFileEdited': wrapCommand(handleFileEdited),
1476
2501
  'Preview.loadContent': wrapCommand(loadContent),
1477
2502
  'Preview.render2': render2,
1478
2503
  'Preview.renderEventListeners': renderEventListeners,
2504
+ 'Preview.rerender': wrapCommand(rerender),
1479
2505
  'Preview.resize': wrapCommand(resize),
1480
2506
  'Preview.saveState': wrapGetter(saveState),
1481
2507
  'Preview.setUri': wrapCommand(setUri),
@@ -1488,6 +2514,11 @@ const listen = async () => {
1488
2514
  commandMap: commandMap
1489
2515
  });
1490
2516
  set$1(rpc);
2517
+ const editorRpc = await LazyTransferMessagePortRpcParent.create({
2518
+ commandMap: {},
2519
+ send: port => sendMessagePortToEditorWorker(port, 9112)
2520
+ });
2521
+ set$2(editorRpc);
1491
2522
  };
1492
2523
 
1493
2524
  const main = async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/preview-worker",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "description": "Preview Worker",
5
5
  "repository": {
6
6
  "type": "git",