@lark.js/mvc 0.0.2 → 0.0.4

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/index.js CHANGED
@@ -6,10 +6,15 @@ var ROUTER_EVENTS = {
6
6
  CHANGED: "changed",
7
7
  PAGE_UNLOAD: "page_unload"
8
8
  };
9
- var TAG_KEY = "lark-key";
10
- var TAG_ATTR_KEY = "lark-attr-key";
11
- var TAG_VIEW_KEY = "lark-view-key";
12
- var LARK_VIEW = "lark-view";
9
+ var LARK_KEYS = {
10
+ /** Attribute name: ldk (static key for skipping VDOM diff) */
11
+ DIFF_KEY: "ldk",
12
+ /** Attribute name: lak (static attribute key) */
13
+ ATTR_KEY: "lak",
14
+ /** Attribute name: lvk (view key for assign) */
15
+ VIEW_KEY: "lvk"
16
+ };
17
+ var LARK_VIEW = "v-lark";
13
18
  var EVENT_METHOD_REGEXP = new RegExp(
14
19
  `(?:([\\w-]+)${SPLITTER})?([^(]+)\\(([\\s\\S]*?)?\\)`
15
20
  );
@@ -33,7 +38,6 @@ function isPlainObject(value) {
33
38
  if (proto === null) return true;
34
39
  return proto === Object.prototype || proto === null;
35
40
  }
36
- var isArray = Array.isArray;
37
41
  function isPrimitiveOrFunc(value) {
38
42
  return !value || typeof value !== "object" && typeof value !== "function";
39
43
  }
@@ -74,13 +78,13 @@ function assign(target, ...sources) {
74
78
  return target;
75
79
  }
76
80
  function funcWithTry(fns, args, context, configError) {
77
- const fnArray = isArray(fns) ? fns : [fns];
81
+ const fnArray = Array.isArray(fns) ? fns : [fns];
78
82
  let ret;
79
83
  for (const fn of fnArray) {
80
84
  try {
81
85
  ret = Function.prototype.apply.call(fn, context, args);
82
86
  } catch (e) {
83
- configError(e);
87
+ configError?.(e);
84
88
  }
85
89
  }
86
90
  return ret;
@@ -108,7 +112,7 @@ function translateData(data, value) {
108
112
  }
109
113
  return value;
110
114
  }
111
- if (isPlainObject(value) || isArray(value)) {
115
+ if (isPlainObject(value) || Array.isArray(value)) {
112
116
  for (const p in value) {
113
117
  if (has(value, p)) {
114
118
  const val = value[p];
@@ -201,13 +205,13 @@ function toMap(list, key) {
201
205
  function now() {
202
206
  return Date.now ? Date.now() : (/* @__PURE__ */ new Date()).getTime();
203
207
  }
204
- function classExtend(ctor, base, props, statics) {
208
+ function classExtend(make, base, props, statics) {
205
209
  const baseProto = base["prototype"] ?? {};
206
- const cProto = Object.create(baseProto);
207
- assign(cProto, props);
208
- Object.assign(ctor, statics);
209
- cProto.constructor = ctor;
210
- ctor["prototype"] = cProto;
210
+ const classProto = Object.create(baseProto);
211
+ assign(classProto, props);
212
+ Object.assign(make, statics);
213
+ classProto.constructor = make;
214
+ make["prototype"] = classProto;
211
215
  }
212
216
 
213
217
  // src/apply-style.ts
@@ -248,8 +252,8 @@ function applyStyle(styleIdOrPairs, css) {
248
252
  }
249
253
 
250
254
  // src/mark.ts
251
- var DELETED_KEY = SPLITTER + "$a";
252
- var MARK_OBJECT_KEY = SPLITTER + "$b";
255
+ var DELETED_KEY = SPLITTER + "$delFlag";
256
+ var MARK_OBJECT_KEY = SPLITTER + "$markKey";
253
257
  function mark(host, key) {
254
258
  let sign = 0;
255
259
  const hostRecord = host;
@@ -273,9 +277,9 @@ function unmark(host) {
273
277
 
274
278
  // src/safeguard.ts
275
279
  var proxiesPool = /* @__PURE__ */ new Map();
276
- var SAFEGUARD_SENTINEL = "_sf_";
280
+ var SAFEGUARD_SENTINEL = "_safe_";
277
281
  function safeguard(data, getter, setter, isRoot) {
278
- if (typeof window.__lark_debug === "undefined" || !window.__lark_debug) {
282
+ if (typeof window.__lark_Debug === "undefined" || !window.__lark_Debug) {
279
283
  return data;
280
284
  }
281
285
  if (typeof Proxy === "undefined") {
@@ -314,7 +318,7 @@ function safeguard(data, getter, setter, isRoot) {
314
318
  if (!prefix && getter) {
315
319
  getter(property);
316
320
  }
317
- if (!isRoot && has(target, property) && (isArray(out) || isPlainObject(out))) {
321
+ if (!isRoot && has(target, property) && (Array.isArray(out) || isPlainObject(out))) {
318
322
  return build(prefix + property + ".", out);
319
323
  }
320
324
  return out;
@@ -489,7 +493,10 @@ var EventEmitter = class {
489
493
  }
490
494
  } else {
491
495
  this.listeners.delete(key);
492
- Reflect.deleteProperty(this, `on${event}`);
496
+ Reflect.deleteProperty(
497
+ this,
498
+ `on${event[0].toUpperCase() + event.slice(1)}`
499
+ );
493
500
  }
494
501
  return this;
495
502
  }
@@ -530,7 +537,7 @@ var EventEmitter = class {
530
537
  }
531
538
  }
532
539
  }
533
- const onMethodName = `on${event}`;
540
+ const onMethodName = `on${event[0].toUpperCase() + event.slice(1)}`;
534
541
  const onMethod = this[onMethodName];
535
542
  if (typeof onMethod === "function") {
536
543
  funcWithTry(
@@ -577,7 +584,7 @@ function teardownKeysRef(keyList) {
577
584
  if (count <= 0) {
578
585
  Reflect.deleteProperty(keyRefCounts, key);
579
586
  Reflect.deleteProperty(appData, key);
580
- if (typeof window.__lark_debug !== "undefined" && window.__lark_debug) {
587
+ if (typeof window.__lark_Debug !== "undefined" && window.__lark_Debug) {
581
588
  Reflect.deleteProperty(dataWhereSet, key);
582
589
  }
583
590
  }
@@ -620,7 +627,7 @@ var State = {
620
627
  */
621
628
  get(key) {
622
629
  const result = key ? appData[key] : appData;
623
- if (typeof window.__lark_debug !== "undefined" && window.__lark_debug) {
630
+ if (typeof window.__lark_Debug !== "undefined" && window.__lark_Debug) {
624
631
  return safeguard(
625
632
  result,
626
633
  (dataKey) => {
@@ -646,7 +653,7 @@ var State = {
646
653
  */
647
654
  set(data, excludes) {
648
655
  dataIsChanged = setData(data, appData, changedKeys, excludes || /* @__PURE__ */ new Set()) || dataIsChanged;
649
- if (typeof window.__lark_debug !== "undefined" && window.__lark_debug && booted) {
656
+ if (typeof window.__lark_Debug !== "undefined" && window.__lark_Debug && booted) {
650
657
  for (const p in data) {
651
658
  dataWhereSet[p] = window.location.pathname;
652
659
  }
@@ -661,7 +668,7 @@ var State = {
661
668
  State.set(data, excludes);
662
669
  }
663
670
  if (dataIsChanged) {
664
- if (typeof window.__lark_debug !== "undefined" && window.__lark_debug) {
671
+ if (typeof window.__lark_Debug !== "undefined" && window.__lark_Debug) {
665
672
  for (const p in changedKeys) {
666
673
  if (has(changedKeys, p)) {
667
674
  clearNotify(p);
@@ -692,7 +699,7 @@ var State = {
692
699
  */
693
700
  clean(keys2) {
694
701
  return {
695
- ctor: function() {
702
+ make: function() {
696
703
  const keyList = setupKeysRef(keys2);
697
704
  this.on("destroy", () => {
698
705
  teardownKeysRef(keyList);
@@ -721,6 +728,7 @@ var State = {
721
728
  emitter.fire(event, data, remove);
722
729
  return State;
723
730
  }
731
+ // onChanged: noop,
724
732
  };
725
733
 
726
734
  // src/router.ts
@@ -873,7 +881,7 @@ var Router = {
873
881
  attachViewAndPath(location);
874
882
  hrefCache.set(href, location);
875
883
  }
876
- if (typeof window.__lark_debug !== "undefined" && window.__lark_debug) {
884
+ if (typeof window.__lark_Debug !== "undefined" && window.__lark_Debug) {
877
885
  location["params"] = safeguard(location["params"]);
878
886
  }
879
887
  return location;
@@ -897,7 +905,7 @@ var Router = {
897
905
  );
898
906
  }
899
907
  silent = 0;
900
- if (typeof window.__lark_debug !== "undefined" && window.__lark_debug && lastChanged) {
908
+ if (typeof window.__lark_Debug !== "undefined" && window.__lark_Debug && lastChanged) {
901
909
  lastChanged = safeguard(lastChanged);
902
910
  }
903
911
  return lastChanged;
@@ -1026,9 +1034,9 @@ var Router = {
1026
1034
  window.addEventListener("hashchange", watchChange);
1027
1035
  window.addEventListener("popstate", watchChange);
1028
1036
  window.addEventListener("beforeunload", (domEvent) => {
1029
- const te = {};
1030
- Router.fire(ROUTER_EVENTS.PAGE_UNLOAD, te);
1031
- const msg = te["msg"];
1037
+ const data = {};
1038
+ Router.fire(ROUTER_EVENTS.PAGE_UNLOAD, data);
1039
+ const msg = data["msg"];
1032
1040
  if (msg) {
1033
1041
  domEvent.returnValue = msg;
1034
1042
  }
@@ -1060,26 +1068,26 @@ var frameGetter;
1060
1068
  function parseEventInfo(eventInfo) {
1061
1069
  const cached = eventInfoCache.get(eventInfo);
1062
1070
  if (cached) {
1063
- return assign({}, cached, { r: eventInfo });
1071
+ return assign({}, cached, { value: eventInfo });
1064
1072
  }
1065
1073
  const match = eventInfo.match(EVENT_METHOD_REGEXP) || [];
1066
1074
  const result = {
1067
- v: match[1] || "",
1068
- n: match[2] || "",
1069
- i: match[3] || ""
1075
+ id: match[1] || "",
1076
+ name: match[2] || "",
1077
+ params: match[3] || ""
1070
1078
  };
1071
1079
  eventInfoCache.set(eventInfo, result);
1072
- return assign({}, result, { r: eventInfo });
1080
+ return assign({}, result, { value: eventInfo });
1073
1081
  }
1074
1082
  function findFrameInfo(current, eventType) {
1075
1083
  const eventInfos = [];
1076
1084
  let begin = current;
1077
- const info = current.getAttribute(`v-${eventType}`);
1085
+ const info = current.getAttribute(`@${eventType}`);
1078
1086
  let match;
1079
1087
  if (info) {
1080
1088
  match = parseEventInfo(info);
1081
1089
  }
1082
- if (match && !match.v || selectorEvents[eventType]) {
1090
+ if (match && !match.id || selectorEvents[eventType]) {
1083
1091
  let selectorFrameId = "#";
1084
1092
  let backtrace = 0;
1085
1093
  while (begin && begin !== document.body) {
@@ -1105,10 +1113,10 @@ function findFrameInfo(current, eventType) {
1105
1113
  if (selectorEntry) {
1106
1114
  for (const selectorName of selectorEntry.selectors) {
1107
1115
  const entry = {
1108
- r: selectorName,
1109
- v: frameId,
1110
- n: selectorName,
1111
- i: ""
1116
+ value: selectorName,
1117
+ id: frameId,
1118
+ name: selectorName,
1119
+ params: ""
1112
1120
  };
1113
1121
  if (selectorName) {
1114
1122
  if (!backtrace && elementMatchesSelector(current, selectorName)) {
@@ -1120,8 +1128,8 @@ function findFrameInfo(current, eventType) {
1120
1128
  }
1121
1129
  }
1122
1130
  if (view.template && !backtrace) {
1123
- if (match && !match.v) {
1124
- match.v = frameId;
1131
+ if (match && !match.id) {
1132
+ match.id = frameId;
1125
1133
  }
1126
1134
  break;
1127
1135
  }
@@ -1137,10 +1145,10 @@ function findFrameInfo(current, eventType) {
1137
1145
  }
1138
1146
  if (match) {
1139
1147
  eventInfos.push({
1140
- v: match.v,
1141
- r: match.r,
1142
- n: match.n,
1143
- i: match.i
1148
+ id: match.id,
1149
+ value: match.value,
1150
+ name: match.name,
1151
+ params: match.params
1144
1152
  });
1145
1153
  }
1146
1154
  return eventInfos;
@@ -1161,7 +1169,7 @@ function domEventProcessor(domEvent) {
1161
1169
  const eventInfos = findFrameInfo(current, eventType);
1162
1170
  if (eventInfos.length) {
1163
1171
  for (const info of eventInfos) {
1164
- const { v: frameId, n: handlerName, i: params } = info;
1172
+ const { id: frameId, name: handlerName, params } = info;
1165
1173
  if (lastFrameId !== frameId) {
1166
1174
  if (lastFrameId && domEvent.isPropagationStopped?.()) {
1167
1175
  break;
@@ -1260,8 +1268,8 @@ var WrapMeta = {
1260
1268
  td: [3, "<table><tbody><tr>"],
1261
1269
  area: [1, "<map>"],
1262
1270
  param: [1, "<object>"],
1263
- g: [1, '<svg xmlns="' + SVG_NS + '">'],
1264
- m: [1, '<math xmlns="' + MATH_NS + '">'],
1271
+ svg: [1, '<svg xmlns="' + SVG_NS + '">'],
1272
+ math: [1, '<math xmlns="' + MATH_NS + '">'],
1265
1273
  _: [0, ""]
1266
1274
  };
1267
1275
  WrapMeta["optgroup"] = WrapMeta["option"];
@@ -1294,9 +1302,9 @@ function vdomGetNode(html, refNode) {
1294
1302
  const ns = refNode.namespaceURI;
1295
1303
  let tag;
1296
1304
  if (ns === SVG_NS) {
1297
- tag = "g";
1305
+ tag = "svg";
1298
1306
  } else if (ns === MATH_NS) {
1299
- tag = "m";
1307
+ tag = "math";
1300
1308
  } else {
1301
1309
  const match = TAG_NAME_REGEXP.exec(html);
1302
1310
  tag = match ? match[1] : "";
@@ -1318,7 +1326,7 @@ function vdomGetCompareKey(node) {
1318
1326
  }
1319
1327
  let key = el.autoId ? "" : el.getAttribute("id") || void 0;
1320
1328
  if (!key) {
1321
- key = el.getAttribute(TAG_KEY) || void 0;
1329
+ key = el.getAttribute(LARK_KEYS.DIFF_KEY) || void 0;
1322
1330
  }
1323
1331
  if (!key) {
1324
1332
  const larkView = el.getAttribute(LARK_VIEW);
@@ -1446,17 +1454,17 @@ function vdomSetChildNodes(oldParent, newParent, ref, frame, keys_) {
1446
1454
  }
1447
1455
  }
1448
1456
  function vdomSetNode(oldNode, newNode, oldParent, ref, frame, keys_) {
1449
- if (vdomSpecialDiff(oldNode, newNode) || oldNode.nodeType === 1 && oldNode.hasAttribute(TAG_VIEW_KEY) || !(oldNode.isEqualNode && oldNode.isEqualNode(newNode))) {
1457
+ if (vdomSpecialDiff(oldNode, newNode) || oldNode.nodeType === 1 && oldNode.hasAttribute(LARK_KEYS.VIEW_KEY) || !(oldNode.isEqualNode && oldNode.isEqualNode(newNode))) {
1450
1458
  if (oldNode.nodeType === newNode.nodeType && oldNode.nodeName === newNode.nodeName) {
1451
1459
  if (oldNode.nodeType === 1) {
1452
1460
  const oldEl = oldNode;
1453
1461
  const newEl = newNode;
1454
- const staticKey = newEl.getAttribute(TAG_KEY);
1455
- if (staticKey && staticKey === oldEl.getAttribute(TAG_KEY)) {
1462
+ const staticKey = newEl.getAttribute(LARK_KEYS.DIFF_KEY);
1463
+ if (staticKey && staticKey === oldEl.getAttribute(LARK_KEYS.DIFF_KEY)) {
1456
1464
  return;
1457
1465
  }
1458
1466
  const newLarkView = newEl.getAttribute(LARK_VIEW);
1459
- const updateAttribute = !newEl.getAttribute(TAG_ATTR_KEY) || newEl.getAttribute(TAG_ATTR_KEY) !== oldEl.getAttribute(TAG_ATTR_KEY);
1467
+ const updateAttribute = !newEl.getAttribute(LARK_KEYS.ATTR_KEY) || newEl.getAttribute(LARK_KEYS.ATTR_KEY) !== oldEl.getAttribute(LARK_KEYS.ATTR_KEY);
1460
1468
  let updateChildren = true;
1461
1469
  if (newLarkView) {
1462
1470
  const oldFrameId = oldEl.getAttribute("id") || "";
@@ -1601,7 +1609,7 @@ var Updater = class {
1601
1609
  if (key) {
1602
1610
  result = this.data[key];
1603
1611
  }
1604
- if (typeof window !== "undefined" && window.__lark_debug) {
1612
+ if (typeof window !== "undefined" && window.__lark_Debug) {
1605
1613
  return safeguard(result);
1606
1614
  }
1607
1615
  return result;
@@ -1736,225 +1744,10 @@ var Updater = class {
1736
1744
  // src/view.ts
1737
1745
  var VIEW_GLOBALS = {};
1738
1746
  if (typeof window !== "undefined") {
1739
- VIEW_GLOBALS["win"] = window;
1747
+ VIEW_GLOBALS["window"] = window;
1740
1748
  }
1741
1749
  if (typeof document !== "undefined") {
1742
- VIEW_GLOBALS["doc"] = document;
1743
- }
1744
- function viewPrepare(oView) {
1745
- if (oView.ctors) {
1746
- return oView.ctors;
1747
- }
1748
- const ctors = [];
1749
- oView.ctors = ctors;
1750
- const proto = oView.prototype;
1751
- const eventsObject = {};
1752
- const eventsList = [];
1753
- const selectorObject = {};
1754
- const mixins = proto["mixins"];
1755
- if (mixins && Array.isArray(mixins)) {
1756
- viewMergeMixins(mixins, oView, ctors);
1757
- }
1758
- for (const p in proto) {
1759
- if (!has(proto, p)) continue;
1760
- const currentFn = proto[p];
1761
- if (typeof currentFn !== "function") continue;
1762
- const matches = p.match(VIEW_EVENT_METHOD_REGEXP);
1763
- if (!matches) continue;
1764
- const isSelector = matches[1];
1765
- const selectorOrCallback = matches[2];
1766
- const events = matches[3];
1767
- const modifiers = matches[4];
1768
- const mod = {};
1769
- if (modifiers) {
1770
- for (const item of modifiers.split(",")) {
1771
- mod[item] = true;
1772
- }
1773
- }
1774
- const eventTypes = events.split(",");
1775
- for (const item of eventTypes) {
1776
- const globalNode = VIEW_GLOBALS[selectorOrCallback];
1777
- let mask = 1;
1778
- if (isSelector) {
1779
- if (globalNode) {
1780
- eventsList.push({
1781
- handler: currentFn,
1782
- element: globalNode,
1783
- eventName: item,
1784
- modifiers: mod
1785
- });
1786
- continue;
1787
- }
1788
- mask = 2;
1789
- let selectorEntry = selectorObject[item];
1790
- if (!selectorEntry) {
1791
- selectorEntry = selectorObject[item] = {
1792
- selectors: []
1793
- };
1794
- }
1795
- if (!selectorEntry[selectorOrCallback]) {
1796
- selectorEntry[selectorOrCallback] = 1;
1797
- selectorEntry.selectors.push(selectorOrCallback);
1798
- }
1799
- }
1800
- eventsObject[item] = (eventsObject[item] || 0) | mask;
1801
- const combinedKey = selectorOrCallback + SPLITTER + item;
1802
- const existingFn = proto[combinedKey];
1803
- if (!existingFn) {
1804
- proto[combinedKey] = currentFn;
1805
- } else {
1806
- const mixinFn = currentFn;
1807
- const existingMixin = existingFn;
1808
- if (existingMixin.b) {
1809
- if (mixinFn.b) {
1810
- proto[combinedKey] = processMixinsSameEvent(
1811
- currentFn,
1812
- existingFn
1813
- );
1814
- } else if (has(proto, p)) {
1815
- proto[combinedKey] = currentFn;
1816
- }
1817
- }
1818
- }
1819
- }
1820
- }
1821
- viewWrapMethod(proto, "render", "$b");
1822
- proto["$eo"] = eventsObject;
1823
- proto["$el"] = eventsList;
1824
- proto["$so"] = selectorObject;
1825
- proto["$f"] = proto["assign"];
1826
- return ctors;
1827
- }
1828
- function viewWrapMethod(proto, fnName, shortKey) {
1829
- const originalFn = proto[fnName];
1830
- if (typeof originalFn !== "function") return;
1831
- const wrapped = function(...args) {
1832
- if (this.signature > 0) {
1833
- this.signature++;
1834
- this.fire("rendercall");
1835
- destroyAllResources(this, false);
1836
- const instanceFn = typeof this[fnName] === "function" ? this[fnName] : originalFn;
1837
- const fnToCall = instanceFn === wrapped ? originalFn : instanceFn;
1838
- return funcWithTry(fnToCall, args, this, noop);
1839
- }
1840
- return void 0;
1841
- };
1842
- proto[fnName] = wrapped;
1843
- proto[shortKey] = wrapped;
1844
- }
1845
- function processMixinsSameEvent(additional, exist) {
1846
- let temp;
1847
- const existMixin = exist;
1848
- if (existMixin.a) {
1849
- temp = existMixin;
1850
- } else {
1851
- temp = function(...e) {
1852
- funcWithTry(temp.a ?? [], e, this, noop);
1853
- };
1854
- temp.a = [exist];
1855
- temp.b = 1;
1856
- }
1857
- const additionalMixin = additional;
1858
- temp.a = (temp.a ?? []).concat(additionalMixin.a ?? [additional]);
1859
- return temp;
1860
- }
1861
- function viewMergeMixins(mixins, viewClass, ctors) {
1862
- const proto = viewClass.prototype;
1863
- const temp = {};
1864
- for (const node of mixins) {
1865
- for (const p in node) {
1866
- if (!has(node, p)) continue;
1867
- const fn = node[p];
1868
- const exist = temp[p];
1869
- if (p === "ctor") {
1870
- ctors.push(fn);
1871
- continue;
1872
- }
1873
- if (VIEW_EVENT_METHOD_REGEXP.test(p)) {
1874
- if (exist) {
1875
- temp[p] = processMixinsSameEvent(fn, exist);
1876
- } else {
1877
- fn.b = 1;
1878
- temp[p] = fn;
1879
- }
1880
- } else {
1881
- if (!exist) {
1882
- temp[p] = fn;
1883
- }
1884
- }
1885
- }
1886
- }
1887
- for (const p in temp) {
1888
- if (!has(proto, p)) {
1889
- proto[p] = temp[p];
1890
- }
1891
- }
1892
- }
1893
- function viewDelegateEvents(view, destroy = false) {
1894
- const proto = Object.getPrototypeOf(view) ?? {};
1895
- const eventsObject = proto["$eo"] || view.eventObjectMap;
1896
- const selectorObject = proto["$so"] || view.eventSelectorMap;
1897
- const eventsList = proto["$el"] || view.globalEventList;
1898
- for (const e in eventsObject) {
1899
- if (has(eventsObject, e)) {
1900
- if (destroy) {
1901
- EventDelegator.unbind(e, !!selectorObject[e]);
1902
- } else {
1903
- EventDelegator.bind(e, !!selectorObject[e]);
1904
- }
1905
- }
1906
- }
1907
- for (const entry of eventsList) {
1908
- if (destroy) {
1909
- entry.element.removeEventListener(
1910
- entry.eventName,
1911
- entry.boundHandler
1912
- );
1913
- } else {
1914
- const handler = entry.handler;
1915
- const element = entry.element;
1916
- const modifiers = entry.modifiers;
1917
- entry.boundHandler = function(domEvent) {
1918
- const extendedEvent = domEvent;
1919
- extendedEvent.eventTarget = element;
1920
- if (modifiers) {
1921
- const kbEvent = domEvent;
1922
- if (modifiers["ctrl"] && !kbEvent.ctrlKey || modifiers["shift"] && !kbEvent.shiftKey || modifiers["alt"] && !kbEvent.altKey || modifiers["meta"] && !kbEvent.metaKey) {
1923
- return;
1924
- }
1925
- }
1926
- funcWithTry(handler, [domEvent], view, noop);
1927
- };
1928
- entry.element.addEventListener(
1929
- entry.eventName,
1930
- entry.boundHandler
1931
- );
1932
- }
1933
- }
1934
- }
1935
- function destroyAllResources(view, lastly) {
1936
- const cache = view.resources;
1937
- for (const p in cache) {
1938
- if (has(cache, p)) {
1939
- const entry = cache[p];
1940
- if (lastly || entry.destroyOnRender) {
1941
- destroyResource(cache, p, true);
1942
- }
1943
- }
1944
- }
1945
- }
1946
- function destroyResource(cache, key, callDestroy, oldEntity) {
1947
- const entry = cache[key];
1948
- if (!entry || entry.entity === oldEntity) return void 0;
1949
- const entity = entry.entity;
1950
- if (entity && typeof entity === "object") {
1951
- const destroyFn = entity["destroy"];
1952
- if (typeof destroyFn === "function" && callDestroy) {
1953
- funcWithTry(destroyFn, [], entity, noop);
1954
- }
1955
- }
1956
- Reflect.deleteProperty(cache, key);
1957
- return entity;
1750
+ VIEW_GLOBALS["document"] = document;
1958
1751
  }
1959
1752
  var View = class _View {
1960
1753
  /** View ID (same as owner frame ID) */
@@ -1979,18 +1772,43 @@ var View = class _View {
1979
1772
  observedStateKeys;
1980
1773
  /** Resource map */
1981
1774
  resources = {};
1982
- /** Selector event map: eventType -> handler name list */
1983
- eventSelectorMap = {};
1984
- /** Event object map: eventType -> bitmask */
1985
- eventObjectMap = {};
1986
- /** Global event list */
1987
- globalEventList = [];
1988
1775
  /** Assign method reference */
1989
1776
  assignMethod;
1990
1777
  /** Whether endUpdate pending */
1991
1778
  endUpdatePending;
1992
1779
  /** Internal event storage */
1993
1780
  _events = new EventEmitter();
1781
+ // ============================================================
1782
+ // Getters for prototype-stored event maps
1783
+ // ============================================================
1784
+ /**
1785
+ * Event bitmask map: eventType -> bitmask (1=root, 2=selector).
1786
+ * Read from prototype ($evtObjMap) set by View.prepare.
1787
+ * Using a getter avoids ES6 class field shadowing the prototype value.
1788
+ */
1789
+ get eventObjectMap() {
1790
+ const proto = Object.getPrototypeOf(this);
1791
+ return proto["$evtObjMap"] || {};
1792
+ }
1793
+ /**
1794
+ * Selector event map: eventType -> selector list.
1795
+ * Read from prototype ($selMap) set by View.prepare.
1796
+ */
1797
+ get eventSelectorMap() {
1798
+ const proto = Object.getPrototypeOf(this);
1799
+ return proto["$selMap"] || {};
1800
+ }
1801
+ /**
1802
+ * Global event list: [{handler, element, eventName, modifiers}].
1803
+ * Read from prototype ($globalEvtList) set by View.prepare.
1804
+ */
1805
+ get globalEventList() {
1806
+ const proto = Object.getPrototypeOf(this);
1807
+ return proto["$globalEvtList"] || [];
1808
+ }
1809
+ // ============================================================
1810
+ // Instance lifecycle methods
1811
+ // ============================================================
1994
1812
  /**
1995
1813
  * Initialize view (called by Frame when mounting).
1996
1814
  */
@@ -1998,14 +1816,7 @@ var View = class _View {
1998
1816
  }
1999
1817
  /**
2000
1818
  * Render view template (called by Frame after init).
2001
- * Wrapped by View_WrapMethod to manage signature + resources.
2002
- *
2003
- * Default implementation calls updater.digest() which:
2004
- * 1. Executes the template function with current data
2005
- * 2. Runs VDOM diff against previous DOM
2006
- * 3. Applies DOM operations
2007
- * 4. Calls endUpdate to mount child frames
2008
- *
1819
+ * Wrapped by View.wrapMethod to manage signature + resources.
2009
1820
  */
2010
1821
  render() {
2011
1822
  this.updater.digest();
@@ -2057,7 +1868,7 @@ var View = class _View {
2057
1868
  if (!flag) {
2058
1869
  setTimeout(
2059
1870
  this.wrapAsync(() => {
2060
- runInvokes(ownerFrame);
1871
+ _View.runInvokes(ownerFrame);
2061
1872
  }),
2062
1873
  0
2063
1874
  );
@@ -2133,7 +1944,7 @@ var View = class _View {
2133
1944
  capture(key, resource, destroyOnRender = false) {
2134
1945
  const cache = this.resources;
2135
1946
  if (resource) {
2136
- destroyResource(cache, key, true, resource);
1947
+ _View.destroyResource(cache, key, true, resource);
2137
1948
  cache[key] = {
2138
1949
  entity: resource,
2139
1950
  destroyOnRender
@@ -2149,7 +1960,7 @@ var View = class _View {
2149
1960
  * If destroy=true, calls the resource's destroy() method.
2150
1961
  */
2151
1962
  release(key, destroy = true) {
2152
- return destroyResource(this.resources, key, destroy);
1963
+ return _View.destroyResource(this.resources, key, destroy);
2153
1964
  }
2154
1965
  // ============================================================
2155
1966
  // Leave tip
@@ -2195,31 +2006,294 @@ var View = class _View {
2195
2006
  });
2196
2007
  }
2197
2008
  // ============================================================
2198
- // Static: extend and merge
2009
+ // Static public methods
2199
2010
  // ============================================================
2200
2011
  /** Collected ctors from mixins */
2201
2012
  static ctors;
2013
+ /**
2014
+ * Prepare a View subclass by scanning its prototype for event method patterns.
2015
+ * Pattern: `$?name<eventType1,eventType2>(&modifiers)`
2016
+ *
2017
+ * Only runs once per View subclass (guarded by ctors marker).
2018
+ * Called from Frame.mountView before creating the view instance.
2019
+ */
2020
+ static prepare(oView) {
2021
+ if (oView.ctors) {
2022
+ return oView.ctors;
2023
+ }
2024
+ const ctors = [];
2025
+ oView.ctors = ctors;
2026
+ const proto = oView.prototype;
2027
+ const eventsObject = {};
2028
+ const eventsList = [];
2029
+ const selectorObject = {};
2030
+ const mixins = proto["mixins"];
2031
+ if (mixins && Array.isArray(mixins)) {
2032
+ _View.mergeMixins(mixins, oView, ctors);
2033
+ }
2034
+ for (const p in proto) {
2035
+ if (!has(proto, p)) continue;
2036
+ const currentFn = proto[p];
2037
+ if (typeof currentFn !== "function") continue;
2038
+ const matches = p.match(VIEW_EVENT_METHOD_REGEXP);
2039
+ if (!matches) continue;
2040
+ const isSelector = matches[1];
2041
+ const selectorOrCallback = matches[2];
2042
+ const events = matches[3];
2043
+ const modifiers = matches[4];
2044
+ const mod = {};
2045
+ if (modifiers) {
2046
+ for (const item of modifiers.split(",")) {
2047
+ mod[item] = true;
2048
+ }
2049
+ }
2050
+ const eventTypes = events.split(",");
2051
+ for (const item of eventTypes) {
2052
+ const globalNode = VIEW_GLOBALS[selectorOrCallback];
2053
+ let mask = 1;
2054
+ if (isSelector) {
2055
+ if (globalNode) {
2056
+ eventsList.push({
2057
+ handler: currentFn,
2058
+ element: globalNode,
2059
+ eventName: item,
2060
+ modifiers: mod
2061
+ });
2062
+ continue;
2063
+ }
2064
+ mask = 2;
2065
+ let selectorEntry = selectorObject[item];
2066
+ if (!selectorEntry) {
2067
+ selectorEntry = selectorObject[item] = {
2068
+ selectors: []
2069
+ };
2070
+ }
2071
+ if (!selectorEntry[selectorOrCallback]) {
2072
+ selectorEntry[selectorOrCallback] = 1;
2073
+ selectorEntry.selectors.push(selectorOrCallback);
2074
+ }
2075
+ }
2076
+ eventsObject[item] = (eventsObject[item] || 0) | mask;
2077
+ const combinedKey = selectorOrCallback + SPLITTER + item;
2078
+ const existingFn = proto[combinedKey];
2079
+ if (!existingFn) {
2080
+ proto[combinedKey] = currentFn;
2081
+ } else {
2082
+ const mixinFn = currentFn;
2083
+ const existingMixin = existingFn;
2084
+ if (existingMixin.marker) {
2085
+ if (mixinFn.marker) {
2086
+ proto[combinedKey] = _View.processMixinsSameEvent(
2087
+ currentFn,
2088
+ existingFn
2089
+ );
2090
+ } else if (has(proto, p)) {
2091
+ proto[combinedKey] = currentFn;
2092
+ }
2093
+ }
2094
+ }
2095
+ }
2096
+ }
2097
+ _View.wrapMethod(proto, "render", "$renderWrap");
2098
+ proto["$evtObjMap"] = eventsObject;
2099
+ proto["$globalEvtList"] = eventsList;
2100
+ proto["$selMap"] = selectorObject;
2101
+ proto["$assignFn"] = proto["assign"];
2102
+ return ctors;
2103
+ }
2104
+ /**
2105
+ * Bind or unbind event delegation for a view instance.
2106
+ * Called from Frame during mount/unmount.
2107
+ */
2108
+ static delegateEvents(view, destroy = false) {
2109
+ const eventsObject = view.eventObjectMap;
2110
+ const selectorObject = view.eventSelectorMap;
2111
+ const eventsList = view.globalEventList;
2112
+ for (const e in eventsObject) {
2113
+ if (has(eventsObject, e)) {
2114
+ if (destroy) {
2115
+ EventDelegator.unbind(e, !!selectorObject[e]);
2116
+ } else {
2117
+ EventDelegator.bind(e, !!selectorObject[e]);
2118
+ }
2119
+ }
2120
+ }
2121
+ for (const entry of eventsList) {
2122
+ if (destroy) {
2123
+ entry.element.removeEventListener(
2124
+ entry.eventName,
2125
+ entry.boundHandler
2126
+ );
2127
+ } else {
2128
+ const handler = entry.handler;
2129
+ const element = entry.element;
2130
+ const modifiers = entry.modifiers;
2131
+ entry.boundHandler = function(domEvent) {
2132
+ const extendedEvent = domEvent;
2133
+ extendedEvent.eventTarget = element;
2134
+ if (modifiers) {
2135
+ const kbEvent = domEvent;
2136
+ if (modifiers["ctrl"] && !kbEvent.ctrlKey || modifiers["shift"] && !kbEvent.shiftKey || modifiers["alt"] && !kbEvent.altKey || modifiers["meta"] && !kbEvent.metaKey) {
2137
+ return;
2138
+ }
2139
+ }
2140
+ funcWithTry(handler, [domEvent], view, noop);
2141
+ };
2142
+ entry.element.addEventListener(
2143
+ entry.eventName,
2144
+ entry.boundHandler
2145
+ );
2146
+ }
2147
+ }
2148
+ }
2149
+ /**
2150
+ * Destroy all resources managed by a view.
2151
+ * If lastly=true, destroy ALL resources; otherwise only destroyOnRender ones.
2152
+ */
2153
+ static destroyAllResources(view, lastly) {
2154
+ const cache = view.resources;
2155
+ for (const p in cache) {
2156
+ if (has(cache, p)) {
2157
+ const entry = cache[p];
2158
+ if (lastly || entry.destroyOnRender) {
2159
+ _View.destroyResource(cache, p, true);
2160
+ }
2161
+ }
2162
+ }
2163
+ }
2164
+ /**
2165
+ * Process deferred invoke calls on a frame.
2166
+ */
2167
+ static runInvokes(frame) {
2168
+ const list = frame.invokeList;
2169
+ if (!list) return;
2170
+ while (list.length) {
2171
+ const entry = list.shift();
2172
+ if (entry && !entry.removed) {
2173
+ frame.invoke(entry.name, entry.args);
2174
+ }
2175
+ }
2176
+ }
2177
+ // ============================================================
2178
+ // Static private methods
2179
+ // ============================================================
2180
+ /**
2181
+ * Wrap a method on the prototype to add signature checking and resource cleanup.
2182
+ */
2183
+ static wrapMethod(proto, fnName, shortKey) {
2184
+ const originalFn = proto[fnName];
2185
+ if (typeof originalFn !== "function") return;
2186
+ const wrapped = function(...args) {
2187
+ if (this.signature > 0) {
2188
+ this.signature++;
2189
+ this.fire("render");
2190
+ _View.destroyAllResources(this, false);
2191
+ const instanceFn = typeof this[fnName] === "function" ? this[fnName] : originalFn;
2192
+ const fnToCall = instanceFn === wrapped ? originalFn : instanceFn;
2193
+ return funcWithTry(fnToCall, args, this, noop);
2194
+ }
2195
+ return void 0;
2196
+ };
2197
+ proto[fnName] = wrapped;
2198
+ proto[shortKey] = wrapped;
2199
+ }
2200
+ /**
2201
+ * When two mixins define the same event method, merge them into
2202
+ * a single function that calls both in sequence.
2203
+ */
2204
+ static processMixinsSameEvent(additional, exist) {
2205
+ let temp;
2206
+ const existMixin = exist;
2207
+ if (existMixin.handlerList) {
2208
+ temp = existMixin;
2209
+ } else {
2210
+ temp = function(...e) {
2211
+ funcWithTry(temp.handlerList ?? [], e, this, noop);
2212
+ };
2213
+ temp.handlerList = [exist];
2214
+ temp.marker = 1;
2215
+ }
2216
+ const additionalMixin = additional;
2217
+ temp.handlerList = (temp.handlerList ?? []).concat(
2218
+ additionalMixin.handlerList ?? [additional]
2219
+ );
2220
+ return temp;
2221
+ }
2222
+ /**
2223
+ * Merge an array of mixin objects into the view prototype.
2224
+ */
2225
+ static mergeMixins(mixins, viewClass, ctors) {
2226
+ const proto = viewClass.prototype;
2227
+ const temp = {};
2228
+ for (const node of mixins) {
2229
+ for (const p in node) {
2230
+ if (!has(node, p)) continue;
2231
+ const fn = node[p];
2232
+ const exist = temp[p];
2233
+ if (p === "make") {
2234
+ ctors.push(fn);
2235
+ continue;
2236
+ }
2237
+ if (VIEW_EVENT_METHOD_REGEXP.test(p)) {
2238
+ if (exist) {
2239
+ temp[p] = _View.processMixinsSameEvent(fn, exist);
2240
+ } else {
2241
+ fn.marker = 1;
2242
+ temp[p] = fn;
2243
+ }
2244
+ } else {
2245
+ if (!exist) {
2246
+ temp[p] = fn;
2247
+ }
2248
+ }
2249
+ }
2250
+ }
2251
+ for (const p in temp) {
2252
+ if (!has(proto, p)) {
2253
+ proto[p] = temp[p];
2254
+ }
2255
+ }
2256
+ }
2257
+ /**
2258
+ * Destroy a single resource entry.
2259
+ */
2260
+ static destroyResource(cache, key, callDestroy, oldEntity) {
2261
+ const entry = cache[key];
2262
+ if (!entry || entry.entity === oldEntity) return void 0;
2263
+ const entity = entry.entity;
2264
+ if (entity && typeof entity === "object") {
2265
+ const destroyFn = entity["destroy"];
2266
+ if (typeof destroyFn === "function" && callDestroy) {
2267
+ funcWithTry(destroyFn, [], entity, noop);
2268
+ }
2269
+ }
2270
+ Reflect.deleteProperty(cache, key);
2271
+ return entity;
2272
+ }
2273
+ // ============================================================
2274
+ // Static: extend and merge
2275
+ // ============================================================
2202
2276
  /**
2203
2277
  * Extend View to create a new View subclass.
2204
2278
  *
2205
2279
  * Supports:
2206
- * - props.ctor: constructor-like init (called with initParams + {node, deep})
2280
+ * - props.make: constructor-like init (called with initParams + {node, deep})
2207
2281
  * - props.mixins: array of mixin objects
2208
2282
  * - Event method patterns: `'name<click>'` etc.
2209
2283
  */
2210
2284
  static extend(props, statics) {
2211
2285
  props = props || {};
2212
- const ctor = props["ctor"];
2286
+ const make = props["make"];
2213
2287
  const ctors = [];
2214
- if (ctor) {
2215
- ctors.push(ctor);
2288
+ if (make) {
2289
+ ctors.push(make);
2216
2290
  }
2217
2291
  const ParentView = this;
2218
2292
  const ChildView = class extends ParentView {
2219
2293
  constructor(nodeId, ownerFrame, initParams, node, mixinCtors) {
2220
2294
  super(nodeId, ownerFrame, initParams, node, []);
2221
2295
  for (const key in props) {
2222
- if (has(props, key) && key !== "ctor") {
2296
+ if (has(props, key) && key !== "make" && key !== "render") {
2223
2297
  this[key] = props[key];
2224
2298
  }
2225
2299
  }
@@ -2241,7 +2315,7 @@ var View = class _View {
2241
2315
  };
2242
2316
  const proto = ChildView.prototype;
2243
2317
  for (const key in props) {
2244
- if (has(props, key) && key !== "ctor") {
2318
+ if (has(props, key) && key !== "make") {
2245
2319
  proto[key] = props[key];
2246
2320
  }
2247
2321
  }
@@ -2252,36 +2326,17 @@ var View = class _View {
2252
2326
  }
2253
2327
  }
2254
2328
  }
2255
- ChildView.merge = viewMerge;
2256
- ChildView.extend = _View.extend;
2257
2329
  return ChildView;
2258
2330
  }
2259
2331
  /**
2260
2332
  * Merge mixins into View prototype.
2261
2333
  */
2262
2334
  static merge(...mixins) {
2263
- const self = this;
2264
- const existingCtors = self.ctors || [];
2265
- viewMergeMixins(mixins, self, existingCtors);
2266
- return self;
2335
+ const existingCtors = this.ctors || [];
2336
+ _View.mergeMixins(mixins, this, existingCtors);
2337
+ return this;
2267
2338
  }
2268
2339
  };
2269
- function viewMerge(...mixins) {
2270
- const self = this;
2271
- const existingCtors = self.ctors || [];
2272
- viewMergeMixins(mixins, self, existingCtors);
2273
- return self;
2274
- }
2275
- function runInvokes(frame) {
2276
- const list = frame.invokeList;
2277
- if (!list) return;
2278
- while (list.length) {
2279
- const entry = list.shift();
2280
- if (entry && !entry.removed) {
2281
- frame.invoke(entry.name, entry.args);
2282
- }
2283
- }
2284
- }
2285
2340
 
2286
2341
  // src/frame.ts
2287
2342
  var frameRegistry = /* @__PURE__ */ new Map();
@@ -2320,7 +2375,7 @@ var Frame = class _Frame extends EventEmitter {
2320
2375
  hasAltered = 0;
2321
2376
  /** Whether view is destroyed */
2322
2377
  destroyed = 0;
2323
- /** View path (lark-view attribute value) */
2378
+ /** View path (v-lark attribute value) */
2324
2379
  viewPath;
2325
2380
  /** Original template before mount */
2326
2381
  originalTemplate;
@@ -2389,7 +2444,7 @@ var Frame = class _Frame extends EventEmitter {
2389
2444
  */
2390
2445
  doMountView(ViewClass, params, node, sign) {
2391
2446
  if (sign !== this.signature) return;
2392
- const mixinCtors = viewPrepare(ViewClass);
2447
+ const mixinCtors = View.prepare(ViewClass);
2393
2448
  const ViewConstructor = ViewClass;
2394
2449
  const view = new ViewConstructor(
2395
2450
  this.id,
@@ -2400,7 +2455,7 @@ var Frame = class _Frame extends EventEmitter {
2400
2455
  );
2401
2456
  this.viewInstance = view;
2402
2457
  view.signature = 1;
2403
- viewDelegateEvents(view);
2458
+ View.delegateEvents(view);
2404
2459
  const initResult = funcWithTry(
2405
2460
  view.init,
2406
2461
  [params, { node, deep: !view.template }],
@@ -2411,13 +2466,10 @@ var Frame = class _Frame extends EventEmitter {
2411
2466
  Promise.resolve(initResult).then(() => {
2412
2467
  if (nextSign !== this.signature) return;
2413
2468
  if (view.template) {
2414
- const renderFn = view.$b;
2415
- if (renderFn) {
2416
- renderFn.call(view);
2417
- }
2469
+ view.render();
2418
2470
  } else {
2419
2471
  this.hasAltered = 0;
2420
- if (!view.$e) {
2472
+ if (!view.endUpdatePendingFlag) {
2421
2473
  view.endUpdate();
2422
2474
  }
2423
2475
  }
@@ -2604,7 +2656,7 @@ var Frame = class _Frame extends EventEmitter {
2604
2656
  /** Get or create root frame */
2605
2657
  static root(rootId) {
2606
2658
  if (!rootFrame) {
2607
- rootId = rootId || "lark-root";
2659
+ rootId = rootId || "root";
2608
2660
  let rootElement = document.getElementById(rootId);
2609
2661
  if (!rootElement) {
2610
2662
  rootElement = document.body;
@@ -2725,19 +2777,19 @@ function registerViewClass(viewPath, ViewClass) {
2725
2777
  }
2726
2778
 
2727
2779
  // src/service.ts
2728
- var Bag = class {
2729
- /** Bag data */
2780
+ var Payload = class {
2781
+ /** Payload data */
2730
2782
  data;
2731
2783
  /** Internal cache info */
2732
2784
  cacheInfo;
2733
2785
  constructor(data = {}) {
2734
2786
  this.data = data;
2735
2787
  }
2736
- /** Get a value from bag data */
2788
+ /** Get a value from payload data */
2737
2789
  get(key) {
2738
2790
  return this.data[key];
2739
2791
  }
2740
- /** Set a value in bag data */
2792
+ /** Set a value in payload data */
2741
2793
  set(keyOrData, value) {
2742
2794
  if (typeof keyOrData === "string") {
2743
2795
  this.data[keyOrData] = value;
@@ -2749,287 +2801,366 @@ var Bag = class {
2749
2801
  };
2750
2802
  var FETCH_FLAGS_ALL = 1;
2751
2803
  var FETCH_FLAGS_ONE = 2;
2752
- function createServiceType(syncFn, cacheMax = 20, cacheBuffer = 5) {
2753
- const metas = {};
2754
- const bagCache = new Cache({
2755
- maxSize: cacheMax,
2756
- bufferSize: cacheBuffer
2757
- });
2758
- const pendingCacheKeys = {};
2759
- const staticEmitter2 = new EventEmitter();
2760
- const serviceType = {
2761
- add(attrs) {
2762
- if (!isArray(attrs)) {
2763
- attrs = [attrs];
2764
- }
2765
- for (const bag of attrs) {
2766
- if (bag) {
2767
- const name = bag.name;
2768
- const cache = bag.cache;
2769
- bag.cache = cache ? cache | 0 : 0;
2770
- metas[name] = bag;
2771
- }
2772
- }
2773
- },
2774
- meta(attrs) {
2775
- const name = typeof attrs === "string" ? attrs : attrs["name"];
2776
- return metas[name] || attrs;
2777
- },
2778
- create(attrs) {
2779
- const meta = serviceType.meta(attrs);
2780
- const cache = attrs["cache"] | 0 || meta.cache || 0;
2781
- const entity = new Bag();
2782
- entity.set(meta);
2783
- entity.cacheInfo = {
2784
- name: meta.name,
2785
- after: meta.after,
2786
- cleans: meta.cleans,
2787
- key: cache ? defaultCacheKey(meta, attrs) : "",
2788
- time: 0
2789
- };
2790
- if (typeof attrs === "object" && attrs !== null) {
2791
- entity.set(attrs);
2792
- }
2793
- const before = meta.before;
2794
- if (before) {
2795
- funcWithTry(before, [entity], entity, noop);
2796
- }
2797
- staticEmitter2.fire("begin", { bag: entity });
2798
- return entity;
2799
- },
2800
- get(attrs, createNew) {
2801
- let entity;
2802
- let needsUpdate = false;
2803
- if (!createNew) {
2804
- entity = serviceType.cached(attrs);
2805
- }
2806
- if (!entity) {
2807
- entity = serviceType.create(attrs);
2808
- needsUpdate = true;
2809
- }
2810
- return { entity, needsUpdate };
2811
- },
2812
- cached(attrs) {
2813
- const meta = serviceType.meta(attrs);
2814
- const cache = attrs["cache"] | 0 || meta.cache || 0;
2815
- let cacheKey = "";
2816
- if (cache) {
2817
- cacheKey = defaultCacheKey(meta, attrs);
2818
- }
2819
- if (cacheKey) {
2820
- const info = pendingCacheKeys[cacheKey];
2821
- if (info) {
2822
- return info.e;
2823
- }
2824
- const cached = bagCache.get(cacheKey);
2825
- if (cached && cached.cacheInfo) {
2826
- if (now() - cached.cacheInfo.time > cache) {
2827
- bagCache.del(cacheKey);
2828
- return void 0;
2804
+ var Service = class {
2805
+ /** Service instance ID */
2806
+ id = "";
2807
+ /** Whether service is busy (1 = busy) */
2808
+ busy = 0;
2809
+ /** Whether service is destroyed (1 = destroyed) */
2810
+ destroyed = 0;
2811
+ /** Task queue for sequential operations */
2812
+ taskQueue = [];
2813
+ /** Previous dequeue arguments */
2814
+ prevArgs = [];
2815
+ /** Instance event emitter */
2816
+ _emitter = new EventEmitter();
2817
+ constructor() {
2818
+ this.id = generateId("service");
2819
+ }
2820
+ // ============================================================
2821
+ // Instance accessors for type-level data
2822
+ // ============================================================
2823
+ /** Instance event emitter (public accessor) */
2824
+ get emitter() {
2825
+ return this._emitter;
2826
+ }
2827
+ /**
2828
+ * Get internals object for serviceSend compatibility.
2829
+ * References per-type static state from the current class.
2830
+ */
2831
+ get internals() {
2832
+ const ctor = this.constructor;
2833
+ return {
2834
+ metaList: ctor._metaList,
2835
+ payloadCache: ctor._payloadCache,
2836
+ pendingCacheKeys: ctor._pendingCacheKeys,
2837
+ syncFn: ctor._syncFn,
2838
+ staticEmitter: ctor._staticEmitter
2839
+ };
2840
+ }
2841
+ /**
2842
+ * Get type reference (the constructor) for serviceSend compatibility.
2843
+ * Static methods like get/create are accessible via the constructor.
2844
+ */
2845
+ get type() {
2846
+ return this.constructor;
2847
+ }
2848
+ // ============================================================
2849
+ // Instance methods
2850
+ // ============================================================
2851
+ /**
2852
+ * Fetch all endpoints, callback when all complete.
2853
+ * Uses cache when available.
2854
+ */
2855
+ all(attrs, done) {
2856
+ serviceSend(this, attrs, done, FETCH_FLAGS_ALL, false);
2857
+ return this;
2858
+ }
2859
+ /**
2860
+ * Fetch all endpoints, callback on each completion.
2861
+ */
2862
+ one(attrs, done) {
2863
+ serviceSend(this, attrs, done, FETCH_FLAGS_ONE, false);
2864
+ return this;
2865
+ }
2866
+ /**
2867
+ * Fetch all endpoints, skip cache (always request).
2868
+ */
2869
+ save(attrs, done) {
2870
+ serviceSend(this, attrs, done, FETCH_FLAGS_ALL, true);
2871
+ return this;
2872
+ }
2873
+ /**
2874
+ * Enqueue a task for sequential execution.
2875
+ */
2876
+ enqueue(callback) {
2877
+ if (!this.destroyed) {
2878
+ this.taskQueue.push(callback);
2879
+ this.dequeue(...this.prevArgs);
2880
+ }
2881
+ return this;
2882
+ }
2883
+ /**
2884
+ * Dequeue and execute the next task in queue.
2885
+ */
2886
+ dequeue(...args) {
2887
+ if (!this.busy && !this.destroyed) {
2888
+ this.busy = 1;
2889
+ setTimeout(() => {
2890
+ this.busy = 0;
2891
+ if (!this.destroyed) {
2892
+ const task2 = this.taskQueue.shift();
2893
+ if (task2) {
2894
+ this.prevArgs = args;
2895
+ funcWithTry(task2, args, this, noop);
2829
2896
  }
2830
- return cached;
2831
2897
  }
2898
+ }, 0);
2899
+ }
2900
+ }
2901
+ /**
2902
+ * Destroy the service instance.
2903
+ * After destruction, no new requests can be sent.
2904
+ */
2905
+ destroy() {
2906
+ this.destroyed = 1;
2907
+ this.taskQueue = [];
2908
+ }
2909
+ // Instance event methods (delegate to instance emitter)
2910
+ on(event, handler) {
2911
+ this._emitter.on(event, handler);
2912
+ return this;
2913
+ }
2914
+ off(event, handler) {
2915
+ this._emitter.off(event, handler);
2916
+ return this;
2917
+ }
2918
+ fire(event, data) {
2919
+ this._emitter.fire(event, data);
2920
+ return this;
2921
+ }
2922
+ // ============================================================
2923
+ // Per-type static state
2924
+ // ============================================================
2925
+ /** Per-type metadata registry */
2926
+ static _metaList = {};
2927
+ /** Per-type payload cache (LFU with frequency eviction) */
2928
+ static _payloadCache = new Cache({
2929
+ maxSize: 20,
2930
+ bufferSize: 5
2931
+ });
2932
+ /** Per-type pending cache keys for deduplication */
2933
+ static _pendingCacheKeys = {};
2934
+ /** Per-type sync function */
2935
+ static _syncFn = noop;
2936
+ /** Per-type static event emitter */
2937
+ static _staticEmitter = new EventEmitter();
2938
+ /** Per-type cache max size */
2939
+ static _cacheMax = 20;
2940
+ /** Per-type cache buffer size */
2941
+ static _cacheBuffer = 5;
2942
+ // ============================================================
2943
+ // Static methods (operate on per-type state via `this`)
2944
+ // ============================================================
2945
+ /**
2946
+ * Register API endpoint metadata.
2947
+ */
2948
+ static add(attrs) {
2949
+ if (!Array.isArray(attrs)) {
2950
+ attrs = [attrs];
2951
+ }
2952
+ for (const payload of attrs) {
2953
+ if (payload) {
2954
+ const name = payload.name;
2955
+ const cache = payload.cache;
2956
+ payload.cache = cache ? cache | 0 : 0;
2957
+ this._metaList[name] = payload;
2832
2958
  }
2833
- return void 0;
2834
- },
2835
- clear(names) {
2836
- const nameList = (typeof names === "string" ? names : names.join(",")).split(",");
2837
- const nameSet = {};
2838
- for (const n of nameList) {
2839
- nameSet[n] = 1;
2959
+ }
2960
+ }
2961
+ /**
2962
+ * Get metadata for an API endpoint.
2963
+ */
2964
+ static meta(attrs) {
2965
+ const name = typeof attrs === "string" ? attrs : attrs["name"];
2966
+ return this._metaList[name] || attrs;
2967
+ }
2968
+ /**
2969
+ * Create a Payload for an API request.
2970
+ */
2971
+ static create(attrs) {
2972
+ const meta = this.meta(attrs);
2973
+ const cache = attrs["cache"] | 0 || meta.cache || 0;
2974
+ const entity = new Payload();
2975
+ entity.set(meta);
2976
+ entity.cacheInfo = {
2977
+ name: meta.name,
2978
+ after: meta.after,
2979
+ cleans: meta.cleanKeys,
2980
+ key: cache ? defaultCacheKey(meta, attrs) : "",
2981
+ time: 0
2982
+ };
2983
+ if (typeof attrs === "object" && attrs !== null) {
2984
+ entity.set(attrs);
2985
+ }
2986
+ const before = meta.before;
2987
+ if (before) {
2988
+ funcWithTry(before, [entity], entity, noop);
2989
+ }
2990
+ this._staticEmitter.fire("begin", { payload: entity });
2991
+ return entity;
2992
+ }
2993
+ /**
2994
+ * Get or create a Payload for an API request.
2995
+ */
2996
+ static get(attrs, createNew) {
2997
+ let entity;
2998
+ let needsUpdate = false;
2999
+ if (!createNew) {
3000
+ entity = this.cached(attrs);
3001
+ }
3002
+ if (!entity) {
3003
+ entity = this.create(attrs);
3004
+ needsUpdate = true;
3005
+ }
3006
+ return { entity, needsUpdate };
3007
+ }
3008
+ /**
3009
+ * Get cached Payload if available and not expired.
3010
+ */
3011
+ static cached(attrs) {
3012
+ const meta = this.meta(attrs);
3013
+ const cache = attrs["cache"] | 0 || meta.cache || 0;
3014
+ let cacheKey = "";
3015
+ if (cache) {
3016
+ cacheKey = defaultCacheKey(meta, attrs);
3017
+ }
3018
+ if (cacheKey) {
3019
+ const info = this._pendingCacheKeys[cacheKey];
3020
+ if (info) {
3021
+ return info.entity;
2840
3022
  }
2841
- const keysToDelete = [];
2842
- bagCache.forEach((bag) => {
2843
- if (bag?.cacheInfo && nameSet[bag.cacheInfo.name]) {
2844
- if (bag.cacheInfo.key) {
2845
- keysToDelete.push(bag.cacheInfo.key);
2846
- }
3023
+ const cached = this._payloadCache.get(cacheKey);
3024
+ if (cached && cached.cacheInfo) {
3025
+ if (now() - cached.cacheInfo.time > cache) {
3026
+ this._payloadCache.del(cacheKey);
3027
+ return void 0;
2847
3028
  }
2848
- });
2849
- for (const key of keysToDelete) {
2850
- bagCache.del(key);
3029
+ return cached;
2851
3030
  }
2852
- },
2853
- on(event, handler) {
2854
- staticEmitter2.on(event, handler);
2855
- },
2856
- off(event, handler) {
2857
- staticEmitter2.off(event, handler);
2858
- },
2859
- fire(event, data) {
2860
- staticEmitter2.fire(event, data);
2861
- },
2862
- extend(newSyncFn, newCacheMax, newCacheBuffer) {
2863
- return createServiceType(
2864
- newSyncFn,
2865
- newCacheMax || cacheMax,
2866
- newCacheBuffer || cacheBuffer
2867
- );
2868
3031
  }
2869
- };
2870
- const internals = {
2871
- metas,
2872
- bagCache,
2873
- pendingCacheKeys,
2874
- syncFn,
2875
- staticEmitter: staticEmitter2
2876
- };
2877
- function ServiceInstance() {
2878
- this.id = generateId("s");
2879
- this["$e"] = 0;
2880
- this["$d"] = 0;
2881
- this["$g"] = [];
2882
- this["$h"] = [];
2883
- this._emitter = new EventEmitter();
2884
- this._internals = internals;
2885
- this._type = serviceType;
2886
- }
2887
- ServiceInstance.prototype = {
2888
- all(attrs, done) {
2889
- serviceSend(this, attrs, done, FETCH_FLAGS_ALL, false);
2890
- return this;
2891
- },
2892
- one(attrs, done) {
2893
- serviceSend(this, attrs, done, FETCH_FLAGS_ONE, false);
2894
- return this;
2895
- },
2896
- save(attrs, done) {
2897
- serviceSend(this, attrs, done, FETCH_FLAGS_ALL, true);
2898
- return this;
2899
- },
2900
- enqueue(callback) {
2901
- if (!this["$d"]) {
2902
- this["$g"].push(callback);
2903
- this.dequeue(...this["$h"]);
2904
- }
2905
- return this;
2906
- },
2907
- dequeue(...args) {
2908
- if (!this["$e"] && !this["$d"]) {
2909
- this["$e"] = 1;
2910
- setTimeout(() => {
2911
- this["$e"] = 0;
2912
- if (!this["$d"]) {
2913
- const task2 = this["$g"].shift();
2914
- if (task2) {
2915
- this["$h"] = args;
2916
- funcWithTry(task2, args, this, noop);
2917
- }
2918
- }
2919
- }, 0);
3032
+ return void 0;
3033
+ }
3034
+ /**
3035
+ * Clear cached payloads by endpoint name.
3036
+ */
3037
+ static clear(names) {
3038
+ const nameList = (typeof names === "string" ? names : names.join(",")).split(",");
3039
+ const nameSet = {};
3040
+ for (const n of nameList) {
3041
+ nameSet[n] = 1;
3042
+ }
3043
+ const keysToDelete = [];
3044
+ this._payloadCache.forEach((payload) => {
3045
+ if (payload?.cacheInfo && nameSet[payload.cacheInfo.name]) {
3046
+ if (payload.cacheInfo.key) {
3047
+ keysToDelete.push(payload.cacheInfo.key);
3048
+ }
2920
3049
  }
2921
- },
2922
- destroy() {
2923
- this["$d"] = 1;
2924
- this["$g"] = [];
2925
- },
2926
- on(event, handler) {
2927
- this._emitter.on(event, handler);
2928
- return this;
2929
- },
2930
- off(event, handler) {
2931
- this._emitter.off(event, handler);
2932
- return this;
2933
- },
2934
- fire(event, data) {
2935
- this._emitter.fire(event, data);
2936
- return this;
3050
+ });
3051
+ for (const key of keysToDelete) {
3052
+ this._payloadCache.del(key);
2937
3053
  }
2938
- };
2939
- const staticsMap = {
2940
- add: serviceType.add,
2941
- meta: serviceType.meta,
2942
- create: serviceType.create,
2943
- get: serviceType.get,
2944
- cached: serviceType.cached,
2945
- clear: serviceType.clear,
2946
- on: serviceType.on,
2947
- off: serviceType.off,
2948
- fire: serviceType.fire,
2949
- extend: serviceType.extend,
2950
- _internals: internals
2951
- };
2952
- const constructor = Object.assign(
2953
- ServiceInstance,
2954
- staticsMap
2955
- );
2956
- return constructor;
2957
- }
2958
- var Service = createServiceType(noop);
3054
+ }
3055
+ // Static event methods (operate on per-type emitter)
3056
+ static on(event, handler) {
3057
+ this._staticEmitter.on(event, handler);
3058
+ }
3059
+ static off(event, handler) {
3060
+ this._staticEmitter.off(event, handler);
3061
+ }
3062
+ static fire(event, data) {
3063
+ this._staticEmitter.fire(event, data);
3064
+ }
3065
+ /**
3066
+ * Create a new Service subclass with a custom sync function.
3067
+ * Each subclass gets its own per-type state (metaList, cache, etc.)
3068
+ * to ensure isolation between different Service types.
3069
+ */
3070
+ static extend(newSyncFn, newCacheMax, newCacheBuffer) {
3071
+ const ParentService = this;
3072
+ class ChildService extends ParentService {
3073
+ static _metaList = {};
3074
+ static _payloadCache = new Cache({
3075
+ maxSize: newCacheMax || ParentService._cacheMax,
3076
+ bufferSize: newCacheBuffer || ParentService._cacheBuffer
3077
+ });
3078
+ static _pendingCacheKeys = {};
3079
+ static _syncFn = newSyncFn;
3080
+ static _staticEmitter = new EventEmitter();
3081
+ static _cacheMax = newCacheMax || ParentService._cacheMax;
3082
+ static _cacheBuffer = newCacheBuffer || ParentService._cacheBuffer;
3083
+ }
3084
+ return ChildService;
3085
+ }
3086
+ };
2959
3087
  function defaultCacheKey(meta, attrs) {
2960
3088
  return JSON.stringify(attrs) + SPLITTER + JSON.stringify(meta);
2961
3089
  }
2962
3090
  function serviceSend(service, attrs, done, flag, save) {
2963
- if (service["$d"]) return;
2964
- if (service["$e"]) {
3091
+ if (service["destroyed"]) return;
3092
+ if (service["busy"]) {
2965
3093
  service.enqueue(
2966
3094
  serviceSend.bind(null, service, attrs, done, flag, save)
2967
3095
  );
2968
3096
  return;
2969
3097
  }
2970
- service["$e"] = 1;
3098
+ service["busy"] = 1;
2971
3099
  let attrList;
2972
3100
  if (typeof attrs === "string") {
2973
3101
  attrList = [{ name: attrs }];
2974
- } else if (isArray(attrs)) {
3102
+ } else if (Array.isArray(attrs)) {
2975
3103
  attrList = attrs;
2976
3104
  } else {
2977
3105
  attrList = [attrs];
2978
3106
  }
2979
- const internals = service._internals;
3107
+ const internals = service.internals;
2980
3108
  const { syncFn, pendingCacheKeys, staticEmitter: staticEmitter2 } = internals;
2981
3109
  let requestCount = 0;
2982
3110
  const total = attrList.length;
2983
3111
  const doneArr = new Array(total + 1);
2984
3112
  const errorArgs = [];
2985
3113
  const remoteComplete = (idx, error) => {
2986
- const bag = doneArr[idx + 1];
2987
- let newBag = false;
3114
+ const payload = doneArr[idx + 1];
3115
+ let newPayload = false;
2988
3116
  if (error) {
2989
3117
  errorArgs[idx] = error;
2990
- staticEmitter2.fire("fail", { bag, error });
3118
+ staticEmitter2.fire("fail", { payload, error });
2991
3119
  } else {
2992
- newBag = true;
2993
- staticEmitter2.fire("done", { bag });
3120
+ newPayload = true;
3121
+ staticEmitter2.fire("done", { payload });
2994
3122
  }
2995
- if (!service["$d"]) {
3123
+ if (!service["destroyed"]) {
2996
3124
  const finish = requestCount === total;
2997
3125
  if (finish) {
2998
- service["$e"] = 0;
3126
+ service["busy"] = 0;
2999
3127
  if (flag === FETCH_FLAGS_ALL) {
3000
3128
  doneArr[0] = errorArgs;
3001
3129
  funcWithTry(done, doneArr, service, noop);
3002
3130
  }
3003
3131
  }
3004
3132
  if (flag === FETCH_FLAGS_ONE) {
3005
- funcWithTry(done, [error || null, bag, finish, idx], service, noop);
3133
+ funcWithTry(done, [error || null, payload, finish, idx], service, noop);
3006
3134
  }
3007
3135
  }
3008
- if (newBag) {
3009
- staticEmitter2.fire("end", { bag, error });
3136
+ if (newPayload) {
3137
+ staticEmitter2.fire("end", { payload, error });
3010
3138
  }
3011
3139
  };
3012
3140
  for (const attr of attrList) {
3013
3141
  if (!attr) continue;
3014
3142
  const attrObj = typeof attr === "string" ? { name: attr } : attr;
3015
- const bagInfo = service._type.get(attrObj, save);
3016
- const bagEntity = bagInfo.entity;
3017
- const cacheKey = bagEntity.cacheInfo?.key || "";
3143
+ const payloadInfo = service.type.get(
3144
+ attrObj,
3145
+ save
3146
+ );
3147
+ const payloadEntity = payloadInfo.entity;
3148
+ const cacheKey = payloadEntity.cacheInfo?.key || "";
3018
3149
  const complete = remoteComplete.bind(null, requestCount++);
3019
3150
  if (cacheKey && pendingCacheKeys[cacheKey]) {
3020
3151
  pendingCacheKeys[cacheKey].push(complete);
3021
- } else if (bagInfo.needsUpdate) {
3152
+ } else if (payloadInfo.needsUpdate) {
3022
3153
  if (cacheKey) {
3023
3154
  const cacheList = [complete];
3024
- cacheList.e = bagEntity;
3155
+ cacheList.entity = payloadEntity;
3025
3156
  pendingCacheKeys[cacheKey] = cacheList;
3026
3157
  const cacheComplete = () => {
3027
3158
  const list = pendingCacheKeys[cacheKey];
3028
- const entity = list.e;
3159
+ const entity = list.entity;
3029
3160
  if (entity.cacheInfo) {
3030
3161
  entity.cacheInfo.time = now();
3031
3162
  }
3032
- internals.bagCache.set(cacheKey, entity);
3163
+ internals.payloadCache.set(cacheKey, entity);
3033
3164
  Reflect.deleteProperty(pendingCacheKeys, cacheKey);
3034
3165
  for (const cb of list) {
3035
3166
  if (typeof cb === "function") {
@@ -3037,9 +3168,9 @@ function serviceSend(service, attrs, done, flag, save) {
3037
3168
  }
3038
3169
  }
3039
3170
  };
3040
- syncFn(bagEntity, cacheComplete);
3171
+ syncFn(payloadEntity, cacheComplete);
3041
3172
  } else {
3042
- syncFn(bagEntity, complete);
3173
+ syncFn(payloadEntity, complete);
3043
3174
  }
3044
3175
  } else {
3045
3176
  complete();
@@ -3047,9 +3178,117 @@ function serviceSend(service, attrs, done, flag, save) {
3047
3178
  }
3048
3179
  }
3049
3180
 
3181
+ // src/frame-visualizer.ts
3182
+ var MSG_PING = "LARK_VISUALIZER_PING";
3183
+ var MSG_PONG = "LARK_VISUALIZER_PONG";
3184
+ var MSG_REQUEST_TREE = "LARK_VISUALIZER_REQUEST_TREE";
3185
+ var MSG_TREE = "LARK_VISUALIZER_TREE";
3186
+ var MSG_TREE_DELTA = "LARK_VISUALIZER_TREE_DELTA";
3187
+ function serializeView(view) {
3188
+ return {
3189
+ id: view.id,
3190
+ rendered: !!view.rendered,
3191
+ signature: view.signature,
3192
+ observedStateKeys: view.observedStateKeys ?? null,
3193
+ locationObserved: {
3194
+ flag: view.locationObserved.flag,
3195
+ keys: view.locationObserved.keys,
3196
+ observePath: view.locationObserved.observePath
3197
+ },
3198
+ hasTemplate: !!view.template
3199
+ };
3200
+ }
3201
+ function serializeFrame(frameId) {
3202
+ const frame = Frame.get(frameId);
3203
+ if (!frame) return null;
3204
+ const view = frame.view;
3205
+ const children = [];
3206
+ for (const childId of frame.children()) {
3207
+ const childNode = serializeFrame(childId);
3208
+ if (childNode) {
3209
+ children.push(childNode);
3210
+ }
3211
+ }
3212
+ return {
3213
+ id: frame.id,
3214
+ parentId: frame.parentId ?? null,
3215
+ viewPath: frame.viewPath ?? null,
3216
+ childrenCount: frame.childrenCount,
3217
+ readyCount: frame.readyCount,
3218
+ childrenCreated: frame.childrenCreated,
3219
+ childrenAlter: frame.childrenAlter,
3220
+ destroyed: frame.destroyed,
3221
+ view: view ? serializeView(view) : null,
3222
+ children
3223
+ };
3224
+ }
3225
+ function serializeFrameTree() {
3226
+ const root = Frame.root();
3227
+ const rootNode = serializeFrame(root.id);
3228
+ let totalFrames = 0;
3229
+ const countFrames = (node) => {
3230
+ if (!node) return;
3231
+ totalFrames++;
3232
+ for (const child of node.children) {
3233
+ countFrames(child);
3234
+ }
3235
+ };
3236
+ countFrames(rootNode);
3237
+ return {
3238
+ root: rootNode,
3239
+ totalFrames,
3240
+ timestamp: Date.now(),
3241
+ rootId: root.id
3242
+ };
3243
+ }
3244
+ var bridgeInstalled = false;
3245
+ var lastTreeJson = "";
3246
+ function installFrameVisualizerBridge() {
3247
+ if (bridgeInstalled) return;
3248
+ if (typeof window === "undefined") return;
3249
+ bridgeInstalled = true;
3250
+ window.addEventListener("message", (event) => {
3251
+ const data = event.data;
3252
+ if (!data || typeof data !== "object") return;
3253
+ const type = data.type;
3254
+ if (type === MSG_PING) {
3255
+ const source = event.source;
3256
+ if (source) {
3257
+ source.postMessage({ type: MSG_PONG }, { targetOrigin: "*" });
3258
+ }
3259
+ return;
3260
+ }
3261
+ if (type === MSG_REQUEST_TREE) {
3262
+ const tree = serializeFrameTree();
3263
+ const source = event.source;
3264
+ if (source) {
3265
+ source.postMessage(
3266
+ { type: MSG_TREE, data: tree },
3267
+ { targetOrigin: "*" }
3268
+ );
3269
+ }
3270
+ }
3271
+ });
3272
+ Frame.on("add", () => {
3273
+ pushTreeUpdate();
3274
+ });
3275
+ Frame.on("remove", () => {
3276
+ pushTreeUpdate();
3277
+ });
3278
+ }
3279
+ function pushTreeUpdate() {
3280
+ if (window === window.parent) return;
3281
+ const tree = serializeFrameTree();
3282
+ const treeJson = JSON.stringify(tree);
3283
+ if (treeJson !== lastTreeJson) {
3284
+ lastTreeJson = treeJson;
3285
+ window.parent.postMessage({ type: MSG_TREE_DELTA, data: tree }, "*");
3286
+ }
3287
+ }
3288
+
3050
3289
  // src/framework.ts
3051
3290
  var config = {
3052
- rootId: "lark-root",
3291
+ rootId: "root",
3053
3292
  hashbang: "#!",
3054
3293
  error: (error) => {
3055
3294
  throw error;
@@ -3142,7 +3381,12 @@ function dispatcherUpdate(frame, stateKeys) {
3142
3381
  const isChanged = stateKeys ? stateIsObserveChanged(view, stateKeys) : viewIsObserveChanged(view);
3143
3382
  let renderPromise;
3144
3383
  if (isChanged) {
3145
- const renderResult = funcWithTry(view.$b ?? view.render, [], view, noop);
3384
+ const renderResult = funcWithTry(
3385
+ view.renderMethod ?? view.render,
3386
+ [],
3387
+ view,
3388
+ noop
3389
+ );
3146
3390
  if (renderResult && typeof renderResult.then === "function") {
3147
3391
  renderPromise = renderResult;
3148
3392
  }
@@ -3164,13 +3408,13 @@ function dispatcherUpdate(frame, stateKeys) {
3164
3408
  }
3165
3409
  function dispatcherNotifyChange(e) {
3166
3410
  const rootFrame2 = Frame.root();
3167
- const view = e["view"];
3411
+ const view = e.view;
3168
3412
  if (view) {
3169
3413
  const viewPath = typeof view === "object" && view !== null ? String(view.to || "") : String(view);
3170
3414
  rootFrame2.mountView(viewPath);
3171
3415
  } else {
3172
3416
  dispatcherUpdateTag++;
3173
- dispatcherUpdate(rootFrame2, e["keys"]);
3417
+ dispatcherUpdate(rootFrame2, e.keys);
3174
3418
  }
3175
3419
  }
3176
3420
  function dispatchEvent(target, eventType, eventInit) {
@@ -3181,8 +3425,6 @@ function dispatchEvent(target, eventType, eventInit) {
3181
3425
  });
3182
3426
  target.dispatchEvent(event);
3183
3427
  }
3184
- var Base = class extends EventEmitter {
3185
- };
3186
3428
  function use(names, callback) {
3187
3429
  if (!config.require) {
3188
3430
  if (callback) callback();
@@ -3197,7 +3439,7 @@ function use(names, callback) {
3197
3439
  }
3198
3440
  }
3199
3441
  var WAIT_OK = 1;
3200
- var WAIT_TIMEOUT_OR_UNFOUND = 0;
3442
+ var WAIT_TIMEOUT_OR_NOT_FOUND = 0;
3201
3443
  function waitZoneViewsRendered(viewId, timeout) {
3202
3444
  if (timeout == null) {
3203
3445
  timeout = 30 * 1e3;
@@ -3208,7 +3450,7 @@ function waitZoneViewsRendered(viewId, timeout) {
3208
3450
  const check = () => {
3209
3451
  const currentTime = now();
3210
3452
  if (currentTime > endTime || !checkFrame) {
3211
- resolve(WAIT_TIMEOUT_OR_UNFOUND);
3453
+ resolve(WAIT_TIMEOUT_OR_NOT_FOUND);
3212
3454
  } else if (checkFrame.childrenCount === checkFrame.readyCount) {
3213
3455
  resolve(WAIT_OK);
3214
3456
  } else {
@@ -3245,14 +3487,15 @@ var Framework = {
3245
3487
  Router._setConfig(config);
3246
3488
  EventDelegator.setFrameGetter((id) => Frame.get(id));
3247
3489
  Router.on(ROUTER_EVENTS.CHANGED, (data) => {
3248
- dispatcherNotifyChange(data);
3490
+ if (data) dispatcherNotifyChange(data);
3249
3491
  });
3250
3492
  State.on(ROUTER_EVENTS.CHANGED, (data) => {
3251
- dispatcherNotifyChange(data);
3493
+ if (data) dispatcherNotifyChange(data);
3252
3494
  });
3253
3495
  booted3 = true;
3254
3496
  markBooted();
3255
3497
  markRouterBooted();
3498
+ installFrameVisualizerBridge();
3256
3499
  const rootFrame2 = Frame.root(config.rootId);
3257
3500
  Router._bind();
3258
3501
  const defaultView = config.defaultView || "";
@@ -3284,7 +3527,7 @@ var Framework = {
3284
3527
  /** Wait for zone views to be rendered */
3285
3528
  waitZoneViewsRendered,
3286
3529
  WAIT_OK,
3287
- WAIT_TIMEOUT_OR_UNFOUND,
3530
+ WAIT_TIMEOUT_OR_NOT_FOUND,
3288
3531
  /**
3289
3532
  * Convert array to hash map.
3290
3533
  */
@@ -3349,7 +3592,7 @@ var Framework = {
3349
3592
  /**
3350
3593
  * Base class with EventEmitter.
3351
3594
  */
3352
- Base,
3595
+ Base: EventEmitter,
3353
3596
  // ============================================================
3354
3597
  // Module access
3355
3598
  // ============================================================
@@ -3367,10 +3610,11 @@ if (typeof window !== "undefined") {
3367
3610
  window.__lark_State = State;
3368
3611
  window.__lark_Router = Router;
3369
3612
  window.__lark_Frame = Frame;
3613
+ window.__lark_View = View;
3370
3614
  }
3371
3615
 
3372
3616
  // src/store.ts
3373
- var LARK_GLOBAL = "lark_global";
3617
+ var LARK_GLOBAL = "lark-global";
3374
3618
  var Platform = /* @__PURE__ */ ((Platform2) => {
3375
3619
  Platform2["Lark"] = "lark";
3376
3620
  Platform2["React"] = "react";
@@ -3413,8 +3657,10 @@ var Queue = class {
3413
3657
  const flushTickTask = () => {
3414
3658
  while (queue.length > 0) {
3415
3659
  const task2 = queue.shift();
3416
- pendingTasks.delete(task2);
3417
- runTask(task2);
3660
+ if (task2) {
3661
+ pendingTasks.delete(task2);
3662
+ runTask(task2);
3663
+ }
3418
3664
  }
3419
3665
  };
3420
3666
  Promise.resolve().then(flushTickTask);
@@ -3513,9 +3759,11 @@ var setStateConfig = (target, config2) => {
3513
3759
  if (target && isObject(config2)) StateConfigMap.set(target, config2);
3514
3760
  };
3515
3761
  var getStateConfig = (target, key) => {
3516
- if (!StateConfigMap.has(target)) return void 0;
3762
+ if (!StateConfigMap.has(target)) {
3763
+ return void 0;
3764
+ }
3517
3765
  const config2 = StateConfigMap.get(target);
3518
- return key ? config2[key] : config2;
3766
+ return key ? config2?.[key] : config2;
3519
3767
  };
3520
3768
  var isState = (target) => isObject(target) && StateConfigMap.has(target);
3521
3769
  var createLinkKeys = (target, property) => {
@@ -3685,20 +3933,20 @@ function createState(initialData, config2) {
3685
3933
  lazySet(state, initialData);
3686
3934
  return state;
3687
3935
  }
3688
- var currLazySetKey = null;
3936
+ var curLazySetKey = null;
3689
3937
  function lazySet(target, data) {
3690
3938
  if (isObject(data)) {
3691
3939
  Reflect.ownKeys(data).forEach((key) => {
3692
3940
  const strKey = key;
3693
- if (currLazySetKey) throw new Error("[lark-store] lazy set key conflict");
3694
- currLazySetKey = strKey;
3941
+ if (curLazySetKey) throw new Error("[lark-store] lazy set key conflict");
3942
+ curLazySetKey = strKey;
3695
3943
  target[strKey] = data[strKey];
3696
3944
  });
3697
3945
  }
3698
3946
  }
3699
3947
  function isLazySet(property) {
3700
- if (currLazySetKey === property) {
3701
- currLazySetKey = "";
3948
+ if (curLazySetKey === property) {
3949
+ curLazySetKey = "";
3702
3950
  return true;
3703
3951
  }
3704
3952
  return false;
@@ -4082,14 +4330,11 @@ function defineStore(name, creator, config2) {
4082
4330
  const useStore = adapter.useStore;
4083
4331
  const store = new StoreClass(name, config2);
4084
4332
  store[_storeCreate](
4085
- creator(
4086
- store[_innerStore](),
4087
- extendApis
4088
- )
4333
+ creator(store[_innerStore](), extendApis)
4089
4334
  );
4090
4335
  Object.defineProperties(useStore, {
4091
4336
  $storeName: { value: name, configurable: true },
4092
- $del: { value: () => store[_storeDestroy](), configurable: true }
4337
+ $destroyFn: { value: () => store[_storeDestroy](), configurable: true }
4093
4338
  });
4094
4339
  if (!StoreCache.has(name)) {
4095
4340
  StoreCache.set(name, { store, creator, config: config2, useStore });
@@ -4154,7 +4399,7 @@ function observeCell(state, cb, immediate = true) {
4154
4399
  }
4155
4400
  function multi(useStore) {
4156
4401
  const storeName = useStore["$storeName"];
4157
- const flagSym = `lark_comp_${storeName}`;
4402
+ const flagSym = `lark-comp-${storeName}`;
4158
4403
  const map = /* @__PURE__ */ new Map();
4159
4404
  let rootViewPath;
4160
4405
  const getFlag = (viewContext) => {
@@ -4163,7 +4408,7 @@ function multi(useStore) {
4163
4408
  const viewId = owner?.["id"] || "";
4164
4409
  let flag;
4165
4410
  if (viewPath === rootViewPath) {
4166
- flag = `${flagSym}_${viewId}`;
4411
+ flag = `${flagSym}-${viewId}`;
4167
4412
  } else {
4168
4413
  flag = owner?.["viewInitParams"]?.[flagSym];
4169
4414
  }
@@ -4180,19 +4425,18 @@ function multi(useStore) {
4180
4425
  };
4181
4426
  const useFn = ((view) => {
4182
4427
  if (!view)
4183
- throw new Error("[lark-store] multi: cannot find the view instance");
4428
+ throw new Error(
4429
+ "[@lark.js/mvc error] multi: cannot find the view instance"
4430
+ );
4184
4431
  const viewCtx = view;
4185
4432
  const flag = viewCtx[flagSym];
4186
4433
  if (map.has(flag)) return map.get(flag);
4187
- const newFn = cloneStore(
4188
- flag,
4189
- useStore
4190
- );
4434
+ const newFn = cloneStore(flag, useStore);
4191
4435
  map.set(flag, newFn);
4192
4436
  return useFn(view);
4193
4437
  });
4194
4438
  const mixinObj = {
4195
- ctor() {
4439
+ make() {
4196
4440
  if (!rootViewPath) {
4197
4441
  const owner = this["owner"];
4198
4442
  rootViewPath = owner?.["path"] || "";
@@ -4242,17 +4486,17 @@ function restoreComments(source, comments) {
4242
4486
  }
4243
4487
  function processViewEvents(source) {
4244
4488
  return source.replace(
4245
- /v-(\w+)="([^"]+)"/g,
4489
+ /@(\w+)="([^"]+)"/g,
4246
4490
  (fullAttr, eventName, attrValue) => {
4247
4491
  const eventMatch = attrValue.match(/^(\w+)\((.*)\)$/s);
4248
4492
  if (!eventMatch) return fullAttr;
4249
4493
  const handlerName = eventMatch[1];
4250
4494
  const paramsStr = eventMatch[2].trim();
4251
4495
  if (!paramsStr) {
4252
- return `v-${eventName}="${VIEW_ID_PLACEHOLDER}${SPLITTER2}${handlerName}()"`;
4496
+ return `@${eventName}="${VIEW_ID_PLACEHOLDER}${SPLITTER2}${handlerName}()"`;
4253
4497
  }
4254
4498
  const urlParams = jsObjectToUrlParams(paramsStr);
4255
- return `v-${eventName}="${VIEW_ID_PLACEHOLDER}${SPLITTER2}${handlerName}(${urlParams})"`;
4499
+ return `@${eventName}="${VIEW_ID_PLACEHOLDER}${SPLITTER2}${handlerName}(${urlParams})"`;
4256
4500
  }
4257
4501
  );
4258
4502
  }
@@ -4325,7 +4569,7 @@ function convertArtSyntax(source, debug) {
4325
4569
  }
4326
4570
  if (blockStack.length > 0) {
4327
4571
  const unclosed = blockStack.map((b) => `"${b.ctrl}" at line ${b.line}`).join(", ");
4328
- throw new Error(`[@lark/mvc error] unclosed block(s): ${unclosed}`);
4572
+ throw new Error(`[@lark.js/mvc error] unclosed block(s): ${unclosed}`);
4329
4573
  }
4330
4574
  return result.join("");
4331
4575
  }
@@ -4419,12 +4663,12 @@ function convertArtExpression(code, debug, lineNo, blockStack = []) {
4419
4663
  }
4420
4664
  return `${debugPrefix}<%}else{%>`;
4421
4665
  }
4422
- case "each": {
4423
- blockStack.push({ ctrl: "each", line: lineNo });
4666
+ case "forOf": {
4667
+ blockStack.push({ ctrl: "forOf", line: lineNo });
4424
4668
  const object = tokens[0];
4425
4669
  if (tokens.length > 1 && tokens[1] !== "as") {
4426
4670
  throw new Error(
4427
- `[@lark/mvc error] bad each syntax: {{${code}}}. Expected "as" keyword, got "${tokens[1]}". Usage: {{each list as item [index]}}`
4671
+ `[@lark.js/mvc error] bad forOf syntax: {{${code}}}. Expected "as" keyword, got "${tokens[1]}". Usage: {{forOf list as item [index]}}`
4428
4672
  );
4429
4673
  }
4430
4674
  const restTokens = tokens.slice(2);
@@ -4446,12 +4690,12 @@ function convertArtExpression(code, debug, lineNo, blockStack = []) {
4446
4690
  }
4447
4691
  return `${debugPrefix}<%for(let ${index}=0${refExpr},${refObjCount}=${refObj}.length${lastCount};${index}<${refObjCount};${index}++){${firstAndLast}${valueDecl}%>`;
4448
4692
  }
4449
- case "parse": {
4450
- blockStack.push({ ctrl: "parse", line: lineNo });
4693
+ case "forIn": {
4694
+ blockStack.push({ ctrl: "forIn", line: lineNo });
4451
4695
  const object = tokens[0];
4452
4696
  if (tokens.length > 1 && tokens[1] !== "as") {
4453
4697
  throw new Error(
4454
- `[@lark/mvc error] bad parse syntax: {{${code}}}. Expected "as" keyword, got "${tokens[1]}". Usage: {{for-in obj as val [key]}}`
4698
+ `[@lark.js/mvc error] bad forIn syntax: {{${code}}}. Expected "as" keyword, got "${tokens[1]}". Usage: {{for-in obj as val [key]}}`
4455
4699
  );
4456
4700
  }
4457
4701
  const restTokens2 = tokens.slice(2);
@@ -4471,19 +4715,19 @@ function convertArtExpression(code, debug, lineNo, blockStack = []) {
4471
4715
  case "set":
4472
4716
  return `${debugPrefix}<%let ${tokens.join(" ")};%>`;
4473
4717
  case "/if":
4474
- case "/each":
4475
- case "/parse":
4718
+ case "/forOf":
4719
+ case "/forIn":
4476
4720
  case "/for": {
4477
4721
  const expectedCtrl = keyword.substring(1);
4478
4722
  const last = blockStack.pop();
4479
4723
  if (!last) {
4480
4724
  throw new Error(
4481
- `[@lark/mvc error(template] unexpected {{${code}}}: no matching open block`
4725
+ `[@lark.js/mvc error] unexpected {{${code}}}: no matching open block`
4482
4726
  );
4483
4727
  }
4484
4728
  if (last.ctrl !== expectedCtrl) {
4485
4729
  throw new Error(
4486
- `[@lark/mvc error(template] unexpected {{${code}}}: expected {{/${last.ctrl}}} to close block opened at line ${last.line}`
4730
+ `[@lark.js/mvc error] unexpected {{${code}}}: expected {{/${last.ctrl}}} to close block opened at line ${last.line}`
4487
4731
  );
4488
4732
  }
4489
4733
  return `${debugPrefix}<%}%>`;
@@ -4547,7 +4791,7 @@ function parseAsExpr(expr) {
4547
4791
  function compileToFunction(source, debug, file) {
4548
4792
  const matcher = /<%([@=!:])?([\s\S]*?)%>|$/g;
4549
4793
  let index = 0;
4550
- let funcSource = `$p+='`;
4794
+ let funcSource = `$out+='`;
4551
4795
  let hasAtRule = false;
4552
4796
  const escapeSlashRegExp = /\\|'/g;
4553
4797
  const escapeBreakReturnRegExp = /\r|\n/g;
@@ -4573,17 +4817,17 @@ function compileToFunction(source, debug, file) {
4573
4817
  }
4574
4818
  if (operate === "@") {
4575
4819
  hasAtRule = true;
4576
- funcSource += `'+($expr='<%${operate + expr}%>',$i($$ref,${content}))+'`;
4820
+ funcSource += `'+($dbgExpr='<%${operate + expr}%>',$refFn($refAlt,${content}))+'`;
4577
4821
  } else if (operate === "=" || operate === ":") {
4578
- funcSource += `'+($expr='<%${operate + expr}%>',$e(${content}))+'`;
4822
+ funcSource += `'+($dbgExpr='<%${operate + expr}%>',$encHtml(${content}))+'`;
4579
4823
  } else if (operate === "!") {
4580
- if (!content.startsWith("$eu(") || !content.endsWith(")")) {
4581
- content = `$n(${content})`;
4824
+ if (!content.startsWith("$encUri(") || !content.endsWith(")")) {
4825
+ content = `$strSafe(${content})`;
4582
4826
  }
4583
- funcSource += `'+($expr='<%${operate + expr}%>',${content})+'`;
4827
+ funcSource += `'+($dbgExpr='<%${operate + expr}%>',${content})+'`;
4584
4828
  } else if (content) {
4585
4829
  if (line > -1) {
4586
- funcSource += `';$line=${line};$art='${art}';`;
4830
+ funcSource += `';$dbgLine=${line};$dbgArt='${art}';`;
4587
4831
  content = "";
4588
4832
  } else {
4589
4833
  funcSource += `';`;
@@ -4592,19 +4836,19 @@ function compileToFunction(source, debug, file) {
4592
4836
  funcSource = funcSource.substring(0, funcSource.length - 4) + ";";
4593
4837
  }
4594
4838
  if (expr) {
4595
- funcSource += `$expr='<%${expr}%>';`;
4839
+ funcSource += `$dbgExpr='<%${expr}%>';`;
4596
4840
  }
4597
- funcSource += content + `;$p+='`;
4841
+ funcSource += content + `;$out+='`;
4598
4842
  }
4599
4843
  } else {
4600
4844
  if (operate === "@") {
4601
4845
  hasAtRule = true;
4602
- funcSource += `'+$i($$ref,${content})+'`;
4846
+ funcSource += `'+$refFn($refAlt,${content})+'`;
4603
4847
  } else if (operate === "=" || operate === ":") {
4604
- funcSource += `'+$e(${content})+'`;
4848
+ funcSource += `'+$encHtml(${content})+'`;
4605
4849
  } else if (operate === "!") {
4606
- if (!content.startsWith("$eu(") || !content.endsWith(")")) {
4607
- content = `$n(${content})`;
4850
+ if (!content.startsWith("$encUri(") || !content.endsWith(")")) {
4851
+ content = `$strSafe(${content})`;
4608
4852
  }
4609
4853
  funcSource += `'+${content}+'`;
4610
4854
  } else if (content) {
@@ -4612,28 +4856,28 @@ function compileToFunction(source, debug, file) {
4612
4856
  if (funcSource.endsWith(`+'';`)) {
4613
4857
  funcSource = funcSource.substring(0, funcSource.length - 4) + ";";
4614
4858
  }
4615
- funcSource += `${content};$p+='`;
4859
+ funcSource += `${content};$out+='`;
4616
4860
  }
4617
4861
  }
4618
4862
  return match;
4619
4863
  });
4620
4864
  funcSource += `';`;
4621
- funcSource = funcSource.replace(/\$p\+='';/g, "");
4622
- funcSource = funcSource.replace(/\$p\+=''\+/g, "$p+=");
4865
+ funcSource = funcSource.replace(/\$out\+='';/g, "");
4866
+ funcSource = funcSource.replace(/\$out\+=''\+/g, "$out+=");
4623
4867
  if (debug) {
4624
4868
  const filePart = file ? `\\r\\n\\tat file:${file}` : "";
4625
- funcSource = `let $expr,$art,$line;try{${funcSource}}catch(ex){let msg='render view error:'+(ex.message||ex);if($art)msg+='\\r\\n\\tsrc art:{{'+$art+'}}\\r\\n\\tat line:'+$line;msg+='\\r\\n\\t'+($art?'translate to:':'expr:');msg+=$expr+'${filePart}';throw msg;}`;
4869
+ funcSource = `let $dbgExpr,$dbgArt,$dbgLine;try{${funcSource}}catch(ex){let msg='render view error:'+(ex.message||ex);if($dbgArt)msg+='\\r\\n\\tsrc art:{{'+$dbgArt+'}}\\r\\n\\tat line:'+$dbgLine;msg+='\\r\\n\\t'+($dbgArt?'translate to:':'expr:');msg+=$dbgExpr+'${filePart}';throw msg;}`;
4626
4870
  }
4627
4871
  const viewIdRegExp = new RegExp(String.fromCharCode(31), "g");
4628
4872
  funcSource = funcSource.replace(viewIdRegExp, `'+$viewId+'`);
4629
- const atRule = hasAtRule ? `if(!$i){$i=(ref,v,k,f)=>{for(f=ref[$g];--f;)if(ref[k=$g+f]===v)return k;ref[k=$g+ref[$g]++]=v;return k;}}` : "";
4630
- const encode = `if(!$n){let $em={'&':'amp','<':'lt','>':'gt','"':'#34','\\'':'#39','\`':'#96'},$er=/[&<>"'\`]/g,$ef=m=>'&'+$em[m]+';';$n=v=>''+(v==null?'':v);$e=v=>$n(v).replace($er,$ef)}`;
4631
- const encodeURIMore = `if(!$eu){let $um={'!':'%21','\\'':'%27','(':'%28',')':'%29','*':'%2A'},$uf=m=>$um[m],$uq=/[!')(*]/g;$eu=v=>encodeURIComponent($n(v)).replace($uq,$uf)}`;
4632
- const encodeQuote = `if(!$eq){let $qr=/['"\\\\]/g;$eq=v=>$n(v).replace($qr,'\\\\$&')}`;
4633
- const refFallback = "if(!$$ref)$$ref=$$;";
4873
+ const atRule = hasAtRule ? `if(!$refFn){$refFn=(ref,v,k,f)=>{for(f=ref[$splitter];--f;)if(ref[k=$splitter+f]===v)return k;ref[k=$splitter+ref[$splitter]++]=v;return k;}}` : "";
4874
+ const encode = `if(!$strSafe){let $entMap={'&':'amp','<':'lt','>':'gt','"':'#34','\\'':'#39','\`':'#96'},$entReg=/[&<>"'\`]/g,$entFn=m=>'&'+$entMap[m]+';';$strSafe=v=>''+(v==null?'':v);$encHtml=v=>$strSafe(v).replace($entReg,$entFn)}`;
4875
+ const encodeURIMore = `if(!$encUri){let $uriMap={'!':'%21','\\'':'%27','(':'%28',')':'%29','*':'%2A'},$uriFn=m=>$uriMap[m],$uriReg=/[!')(*]/g;$encUri=v=>encodeURIComponent($strSafe(v)).replace($uriReg,$uriFn)}`;
4876
+ const encodeQuote = `if(!$encQuote){let $qReg=/['"\\\\]/g;$encQuote=v=>$strSafe(v).replace($qReg,'\\\\$&')}`;
4877
+ const refFallback = "if(!$refAlt)$refAlt=$data;";
4634
4878
  const fns = `${refFallback}${encode}${encodeURIMore}${encodeQuote}${atRule};`;
4635
- const fullSource = `${fns}let $g='\\x1e',$_temp,$p=''{{VARS}};${funcSource}return $p`;
4636
- return `($$,$viewId,$$ref,$e,$n,$eu,$i,$eq)=>{${fullSource}}`;
4879
+ const fullSource = `${fns}let $splitter='\\x1e',$tmp,$out=''{{VARS}};${funcSource}return $out`;
4880
+ return `($data,$viewId,$refAlt,$encHtml,$strSafe,$encUri,$refFn,$encQuote)=>{${fullSource}}`;
4637
4881
  }
4638
4882
  function compileTemplate(source, options = {}) {
4639
4883
  const { debug = false, globalVars = [], file } = options;
@@ -4642,17 +4886,17 @@ function compileTemplate(source, options = {}) {
4642
4886
  const viewEventProcessed = processViewEvents(converted);
4643
4887
  const finalSource = restoreComments(viewEventProcessed, comments);
4644
4888
  const funcBody = compileToFunction(finalSource, debug, file);
4645
- const varDeclarations = globalVars.map((key) => `,${key}=$$.${key}`).join("");
4889
+ const varDeclarations = globalVars.map((key) => `,${key}=$data.${key}`).join("");
4646
4890
  const funcWithVars = funcBody.replace("{{VARS}}", () => varDeclarations);
4647
4891
  return `export default function(data, selfId, refData) {
4648
- let $$ = data || {},
4892
+ let $data = data || {},
4649
4893
  $viewId = selfId || '';
4650
- return (${funcWithVars})($$, $viewId, refData,
4651
- /* $e */ v => String(v == null ? '' : v).replace(/[&<>"'\`]/g, m => '&' + ({'&':'amp','<':'lt','>':'gt','"':'#34',"'":'#39','\`':'#96'})[m] + ';'),
4652
- /* $n */ v => String(v == null ? '' : v),
4653
- /* $eu */ null,
4654
- /* $i */ null,
4655
- /* $eq */ null
4894
+ return (${funcWithVars})($data, $viewId, refData,
4895
+ /* $encHtml */ v => String(v == null ? '' : v).replace(/[&<>"'\`]/g, m => '&' + ({'&':'amp','<':'lt','>':'gt','"':'#34',"'":'#39','\`':'#96'})[m] + ';'),
4896
+ /* $strSafe */ v => String(v == null ? '' : v),
4897
+ /* $encUri */ null,
4898
+ /* $refFn */ null,
4899
+ /* $encQuote */ null
4656
4900
  );
4657
4901
  }`;
4658
4902
  }
@@ -4761,7 +5005,7 @@ function fallbackExtractVariables(source) {
4761
5005
  while ((m = outputRegExp.exec(source)) !== null) {
4762
5006
  vars.add(m[1]);
4763
5007
  }
4764
- const eachRegExp = /\{\{each\s+([a-zA-Z_$][\w$]*)\s+as/g;
5008
+ const eachRegExp = /\{\{forOf\s+([a-zA-Z_$][\w$]*)\s+as/g;
4765
5009
  while ((m = eachRegExp.exec(source)) !== null) {
4766
5010
  vars.add(m[1]);
4767
5011
  }
@@ -4807,77 +5051,88 @@ var BUILTIN_GLOBALS = {
4807
5051
  //
4808
5052
  // These variables appear in the generated template function signature
4809
5053
  // or body. They must be excluded from extractGlobalVars() so that
4810
- // they are not mistaken for user data variables and destructured from $$.
5054
+ // they are not mistaken for user data variables and destructured from $data.
4811
5055
  // SPLITTER character constant (same as \x1e), used as namespace separator
4812
5056
  // for refData keys, event attribute encoding, and internal data structures.
4813
- // Declared as: let $g='\x1e'
4814
- $g: 1,
4815
- // refData — the data object passed from Updater to the template function.
4816
- // User variables are destructured from $$ at the top of the function:
4817
- // let {name, age} = $$;
5057
+ // Declared as: let $splitter='\x1e'
5058
+ $splitter: 1,
5059
+ // Data — the data object passed from Updater to the template function.
5060
+ // User variables are destructured from $data at the top of the function:
5061
+ // let {name, age} = $data;
4818
5062
  // This is the first parameter of the generated arrow function.
4819
- $$: 1,
5063
+ $data: 1,
4820
5064
  // Null-safe toString: v => '' + (v == null ? '' : v)
4821
5065
  // Converts null/undefined to empty string, otherwise calls toString().
4822
5066
  // Wraps every {{!raw}} output to prevent "null" / "undefined" rendering.
4823
- $n: 1,
4824
- // HTML entity encoder: v => $n(v).replace(/[&<>"'`]/g, entityMap)
5067
+ $strSafe: 1,
5068
+ // HTML entity encoder: v => $strSafe(v).replace(/[&<>"'`]/g, entityMap)
4825
5069
  // Encodes &, <, >, ", ', ` to HTML entities (&amp; &lt; etc.)
4826
5070
  // Applied to all {{=escaped}} and {{:binding}} outputs.
4827
- $e: 1,
4828
- // HTML entity map — internal object used by $e:
5071
+ $encHtml: 1,
5072
+ // HTML entity map — internal object used by $encHtml:
4829
5073
  // {'&':'amp','<':'gt','>':'gt','"':'#34','\'':'#39','`':'#96'}
4830
- // Not a standalone function; referenced inside $e's closure.
4831
- $em: 1,
4832
- // HTML entity RegExp — internal regexp used by $e:
5074
+ // Not a standalone function; referenced inside $encHtml's closure.
5075
+ $entMap: 1,
5076
+ // HTML entity RegExp — internal regexp used by $encHtml:
4833
5077
  // /[&<>"'`]/g
4834
- $er: 1,
4835
- // HTML entity replacer function — internal helper used by $e:
4836
- // m => '&' + $em[m] + ';'
4837
- // Maps each matched character to its entity string.
4838
- $ef: 1,
5078
+ $entReg: 1,
5079
+ // HTML entity replacer function — internal helper used by $encHtml:
5080
+ // m => '&' + $entMap[m] + ';'
5081
+ // Maps matched character to its entity string.
5082
+ $entFn: 1,
4839
5083
  // Output buffer — the string accumulator for rendered HTML.
4840
- // All template output is appended via $p += '...'.
4841
- // Declared as: let $p = ''
4842
- $p: 1,
5084
+ // All template output is appended via $out += '...'.
5085
+ // Declared as: let $out = ''
5086
+ $out: 1,
4843
5087
  // Reference lookup: (refData, value) => key
4844
5088
  // Finds or allocates a SPLITTER-prefixed key in refData for a given
4845
5089
  // object reference. Used by {{@ref}} operator for passing object
4846
- // references to child views via lark-view attributes.
4847
- // Aligned with mx.js Updater_Ref.
4848
- $i: 1,
4849
- // URI encoder: v => encodeURIComponent($n(v)).replace(/[!')(*]/g, extraMap)
5090
+ // references to child views via v-lark attributes.
5091
+ $refFn: 1,
5092
+ // URI encoder: v => encodeURIComponent($strSafe(v)).replace(/[!')(*]/g, extraMap)
4850
5093
  // Extends encodeURIComponent with encoding of ! ' ( ) *.
4851
- // Applied to values in v-event URL parameters and {{!uri}} contexts.
4852
- $eu: 1,
4853
- // Quote encoder: v => $n(v).replace(/['"\\]/g, '\\$&')
5094
+ // Applied to values in @event URL parameters and {{!uri}} contexts.
5095
+ $encUri: 1,
5096
+ // URI encode map internal object used by $encUri:
5097
+ // {'!':'%21','\'':'%27','(':'%28',')':'%29','*':'%2A'}
5098
+ $uriMap: 1,
5099
+ // URI encode replacer — internal helper used by $encUri:
5100
+ // m => $uriMap[m]
5101
+ $uriFn: 1,
5102
+ // URI encode regexp — internal regexp used by $encUri:
5103
+ // /[!')(*]/g
5104
+ $uriReg: 1,
5105
+ // Quote encoder: v => $strSafe(v).replace(/['"\\]/g, '\\$&')
4854
5106
  // Escapes quotes and backslashes for safe embedding in HTML attribute
4855
5107
  // values (e.g. data-json='...').
4856
- $eq: 1,
5108
+ $encQuote: 1,
5109
+ // Quote encode regexp — internal regexp used by $encQuote:
5110
+ // /['"\\]/g
5111
+ $qReg: 1,
4857
5112
  // View ID — the unique identifier of the owning View instance.
4858
- // Injected into v-event attribute values at render time so that
5113
+ // Injected into @event attribute values at render time so that
4859
5114
  // EventDelegator can dispatch events to the correct View handler.
4860
5115
  // The \x1f placeholder in compiled output is replaced with '+$viewId+'.
4861
5116
  $viewId: 1,
4862
5117
  // Debug: current expression text — stores the template expression being
4863
5118
  // evaluated, for error reporting. Only present in debug mode.
4864
- // e.g. $expr='<%=user.name%>'
4865
- $expr: 1,
5119
+ // e.g. $dbgExpr='<%=user.name%>'
5120
+ $dbgExpr: 1,
4866
5121
  // Debug: original art syntax — stores the {{}} template syntax before
4867
5122
  // conversion, for error reporting. Only present in debug mode.
4868
- // e.g. $art='{{=user.name}}'
4869
- $art: 1,
5123
+ // e.g. $dbgArt='{{=user.name}}'
5124
+ $dbgArt: 1,
4870
5125
  // Debug: source line number — tracks the current line in the template
4871
5126
  // source, for error reporting. Only present in debug mode.
4872
- $line: 1,
4873
- // refData alias — fallback reference lookup table.
4874
- // Defaults to $$ when no explicit $$ref is provided.
4875
- // Ensures $i() does not crash when @ operator is used without refData.
4876
- $$ref: 1,
5127
+ $dbgLine: 1,
5128
+ // RefData alias — fallback reference lookup table.
5129
+ // Defaults to $data when no explicit $refAlt is provided.
5130
+ // Ensures $refFn() does not crash when @ operator is used without refData.
5131
+ $refAlt: 1,
4877
5132
  // Temporary variable — used by the compiler for intermediate
4878
5133
  // expression results in generated code (e.g. loop variables,
4879
- // conditional branches). Declared as: let $_temp
4880
- $_temp: 1,
5134
+ // conditional branches). Declared as: let $tmp
5135
+ $tmp: 1,
4881
5136
  // JS literals
4882
5137
  undefined: 1,
4883
5138
  null: 1,
@@ -4942,7 +5197,6 @@ var BUILTIN_GLOBALS = {
4942
5197
  };
4943
5198
  var BUILTIN_GLOBAL_SET = new Set(Object.keys(BUILTIN_GLOBALS));
4944
5199
  export {
4945
- Bag,
4946
5200
  CALL_BREAK_TIME,
4947
5201
  Cache,
4948
5202
  EVENT_METHOD_REGEXP,
@@ -4951,16 +5205,14 @@ export {
4951
5205
  Frame,
4952
5206
  Framework,
4953
5207
  LARK_VIEW,
5208
+ Payload,
4954
5209
  Platform,
4955
5210
  ROUTER_EVENTS,
4956
5211
  Router,
4957
5212
  SPLITTER,
4958
5213
  Service,
4959
5214
  State,
4960
- TAG_ATTR_KEY,
4961
- TAG_KEY,
4962
5215
  TAG_NAME_REGEXP,
4963
- TAG_VIEW_KEY,
4964
5216
  Updater,
4965
5217
  VIEW_EVENT_METHOD_REGEXP,
4966
5218
  View,
@@ -4991,7 +5243,7 @@ export {
4991
5243
  getStore,
4992
5244
  getUseStore,
4993
5245
  has,
4994
- isArray,
5246
+ installFrameVisualizerBridge,
4995
5247
  isPlainObject,
4996
5248
  isPrimitive,
4997
5249
  isPrimitiveOrFunc,
@@ -5011,6 +5263,7 @@ export {
5011
5263
  parseUri,
5012
5264
  registerViewClass,
5013
5265
  safeguard,
5266
+ serializeFrameTree,
5014
5267
  setData,
5015
5268
  shallowSet,
5016
5269
  mark2 as storeMark,