@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.cjs CHANGED
@@ -20,7 +20,6 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
- Bag: () => Bag,
24
23
  CALL_BREAK_TIME: () => CALL_BREAK_TIME,
25
24
  Cache: () => Cache,
26
25
  EVENT_METHOD_REGEXP: () => EVENT_METHOD_REGEXP,
@@ -29,16 +28,14 @@ __export(index_exports, {
29
28
  Frame: () => Frame,
30
29
  Framework: () => Framework,
31
30
  LARK_VIEW: () => LARK_VIEW,
31
+ Payload: () => Payload,
32
32
  Platform: () => Platform,
33
33
  ROUTER_EVENTS: () => ROUTER_EVENTS,
34
34
  Router: () => Router,
35
35
  SPLITTER: () => SPLITTER,
36
36
  Service: () => Service,
37
37
  State: () => State,
38
- TAG_ATTR_KEY: () => TAG_ATTR_KEY,
39
- TAG_KEY: () => TAG_KEY,
40
38
  TAG_NAME_REGEXP: () => TAG_NAME_REGEXP,
41
- TAG_VIEW_KEY: () => TAG_VIEW_KEY,
42
39
  Updater: () => Updater,
43
40
  VIEW_EVENT_METHOD_REGEXP: () => VIEW_EVENT_METHOD_REGEXP,
44
41
  View: () => View,
@@ -69,7 +66,7 @@ __export(index_exports, {
69
66
  getStore: () => getStore,
70
67
  getUseStore: () => getUseStore,
71
68
  has: () => has,
72
- isArray: () => isArray,
69
+ installFrameVisualizerBridge: () => installFrameVisualizerBridge,
73
70
  isPlainObject: () => isPlainObject,
74
71
  isPrimitive: () => isPrimitive,
75
72
  isPrimitiveOrFunc: () => isPrimitiveOrFunc,
@@ -89,6 +86,7 @@ __export(index_exports, {
89
86
  parseUri: () => parseUri,
90
87
  registerViewClass: () => registerViewClass,
91
88
  safeguard: () => safeguard,
89
+ serializeFrameTree: () => serializeFrameTree,
92
90
  setData: () => setData,
93
91
  shallowSet: () => shallowSet,
94
92
  storeMark: () => mark2,
@@ -116,10 +114,15 @@ var ROUTER_EVENTS = {
116
114
  CHANGED: "changed",
117
115
  PAGE_UNLOAD: "page_unload"
118
116
  };
119
- var TAG_KEY = "lark-key";
120
- var TAG_ATTR_KEY = "lark-attr-key";
121
- var TAG_VIEW_KEY = "lark-view-key";
122
- var LARK_VIEW = "lark-view";
117
+ var LARK_KEYS = {
118
+ /** Attribute name: ldk (static key for skipping VDOM diff) */
119
+ DIFF_KEY: "ldk",
120
+ /** Attribute name: lak (static attribute key) */
121
+ ATTR_KEY: "lak",
122
+ /** Attribute name: lvk (view key for assign) */
123
+ VIEW_KEY: "lvk"
124
+ };
125
+ var LARK_VIEW = "v-lark";
123
126
  var EVENT_METHOD_REGEXP = new RegExp(
124
127
  `(?:([\\w-]+)${SPLITTER})?([^(]+)\\(([\\s\\S]*?)?\\)`
125
128
  );
@@ -143,7 +146,6 @@ function isPlainObject(value) {
143
146
  if (proto === null) return true;
144
147
  return proto === Object.prototype || proto === null;
145
148
  }
146
- var isArray = Array.isArray;
147
149
  function isPrimitiveOrFunc(value) {
148
150
  return !value || typeof value !== "object" && typeof value !== "function";
149
151
  }
@@ -184,13 +186,13 @@ function assign(target, ...sources) {
184
186
  return target;
185
187
  }
186
188
  function funcWithTry(fns, args, context, configError) {
187
- const fnArray = isArray(fns) ? fns : [fns];
189
+ const fnArray = Array.isArray(fns) ? fns : [fns];
188
190
  let ret;
189
191
  for (const fn of fnArray) {
190
192
  try {
191
193
  ret = Function.prototype.apply.call(fn, context, args);
192
194
  } catch (e) {
193
- configError(e);
195
+ configError?.(e);
194
196
  }
195
197
  }
196
198
  return ret;
@@ -218,7 +220,7 @@ function translateData(data, value) {
218
220
  }
219
221
  return value;
220
222
  }
221
- if (isPlainObject(value) || isArray(value)) {
223
+ if (isPlainObject(value) || Array.isArray(value)) {
222
224
  for (const p in value) {
223
225
  if (has(value, p)) {
224
226
  const val = value[p];
@@ -311,13 +313,13 @@ function toMap(list, key) {
311
313
  function now() {
312
314
  return Date.now ? Date.now() : (/* @__PURE__ */ new Date()).getTime();
313
315
  }
314
- function classExtend(ctor, base, props, statics) {
316
+ function classExtend(make, base, props, statics) {
315
317
  const baseProto = base["prototype"] ?? {};
316
- const cProto = Object.create(baseProto);
317
- assign(cProto, props);
318
- Object.assign(ctor, statics);
319
- cProto.constructor = ctor;
320
- ctor["prototype"] = cProto;
318
+ const classProto = Object.create(baseProto);
319
+ assign(classProto, props);
320
+ Object.assign(make, statics);
321
+ classProto.constructor = make;
322
+ make["prototype"] = classProto;
321
323
  }
322
324
 
323
325
  // src/apply-style.ts
@@ -358,8 +360,8 @@ function applyStyle(styleIdOrPairs, css) {
358
360
  }
359
361
 
360
362
  // src/mark.ts
361
- var DELETED_KEY = SPLITTER + "$a";
362
- var MARK_OBJECT_KEY = SPLITTER + "$b";
363
+ var DELETED_KEY = SPLITTER + "$delFlag";
364
+ var MARK_OBJECT_KEY = SPLITTER + "$markKey";
363
365
  function mark(host, key) {
364
366
  let sign = 0;
365
367
  const hostRecord = host;
@@ -383,9 +385,9 @@ function unmark(host) {
383
385
 
384
386
  // src/safeguard.ts
385
387
  var proxiesPool = /* @__PURE__ */ new Map();
386
- var SAFEGUARD_SENTINEL = "_sf_";
388
+ var SAFEGUARD_SENTINEL = "_safe_";
387
389
  function safeguard(data, getter, setter, isRoot) {
388
- if (typeof window.__lark_debug === "undefined" || !window.__lark_debug) {
390
+ if (typeof window.__lark_Debug === "undefined" || !window.__lark_Debug) {
389
391
  return data;
390
392
  }
391
393
  if (typeof Proxy === "undefined") {
@@ -424,7 +426,7 @@ function safeguard(data, getter, setter, isRoot) {
424
426
  if (!prefix && getter) {
425
427
  getter(property);
426
428
  }
427
- if (!isRoot && has(target, property) && (isArray(out) || isPlainObject(out))) {
429
+ if (!isRoot && has(target, property) && (Array.isArray(out) || isPlainObject(out))) {
428
430
  return build(prefix + property + ".", out);
429
431
  }
430
432
  return out;
@@ -599,7 +601,10 @@ var EventEmitter = class {
599
601
  }
600
602
  } else {
601
603
  this.listeners.delete(key);
602
- Reflect.deleteProperty(this, `on${event}`);
604
+ Reflect.deleteProperty(
605
+ this,
606
+ `on${event[0].toUpperCase() + event.slice(1)}`
607
+ );
603
608
  }
604
609
  return this;
605
610
  }
@@ -640,7 +645,7 @@ var EventEmitter = class {
640
645
  }
641
646
  }
642
647
  }
643
- const onMethodName = `on${event}`;
648
+ const onMethodName = `on${event[0].toUpperCase() + event.slice(1)}`;
644
649
  const onMethod = this[onMethodName];
645
650
  if (typeof onMethod === "function") {
646
651
  funcWithTry(
@@ -687,7 +692,7 @@ function teardownKeysRef(keyList) {
687
692
  if (count <= 0) {
688
693
  Reflect.deleteProperty(keyRefCounts, key);
689
694
  Reflect.deleteProperty(appData, key);
690
- if (typeof window.__lark_debug !== "undefined" && window.__lark_debug) {
695
+ if (typeof window.__lark_Debug !== "undefined" && window.__lark_Debug) {
691
696
  Reflect.deleteProperty(dataWhereSet, key);
692
697
  }
693
698
  }
@@ -730,7 +735,7 @@ var State = {
730
735
  */
731
736
  get(key) {
732
737
  const result = key ? appData[key] : appData;
733
- if (typeof window.__lark_debug !== "undefined" && window.__lark_debug) {
738
+ if (typeof window.__lark_Debug !== "undefined" && window.__lark_Debug) {
734
739
  return safeguard(
735
740
  result,
736
741
  (dataKey) => {
@@ -756,7 +761,7 @@ var State = {
756
761
  */
757
762
  set(data, excludes) {
758
763
  dataIsChanged = setData(data, appData, changedKeys, excludes || /* @__PURE__ */ new Set()) || dataIsChanged;
759
- if (typeof window.__lark_debug !== "undefined" && window.__lark_debug && booted) {
764
+ if (typeof window.__lark_Debug !== "undefined" && window.__lark_Debug && booted) {
760
765
  for (const p in data) {
761
766
  dataWhereSet[p] = window.location.pathname;
762
767
  }
@@ -771,7 +776,7 @@ var State = {
771
776
  State.set(data, excludes);
772
777
  }
773
778
  if (dataIsChanged) {
774
- if (typeof window.__lark_debug !== "undefined" && window.__lark_debug) {
779
+ if (typeof window.__lark_Debug !== "undefined" && window.__lark_Debug) {
775
780
  for (const p in changedKeys) {
776
781
  if (has(changedKeys, p)) {
777
782
  clearNotify(p);
@@ -802,7 +807,7 @@ var State = {
802
807
  */
803
808
  clean(keys2) {
804
809
  return {
805
- ctor: function() {
810
+ make: function() {
806
811
  const keyList = setupKeysRef(keys2);
807
812
  this.on("destroy", () => {
808
813
  teardownKeysRef(keyList);
@@ -831,6 +836,7 @@ var State = {
831
836
  emitter.fire(event, data, remove);
832
837
  return State;
833
838
  }
839
+ // onChanged: noop,
834
840
  };
835
841
 
836
842
  // src/router.ts
@@ -983,7 +989,7 @@ var Router = {
983
989
  attachViewAndPath(location);
984
990
  hrefCache.set(href, location);
985
991
  }
986
- if (typeof window.__lark_debug !== "undefined" && window.__lark_debug) {
992
+ if (typeof window.__lark_Debug !== "undefined" && window.__lark_Debug) {
987
993
  location["params"] = safeguard(location["params"]);
988
994
  }
989
995
  return location;
@@ -1007,7 +1013,7 @@ var Router = {
1007
1013
  );
1008
1014
  }
1009
1015
  silent = 0;
1010
- if (typeof window.__lark_debug !== "undefined" && window.__lark_debug && lastChanged) {
1016
+ if (typeof window.__lark_Debug !== "undefined" && window.__lark_Debug && lastChanged) {
1011
1017
  lastChanged = safeguard(lastChanged);
1012
1018
  }
1013
1019
  return lastChanged;
@@ -1136,9 +1142,9 @@ var Router = {
1136
1142
  window.addEventListener("hashchange", watchChange);
1137
1143
  window.addEventListener("popstate", watchChange);
1138
1144
  window.addEventListener("beforeunload", (domEvent) => {
1139
- const te = {};
1140
- Router.fire(ROUTER_EVENTS.PAGE_UNLOAD, te);
1141
- const msg = te["msg"];
1145
+ const data = {};
1146
+ Router.fire(ROUTER_EVENTS.PAGE_UNLOAD, data);
1147
+ const msg = data["msg"];
1142
1148
  if (msg) {
1143
1149
  domEvent.returnValue = msg;
1144
1150
  }
@@ -1170,26 +1176,26 @@ var frameGetter;
1170
1176
  function parseEventInfo(eventInfo) {
1171
1177
  const cached = eventInfoCache.get(eventInfo);
1172
1178
  if (cached) {
1173
- return assign({}, cached, { r: eventInfo });
1179
+ return assign({}, cached, { value: eventInfo });
1174
1180
  }
1175
1181
  const match = eventInfo.match(EVENT_METHOD_REGEXP) || [];
1176
1182
  const result = {
1177
- v: match[1] || "",
1178
- n: match[2] || "",
1179
- i: match[3] || ""
1183
+ id: match[1] || "",
1184
+ name: match[2] || "",
1185
+ params: match[3] || ""
1180
1186
  };
1181
1187
  eventInfoCache.set(eventInfo, result);
1182
- return assign({}, result, { r: eventInfo });
1188
+ return assign({}, result, { value: eventInfo });
1183
1189
  }
1184
1190
  function findFrameInfo(current, eventType) {
1185
1191
  const eventInfos = [];
1186
1192
  let begin = current;
1187
- const info = current.getAttribute(`v-${eventType}`);
1193
+ const info = current.getAttribute(`@${eventType}`);
1188
1194
  let match;
1189
1195
  if (info) {
1190
1196
  match = parseEventInfo(info);
1191
1197
  }
1192
- if (match && !match.v || selectorEvents[eventType]) {
1198
+ if (match && !match.id || selectorEvents[eventType]) {
1193
1199
  let selectorFrameId = "#";
1194
1200
  let backtrace = 0;
1195
1201
  while (begin && begin !== document.body) {
@@ -1215,10 +1221,10 @@ function findFrameInfo(current, eventType) {
1215
1221
  if (selectorEntry) {
1216
1222
  for (const selectorName of selectorEntry.selectors) {
1217
1223
  const entry = {
1218
- r: selectorName,
1219
- v: frameId,
1220
- n: selectorName,
1221
- i: ""
1224
+ value: selectorName,
1225
+ id: frameId,
1226
+ name: selectorName,
1227
+ params: ""
1222
1228
  };
1223
1229
  if (selectorName) {
1224
1230
  if (!backtrace && elementMatchesSelector(current, selectorName)) {
@@ -1230,8 +1236,8 @@ function findFrameInfo(current, eventType) {
1230
1236
  }
1231
1237
  }
1232
1238
  if (view.template && !backtrace) {
1233
- if (match && !match.v) {
1234
- match.v = frameId;
1239
+ if (match && !match.id) {
1240
+ match.id = frameId;
1235
1241
  }
1236
1242
  break;
1237
1243
  }
@@ -1247,10 +1253,10 @@ function findFrameInfo(current, eventType) {
1247
1253
  }
1248
1254
  if (match) {
1249
1255
  eventInfos.push({
1250
- v: match.v,
1251
- r: match.r,
1252
- n: match.n,
1253
- i: match.i
1256
+ id: match.id,
1257
+ value: match.value,
1258
+ name: match.name,
1259
+ params: match.params
1254
1260
  });
1255
1261
  }
1256
1262
  return eventInfos;
@@ -1271,7 +1277,7 @@ function domEventProcessor(domEvent) {
1271
1277
  const eventInfos = findFrameInfo(current, eventType);
1272
1278
  if (eventInfos.length) {
1273
1279
  for (const info of eventInfos) {
1274
- const { v: frameId, n: handlerName, i: params } = info;
1280
+ const { id: frameId, name: handlerName, params } = info;
1275
1281
  if (lastFrameId !== frameId) {
1276
1282
  if (lastFrameId && domEvent.isPropagationStopped?.()) {
1277
1283
  break;
@@ -1370,8 +1376,8 @@ var WrapMeta = {
1370
1376
  td: [3, "<table><tbody><tr>"],
1371
1377
  area: [1, "<map>"],
1372
1378
  param: [1, "<object>"],
1373
- g: [1, '<svg xmlns="' + SVG_NS + '">'],
1374
- m: [1, '<math xmlns="' + MATH_NS + '">'],
1379
+ svg: [1, '<svg xmlns="' + SVG_NS + '">'],
1380
+ math: [1, '<math xmlns="' + MATH_NS + '">'],
1375
1381
  _: [0, ""]
1376
1382
  };
1377
1383
  WrapMeta["optgroup"] = WrapMeta["option"];
@@ -1404,9 +1410,9 @@ function vdomGetNode(html, refNode) {
1404
1410
  const ns = refNode.namespaceURI;
1405
1411
  let tag;
1406
1412
  if (ns === SVG_NS) {
1407
- tag = "g";
1413
+ tag = "svg";
1408
1414
  } else if (ns === MATH_NS) {
1409
- tag = "m";
1415
+ tag = "math";
1410
1416
  } else {
1411
1417
  const match = TAG_NAME_REGEXP.exec(html);
1412
1418
  tag = match ? match[1] : "";
@@ -1428,7 +1434,7 @@ function vdomGetCompareKey(node) {
1428
1434
  }
1429
1435
  let key = el.autoId ? "" : el.getAttribute("id") || void 0;
1430
1436
  if (!key) {
1431
- key = el.getAttribute(TAG_KEY) || void 0;
1437
+ key = el.getAttribute(LARK_KEYS.DIFF_KEY) || void 0;
1432
1438
  }
1433
1439
  if (!key) {
1434
1440
  const larkView = el.getAttribute(LARK_VIEW);
@@ -1556,17 +1562,17 @@ function vdomSetChildNodes(oldParent, newParent, ref, frame, keys_) {
1556
1562
  }
1557
1563
  }
1558
1564
  function vdomSetNode(oldNode, newNode, oldParent, ref, frame, keys_) {
1559
- if (vdomSpecialDiff(oldNode, newNode) || oldNode.nodeType === 1 && oldNode.hasAttribute(TAG_VIEW_KEY) || !(oldNode.isEqualNode && oldNode.isEqualNode(newNode))) {
1565
+ if (vdomSpecialDiff(oldNode, newNode) || oldNode.nodeType === 1 && oldNode.hasAttribute(LARK_KEYS.VIEW_KEY) || !(oldNode.isEqualNode && oldNode.isEqualNode(newNode))) {
1560
1566
  if (oldNode.nodeType === newNode.nodeType && oldNode.nodeName === newNode.nodeName) {
1561
1567
  if (oldNode.nodeType === 1) {
1562
1568
  const oldEl = oldNode;
1563
1569
  const newEl = newNode;
1564
- const staticKey = newEl.getAttribute(TAG_KEY);
1565
- if (staticKey && staticKey === oldEl.getAttribute(TAG_KEY)) {
1570
+ const staticKey = newEl.getAttribute(LARK_KEYS.DIFF_KEY);
1571
+ if (staticKey && staticKey === oldEl.getAttribute(LARK_KEYS.DIFF_KEY)) {
1566
1572
  return;
1567
1573
  }
1568
1574
  const newLarkView = newEl.getAttribute(LARK_VIEW);
1569
- const updateAttribute = !newEl.getAttribute(TAG_ATTR_KEY) || newEl.getAttribute(TAG_ATTR_KEY) !== oldEl.getAttribute(TAG_ATTR_KEY);
1575
+ const updateAttribute = !newEl.getAttribute(LARK_KEYS.ATTR_KEY) || newEl.getAttribute(LARK_KEYS.ATTR_KEY) !== oldEl.getAttribute(LARK_KEYS.ATTR_KEY);
1570
1576
  let updateChildren = true;
1571
1577
  if (newLarkView) {
1572
1578
  const oldFrameId = oldEl.getAttribute("id") || "";
@@ -1711,7 +1717,7 @@ var Updater = class {
1711
1717
  if (key) {
1712
1718
  result = this.data[key];
1713
1719
  }
1714
- if (typeof window !== "undefined" && window.__lark_debug) {
1720
+ if (typeof window !== "undefined" && window.__lark_Debug) {
1715
1721
  return safeguard(result);
1716
1722
  }
1717
1723
  return result;
@@ -1846,225 +1852,10 @@ var Updater = class {
1846
1852
  // src/view.ts
1847
1853
  var VIEW_GLOBALS = {};
1848
1854
  if (typeof window !== "undefined") {
1849
- VIEW_GLOBALS["win"] = window;
1855
+ VIEW_GLOBALS["window"] = window;
1850
1856
  }
1851
1857
  if (typeof document !== "undefined") {
1852
- VIEW_GLOBALS["doc"] = document;
1853
- }
1854
- function viewPrepare(oView) {
1855
- if (oView.ctors) {
1856
- return oView.ctors;
1857
- }
1858
- const ctors = [];
1859
- oView.ctors = ctors;
1860
- const proto = oView.prototype;
1861
- const eventsObject = {};
1862
- const eventsList = [];
1863
- const selectorObject = {};
1864
- const mixins = proto["mixins"];
1865
- if (mixins && Array.isArray(mixins)) {
1866
- viewMergeMixins(mixins, oView, ctors);
1867
- }
1868
- for (const p in proto) {
1869
- if (!has(proto, p)) continue;
1870
- const currentFn = proto[p];
1871
- if (typeof currentFn !== "function") continue;
1872
- const matches = p.match(VIEW_EVENT_METHOD_REGEXP);
1873
- if (!matches) continue;
1874
- const isSelector = matches[1];
1875
- const selectorOrCallback = matches[2];
1876
- const events = matches[3];
1877
- const modifiers = matches[4];
1878
- const mod = {};
1879
- if (modifiers) {
1880
- for (const item of modifiers.split(",")) {
1881
- mod[item] = true;
1882
- }
1883
- }
1884
- const eventTypes = events.split(",");
1885
- for (const item of eventTypes) {
1886
- const globalNode = VIEW_GLOBALS[selectorOrCallback];
1887
- let mask = 1;
1888
- if (isSelector) {
1889
- if (globalNode) {
1890
- eventsList.push({
1891
- handler: currentFn,
1892
- element: globalNode,
1893
- eventName: item,
1894
- modifiers: mod
1895
- });
1896
- continue;
1897
- }
1898
- mask = 2;
1899
- let selectorEntry = selectorObject[item];
1900
- if (!selectorEntry) {
1901
- selectorEntry = selectorObject[item] = {
1902
- selectors: []
1903
- };
1904
- }
1905
- if (!selectorEntry[selectorOrCallback]) {
1906
- selectorEntry[selectorOrCallback] = 1;
1907
- selectorEntry.selectors.push(selectorOrCallback);
1908
- }
1909
- }
1910
- eventsObject[item] = (eventsObject[item] || 0) | mask;
1911
- const combinedKey = selectorOrCallback + SPLITTER + item;
1912
- const existingFn = proto[combinedKey];
1913
- if (!existingFn) {
1914
- proto[combinedKey] = currentFn;
1915
- } else {
1916
- const mixinFn = currentFn;
1917
- const existingMixin = existingFn;
1918
- if (existingMixin.b) {
1919
- if (mixinFn.b) {
1920
- proto[combinedKey] = processMixinsSameEvent(
1921
- currentFn,
1922
- existingFn
1923
- );
1924
- } else if (has(proto, p)) {
1925
- proto[combinedKey] = currentFn;
1926
- }
1927
- }
1928
- }
1929
- }
1930
- }
1931
- viewWrapMethod(proto, "render", "$b");
1932
- proto["$eo"] = eventsObject;
1933
- proto["$el"] = eventsList;
1934
- proto["$so"] = selectorObject;
1935
- proto["$f"] = proto["assign"];
1936
- return ctors;
1937
- }
1938
- function viewWrapMethod(proto, fnName, shortKey) {
1939
- const originalFn = proto[fnName];
1940
- if (typeof originalFn !== "function") return;
1941
- const wrapped = function(...args) {
1942
- if (this.signature > 0) {
1943
- this.signature++;
1944
- this.fire("rendercall");
1945
- destroyAllResources(this, false);
1946
- const instanceFn = typeof this[fnName] === "function" ? this[fnName] : originalFn;
1947
- const fnToCall = instanceFn === wrapped ? originalFn : instanceFn;
1948
- return funcWithTry(fnToCall, args, this, noop);
1949
- }
1950
- return void 0;
1951
- };
1952
- proto[fnName] = wrapped;
1953
- proto[shortKey] = wrapped;
1954
- }
1955
- function processMixinsSameEvent(additional, exist) {
1956
- let temp;
1957
- const existMixin = exist;
1958
- if (existMixin.a) {
1959
- temp = existMixin;
1960
- } else {
1961
- temp = function(...e) {
1962
- funcWithTry(temp.a ?? [], e, this, noop);
1963
- };
1964
- temp.a = [exist];
1965
- temp.b = 1;
1966
- }
1967
- const additionalMixin = additional;
1968
- temp.a = (temp.a ?? []).concat(additionalMixin.a ?? [additional]);
1969
- return temp;
1970
- }
1971
- function viewMergeMixins(mixins, viewClass, ctors) {
1972
- const proto = viewClass.prototype;
1973
- const temp = {};
1974
- for (const node of mixins) {
1975
- for (const p in node) {
1976
- if (!has(node, p)) continue;
1977
- const fn = node[p];
1978
- const exist = temp[p];
1979
- if (p === "ctor") {
1980
- ctors.push(fn);
1981
- continue;
1982
- }
1983
- if (VIEW_EVENT_METHOD_REGEXP.test(p)) {
1984
- if (exist) {
1985
- temp[p] = processMixinsSameEvent(fn, exist);
1986
- } else {
1987
- fn.b = 1;
1988
- temp[p] = fn;
1989
- }
1990
- } else {
1991
- if (!exist) {
1992
- temp[p] = fn;
1993
- }
1994
- }
1995
- }
1996
- }
1997
- for (const p in temp) {
1998
- if (!has(proto, p)) {
1999
- proto[p] = temp[p];
2000
- }
2001
- }
2002
- }
2003
- function viewDelegateEvents(view, destroy = false) {
2004
- const proto = Object.getPrototypeOf(view) ?? {};
2005
- const eventsObject = proto["$eo"] || view.eventObjectMap;
2006
- const selectorObject = proto["$so"] || view.eventSelectorMap;
2007
- const eventsList = proto["$el"] || view.globalEventList;
2008
- for (const e in eventsObject) {
2009
- if (has(eventsObject, e)) {
2010
- if (destroy) {
2011
- EventDelegator.unbind(e, !!selectorObject[e]);
2012
- } else {
2013
- EventDelegator.bind(e, !!selectorObject[e]);
2014
- }
2015
- }
2016
- }
2017
- for (const entry of eventsList) {
2018
- if (destroy) {
2019
- entry.element.removeEventListener(
2020
- entry.eventName,
2021
- entry.boundHandler
2022
- );
2023
- } else {
2024
- const handler = entry.handler;
2025
- const element = entry.element;
2026
- const modifiers = entry.modifiers;
2027
- entry.boundHandler = function(domEvent) {
2028
- const extendedEvent = domEvent;
2029
- extendedEvent.eventTarget = element;
2030
- if (modifiers) {
2031
- const kbEvent = domEvent;
2032
- if (modifiers["ctrl"] && !kbEvent.ctrlKey || modifiers["shift"] && !kbEvent.shiftKey || modifiers["alt"] && !kbEvent.altKey || modifiers["meta"] && !kbEvent.metaKey) {
2033
- return;
2034
- }
2035
- }
2036
- funcWithTry(handler, [domEvent], view, noop);
2037
- };
2038
- entry.element.addEventListener(
2039
- entry.eventName,
2040
- entry.boundHandler
2041
- );
2042
- }
2043
- }
2044
- }
2045
- function destroyAllResources(view, lastly) {
2046
- const cache = view.resources;
2047
- for (const p in cache) {
2048
- if (has(cache, p)) {
2049
- const entry = cache[p];
2050
- if (lastly || entry.destroyOnRender) {
2051
- destroyResource(cache, p, true);
2052
- }
2053
- }
2054
- }
2055
- }
2056
- function destroyResource(cache, key, callDestroy, oldEntity) {
2057
- const entry = cache[key];
2058
- if (!entry || entry.entity === oldEntity) return void 0;
2059
- const entity = entry.entity;
2060
- if (entity && typeof entity === "object") {
2061
- const destroyFn = entity["destroy"];
2062
- if (typeof destroyFn === "function" && callDestroy) {
2063
- funcWithTry(destroyFn, [], entity, noop);
2064
- }
2065
- }
2066
- Reflect.deleteProperty(cache, key);
2067
- return entity;
1858
+ VIEW_GLOBALS["document"] = document;
2068
1859
  }
2069
1860
  var View = class _View {
2070
1861
  /** View ID (same as owner frame ID) */
@@ -2089,18 +1880,43 @@ var View = class _View {
2089
1880
  observedStateKeys;
2090
1881
  /** Resource map */
2091
1882
  resources = {};
2092
- /** Selector event map: eventType -> handler name list */
2093
- eventSelectorMap = {};
2094
- /** Event object map: eventType -> bitmask */
2095
- eventObjectMap = {};
2096
- /** Global event list */
2097
- globalEventList = [];
2098
1883
  /** Assign method reference */
2099
1884
  assignMethod;
2100
1885
  /** Whether endUpdate pending */
2101
1886
  endUpdatePending;
2102
1887
  /** Internal event storage */
2103
1888
  _events = new EventEmitter();
1889
+ // ============================================================
1890
+ // Getters for prototype-stored event maps
1891
+ // ============================================================
1892
+ /**
1893
+ * Event bitmask map: eventType -> bitmask (1=root, 2=selector).
1894
+ * Read from prototype ($evtObjMap) set by View.prepare.
1895
+ * Using a getter avoids ES6 class field shadowing the prototype value.
1896
+ */
1897
+ get eventObjectMap() {
1898
+ const proto = Object.getPrototypeOf(this);
1899
+ return proto["$evtObjMap"] || {};
1900
+ }
1901
+ /**
1902
+ * Selector event map: eventType -> selector list.
1903
+ * Read from prototype ($selMap) set by View.prepare.
1904
+ */
1905
+ get eventSelectorMap() {
1906
+ const proto = Object.getPrototypeOf(this);
1907
+ return proto["$selMap"] || {};
1908
+ }
1909
+ /**
1910
+ * Global event list: [{handler, element, eventName, modifiers}].
1911
+ * Read from prototype ($globalEvtList) set by View.prepare.
1912
+ */
1913
+ get globalEventList() {
1914
+ const proto = Object.getPrototypeOf(this);
1915
+ return proto["$globalEvtList"] || [];
1916
+ }
1917
+ // ============================================================
1918
+ // Instance lifecycle methods
1919
+ // ============================================================
2104
1920
  /**
2105
1921
  * Initialize view (called by Frame when mounting).
2106
1922
  */
@@ -2108,14 +1924,7 @@ var View = class _View {
2108
1924
  }
2109
1925
  /**
2110
1926
  * Render view template (called by Frame after init).
2111
- * Wrapped by View_WrapMethod to manage signature + resources.
2112
- *
2113
- * Default implementation calls updater.digest() which:
2114
- * 1. Executes the template function with current data
2115
- * 2. Runs VDOM diff against previous DOM
2116
- * 3. Applies DOM operations
2117
- * 4. Calls endUpdate to mount child frames
2118
- *
1927
+ * Wrapped by View.wrapMethod to manage signature + resources.
2119
1928
  */
2120
1929
  render() {
2121
1930
  this.updater.digest();
@@ -2167,7 +1976,7 @@ var View = class _View {
2167
1976
  if (!flag) {
2168
1977
  setTimeout(
2169
1978
  this.wrapAsync(() => {
2170
- runInvokes(ownerFrame);
1979
+ _View.runInvokes(ownerFrame);
2171
1980
  }),
2172
1981
  0
2173
1982
  );
@@ -2243,7 +2052,7 @@ var View = class _View {
2243
2052
  capture(key, resource, destroyOnRender = false) {
2244
2053
  const cache = this.resources;
2245
2054
  if (resource) {
2246
- destroyResource(cache, key, true, resource);
2055
+ _View.destroyResource(cache, key, true, resource);
2247
2056
  cache[key] = {
2248
2057
  entity: resource,
2249
2058
  destroyOnRender
@@ -2259,7 +2068,7 @@ var View = class _View {
2259
2068
  * If destroy=true, calls the resource's destroy() method.
2260
2069
  */
2261
2070
  release(key, destroy = true) {
2262
- return destroyResource(this.resources, key, destroy);
2071
+ return _View.destroyResource(this.resources, key, destroy);
2263
2072
  }
2264
2073
  // ============================================================
2265
2074
  // Leave tip
@@ -2305,31 +2114,294 @@ var View = class _View {
2305
2114
  });
2306
2115
  }
2307
2116
  // ============================================================
2308
- // Static: extend and merge
2117
+ // Static public methods
2309
2118
  // ============================================================
2310
2119
  /** Collected ctors from mixins */
2311
2120
  static ctors;
2121
+ /**
2122
+ * Prepare a View subclass by scanning its prototype for event method patterns.
2123
+ * Pattern: `$?name<eventType1,eventType2>(&modifiers)`
2124
+ *
2125
+ * Only runs once per View subclass (guarded by ctors marker).
2126
+ * Called from Frame.mountView before creating the view instance.
2127
+ */
2128
+ static prepare(oView) {
2129
+ if (oView.ctors) {
2130
+ return oView.ctors;
2131
+ }
2132
+ const ctors = [];
2133
+ oView.ctors = ctors;
2134
+ const proto = oView.prototype;
2135
+ const eventsObject = {};
2136
+ const eventsList = [];
2137
+ const selectorObject = {};
2138
+ const mixins = proto["mixins"];
2139
+ if (mixins && Array.isArray(mixins)) {
2140
+ _View.mergeMixins(mixins, oView, ctors);
2141
+ }
2142
+ for (const p in proto) {
2143
+ if (!has(proto, p)) continue;
2144
+ const currentFn = proto[p];
2145
+ if (typeof currentFn !== "function") continue;
2146
+ const matches = p.match(VIEW_EVENT_METHOD_REGEXP);
2147
+ if (!matches) continue;
2148
+ const isSelector = matches[1];
2149
+ const selectorOrCallback = matches[2];
2150
+ const events = matches[3];
2151
+ const modifiers = matches[4];
2152
+ const mod = {};
2153
+ if (modifiers) {
2154
+ for (const item of modifiers.split(",")) {
2155
+ mod[item] = true;
2156
+ }
2157
+ }
2158
+ const eventTypes = events.split(",");
2159
+ for (const item of eventTypes) {
2160
+ const globalNode = VIEW_GLOBALS[selectorOrCallback];
2161
+ let mask = 1;
2162
+ if (isSelector) {
2163
+ if (globalNode) {
2164
+ eventsList.push({
2165
+ handler: currentFn,
2166
+ element: globalNode,
2167
+ eventName: item,
2168
+ modifiers: mod
2169
+ });
2170
+ continue;
2171
+ }
2172
+ mask = 2;
2173
+ let selectorEntry = selectorObject[item];
2174
+ if (!selectorEntry) {
2175
+ selectorEntry = selectorObject[item] = {
2176
+ selectors: []
2177
+ };
2178
+ }
2179
+ if (!selectorEntry[selectorOrCallback]) {
2180
+ selectorEntry[selectorOrCallback] = 1;
2181
+ selectorEntry.selectors.push(selectorOrCallback);
2182
+ }
2183
+ }
2184
+ eventsObject[item] = (eventsObject[item] || 0) | mask;
2185
+ const combinedKey = selectorOrCallback + SPLITTER + item;
2186
+ const existingFn = proto[combinedKey];
2187
+ if (!existingFn) {
2188
+ proto[combinedKey] = currentFn;
2189
+ } else {
2190
+ const mixinFn = currentFn;
2191
+ const existingMixin = existingFn;
2192
+ if (existingMixin.marker) {
2193
+ if (mixinFn.marker) {
2194
+ proto[combinedKey] = _View.processMixinsSameEvent(
2195
+ currentFn,
2196
+ existingFn
2197
+ );
2198
+ } else if (has(proto, p)) {
2199
+ proto[combinedKey] = currentFn;
2200
+ }
2201
+ }
2202
+ }
2203
+ }
2204
+ }
2205
+ _View.wrapMethod(proto, "render", "$renderWrap");
2206
+ proto["$evtObjMap"] = eventsObject;
2207
+ proto["$globalEvtList"] = eventsList;
2208
+ proto["$selMap"] = selectorObject;
2209
+ proto["$assignFn"] = proto["assign"];
2210
+ return ctors;
2211
+ }
2212
+ /**
2213
+ * Bind or unbind event delegation for a view instance.
2214
+ * Called from Frame during mount/unmount.
2215
+ */
2216
+ static delegateEvents(view, destroy = false) {
2217
+ const eventsObject = view.eventObjectMap;
2218
+ const selectorObject = view.eventSelectorMap;
2219
+ const eventsList = view.globalEventList;
2220
+ for (const e in eventsObject) {
2221
+ if (has(eventsObject, e)) {
2222
+ if (destroy) {
2223
+ EventDelegator.unbind(e, !!selectorObject[e]);
2224
+ } else {
2225
+ EventDelegator.bind(e, !!selectorObject[e]);
2226
+ }
2227
+ }
2228
+ }
2229
+ for (const entry of eventsList) {
2230
+ if (destroy) {
2231
+ entry.element.removeEventListener(
2232
+ entry.eventName,
2233
+ entry.boundHandler
2234
+ );
2235
+ } else {
2236
+ const handler = entry.handler;
2237
+ const element = entry.element;
2238
+ const modifiers = entry.modifiers;
2239
+ entry.boundHandler = function(domEvent) {
2240
+ const extendedEvent = domEvent;
2241
+ extendedEvent.eventTarget = element;
2242
+ if (modifiers) {
2243
+ const kbEvent = domEvent;
2244
+ if (modifiers["ctrl"] && !kbEvent.ctrlKey || modifiers["shift"] && !kbEvent.shiftKey || modifiers["alt"] && !kbEvent.altKey || modifiers["meta"] && !kbEvent.metaKey) {
2245
+ return;
2246
+ }
2247
+ }
2248
+ funcWithTry(handler, [domEvent], view, noop);
2249
+ };
2250
+ entry.element.addEventListener(
2251
+ entry.eventName,
2252
+ entry.boundHandler
2253
+ );
2254
+ }
2255
+ }
2256
+ }
2257
+ /**
2258
+ * Destroy all resources managed by a view.
2259
+ * If lastly=true, destroy ALL resources; otherwise only destroyOnRender ones.
2260
+ */
2261
+ static destroyAllResources(view, lastly) {
2262
+ const cache = view.resources;
2263
+ for (const p in cache) {
2264
+ if (has(cache, p)) {
2265
+ const entry = cache[p];
2266
+ if (lastly || entry.destroyOnRender) {
2267
+ _View.destroyResource(cache, p, true);
2268
+ }
2269
+ }
2270
+ }
2271
+ }
2272
+ /**
2273
+ * Process deferred invoke calls on a frame.
2274
+ */
2275
+ static 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
+ // ============================================================
2286
+ // Static private methods
2287
+ // ============================================================
2288
+ /**
2289
+ * Wrap a method on the prototype to add signature checking and resource cleanup.
2290
+ */
2291
+ static wrapMethod(proto, fnName, shortKey) {
2292
+ const originalFn = proto[fnName];
2293
+ if (typeof originalFn !== "function") return;
2294
+ const wrapped = function(...args) {
2295
+ if (this.signature > 0) {
2296
+ this.signature++;
2297
+ this.fire("render");
2298
+ _View.destroyAllResources(this, false);
2299
+ const instanceFn = typeof this[fnName] === "function" ? this[fnName] : originalFn;
2300
+ const fnToCall = instanceFn === wrapped ? originalFn : instanceFn;
2301
+ return funcWithTry(fnToCall, args, this, noop);
2302
+ }
2303
+ return void 0;
2304
+ };
2305
+ proto[fnName] = wrapped;
2306
+ proto[shortKey] = wrapped;
2307
+ }
2308
+ /**
2309
+ * When two mixins define the same event method, merge them into
2310
+ * a single function that calls both in sequence.
2311
+ */
2312
+ static processMixinsSameEvent(additional, exist) {
2313
+ let temp;
2314
+ const existMixin = exist;
2315
+ if (existMixin.handlerList) {
2316
+ temp = existMixin;
2317
+ } else {
2318
+ temp = function(...e) {
2319
+ funcWithTry(temp.handlerList ?? [], e, this, noop);
2320
+ };
2321
+ temp.handlerList = [exist];
2322
+ temp.marker = 1;
2323
+ }
2324
+ const additionalMixin = additional;
2325
+ temp.handlerList = (temp.handlerList ?? []).concat(
2326
+ additionalMixin.handlerList ?? [additional]
2327
+ );
2328
+ return temp;
2329
+ }
2330
+ /**
2331
+ * Merge an array of mixin objects into the view prototype.
2332
+ */
2333
+ static mergeMixins(mixins, viewClass, ctors) {
2334
+ const proto = viewClass.prototype;
2335
+ const temp = {};
2336
+ for (const node of mixins) {
2337
+ for (const p in node) {
2338
+ if (!has(node, p)) continue;
2339
+ const fn = node[p];
2340
+ const exist = temp[p];
2341
+ if (p === "make") {
2342
+ ctors.push(fn);
2343
+ continue;
2344
+ }
2345
+ if (VIEW_EVENT_METHOD_REGEXP.test(p)) {
2346
+ if (exist) {
2347
+ temp[p] = _View.processMixinsSameEvent(fn, exist);
2348
+ } else {
2349
+ fn.marker = 1;
2350
+ temp[p] = fn;
2351
+ }
2352
+ } else {
2353
+ if (!exist) {
2354
+ temp[p] = fn;
2355
+ }
2356
+ }
2357
+ }
2358
+ }
2359
+ for (const p in temp) {
2360
+ if (!has(proto, p)) {
2361
+ proto[p] = temp[p];
2362
+ }
2363
+ }
2364
+ }
2365
+ /**
2366
+ * Destroy a single resource entry.
2367
+ */
2368
+ static destroyResource(cache, key, callDestroy, oldEntity) {
2369
+ const entry = cache[key];
2370
+ if (!entry || entry.entity === oldEntity) return void 0;
2371
+ const entity = entry.entity;
2372
+ if (entity && typeof entity === "object") {
2373
+ const destroyFn = entity["destroy"];
2374
+ if (typeof destroyFn === "function" && callDestroy) {
2375
+ funcWithTry(destroyFn, [], entity, noop);
2376
+ }
2377
+ }
2378
+ Reflect.deleteProperty(cache, key);
2379
+ return entity;
2380
+ }
2381
+ // ============================================================
2382
+ // Static: extend and merge
2383
+ // ============================================================
2312
2384
  /**
2313
2385
  * Extend View to create a new View subclass.
2314
2386
  *
2315
2387
  * Supports:
2316
- * - props.ctor: constructor-like init (called with initParams + {node, deep})
2388
+ * - props.make: constructor-like init (called with initParams + {node, deep})
2317
2389
  * - props.mixins: array of mixin objects
2318
2390
  * - Event method patterns: `'name<click>'` etc.
2319
2391
  */
2320
2392
  static extend(props, statics) {
2321
2393
  props = props || {};
2322
- const ctor = props["ctor"];
2394
+ const make = props["make"];
2323
2395
  const ctors = [];
2324
- if (ctor) {
2325
- ctors.push(ctor);
2396
+ if (make) {
2397
+ ctors.push(make);
2326
2398
  }
2327
2399
  const ParentView = this;
2328
2400
  const ChildView = class extends ParentView {
2329
2401
  constructor(nodeId, ownerFrame, initParams, node, mixinCtors) {
2330
2402
  super(nodeId, ownerFrame, initParams, node, []);
2331
2403
  for (const key in props) {
2332
- if (has(props, key) && key !== "ctor") {
2404
+ if (has(props, key) && key !== "make" && key !== "render") {
2333
2405
  this[key] = props[key];
2334
2406
  }
2335
2407
  }
@@ -2351,7 +2423,7 @@ var View = class _View {
2351
2423
  };
2352
2424
  const proto = ChildView.prototype;
2353
2425
  for (const key in props) {
2354
- if (has(props, key) && key !== "ctor") {
2426
+ if (has(props, key) && key !== "make") {
2355
2427
  proto[key] = props[key];
2356
2428
  }
2357
2429
  }
@@ -2362,36 +2434,17 @@ var View = class _View {
2362
2434
  }
2363
2435
  }
2364
2436
  }
2365
- ChildView.merge = viewMerge;
2366
- ChildView.extend = _View.extend;
2367
2437
  return ChildView;
2368
2438
  }
2369
2439
  /**
2370
2440
  * Merge mixins into View prototype.
2371
2441
  */
2372
2442
  static merge(...mixins) {
2373
- const self = this;
2374
- const existingCtors = self.ctors || [];
2375
- viewMergeMixins(mixins, self, existingCtors);
2376
- return self;
2443
+ const existingCtors = this.ctors || [];
2444
+ _View.mergeMixins(mixins, this, existingCtors);
2445
+ return this;
2377
2446
  }
2378
2447
  };
2379
- function viewMerge(...mixins) {
2380
- const self = this;
2381
- const existingCtors = self.ctors || [];
2382
- viewMergeMixins(mixins, self, existingCtors);
2383
- return self;
2384
- }
2385
- function runInvokes(frame) {
2386
- const list = frame.invokeList;
2387
- if (!list) return;
2388
- while (list.length) {
2389
- const entry = list.shift();
2390
- if (entry && !entry.removed) {
2391
- frame.invoke(entry.name, entry.args);
2392
- }
2393
- }
2394
- }
2395
2448
 
2396
2449
  // src/frame.ts
2397
2450
  var frameRegistry = /* @__PURE__ */ new Map();
@@ -2430,7 +2483,7 @@ var Frame = class _Frame extends EventEmitter {
2430
2483
  hasAltered = 0;
2431
2484
  /** Whether view is destroyed */
2432
2485
  destroyed = 0;
2433
- /** View path (lark-view attribute value) */
2486
+ /** View path (v-lark attribute value) */
2434
2487
  viewPath;
2435
2488
  /** Original template before mount */
2436
2489
  originalTemplate;
@@ -2499,7 +2552,7 @@ var Frame = class _Frame extends EventEmitter {
2499
2552
  */
2500
2553
  doMountView(ViewClass, params, node, sign) {
2501
2554
  if (sign !== this.signature) return;
2502
- const mixinCtors = viewPrepare(ViewClass);
2555
+ const mixinCtors = View.prepare(ViewClass);
2503
2556
  const ViewConstructor = ViewClass;
2504
2557
  const view = new ViewConstructor(
2505
2558
  this.id,
@@ -2510,7 +2563,7 @@ var Frame = class _Frame extends EventEmitter {
2510
2563
  );
2511
2564
  this.viewInstance = view;
2512
2565
  view.signature = 1;
2513
- viewDelegateEvents(view);
2566
+ View.delegateEvents(view);
2514
2567
  const initResult = funcWithTry(
2515
2568
  view.init,
2516
2569
  [params, { node, deep: !view.template }],
@@ -2521,13 +2574,10 @@ var Frame = class _Frame extends EventEmitter {
2521
2574
  Promise.resolve(initResult).then(() => {
2522
2575
  if (nextSign !== this.signature) return;
2523
2576
  if (view.template) {
2524
- const renderFn = view.$b;
2525
- if (renderFn) {
2526
- renderFn.call(view);
2527
- }
2577
+ view.render();
2528
2578
  } else {
2529
2579
  this.hasAltered = 0;
2530
- if (!view.$e) {
2580
+ if (!view.endUpdatePendingFlag) {
2531
2581
  view.endUpdate();
2532
2582
  }
2533
2583
  }
@@ -2714,7 +2764,7 @@ var Frame = class _Frame extends EventEmitter {
2714
2764
  /** Get or create root frame */
2715
2765
  static root(rootId) {
2716
2766
  if (!rootFrame) {
2717
- rootId = rootId || "lark-root";
2767
+ rootId = rootId || "root";
2718
2768
  let rootElement = document.getElementById(rootId);
2719
2769
  if (!rootElement) {
2720
2770
  rootElement = document.body;
@@ -2835,19 +2885,19 @@ function registerViewClass(viewPath, ViewClass) {
2835
2885
  }
2836
2886
 
2837
2887
  // src/service.ts
2838
- var Bag = class {
2839
- /** Bag data */
2888
+ var Payload = class {
2889
+ /** Payload data */
2840
2890
  data;
2841
2891
  /** Internal cache info */
2842
2892
  cacheInfo;
2843
2893
  constructor(data = {}) {
2844
2894
  this.data = data;
2845
2895
  }
2846
- /** Get a value from bag data */
2896
+ /** Get a value from payload data */
2847
2897
  get(key) {
2848
2898
  return this.data[key];
2849
2899
  }
2850
- /** Set a value in bag data */
2900
+ /** Set a value in payload data */
2851
2901
  set(keyOrData, value) {
2852
2902
  if (typeof keyOrData === "string") {
2853
2903
  this.data[keyOrData] = value;
@@ -2859,287 +2909,366 @@ var Bag = class {
2859
2909
  };
2860
2910
  var FETCH_FLAGS_ALL = 1;
2861
2911
  var FETCH_FLAGS_ONE = 2;
2862
- function createServiceType(syncFn, cacheMax = 20, cacheBuffer = 5) {
2863
- const metas = {};
2864
- const bagCache = new Cache({
2865
- maxSize: cacheMax,
2866
- bufferSize: cacheBuffer
2867
- });
2868
- const pendingCacheKeys = {};
2869
- const staticEmitter2 = new EventEmitter();
2870
- const serviceType = {
2871
- add(attrs) {
2872
- if (!isArray(attrs)) {
2873
- attrs = [attrs];
2874
- }
2875
- for (const bag of attrs) {
2876
- if (bag) {
2877
- const name = bag.name;
2878
- const cache = bag.cache;
2879
- bag.cache = cache ? cache | 0 : 0;
2880
- metas[name] = bag;
2881
- }
2882
- }
2883
- },
2884
- meta(attrs) {
2885
- const name = typeof attrs === "string" ? attrs : attrs["name"];
2886
- return metas[name] || attrs;
2887
- },
2888
- create(attrs) {
2889
- const meta = serviceType.meta(attrs);
2890
- const cache = attrs["cache"] | 0 || meta.cache || 0;
2891
- const entity = new Bag();
2892
- entity.set(meta);
2893
- entity.cacheInfo = {
2894
- name: meta.name,
2895
- after: meta.after,
2896
- cleans: meta.cleans,
2897
- key: cache ? defaultCacheKey(meta, attrs) : "",
2898
- time: 0
2899
- };
2900
- if (typeof attrs === "object" && attrs !== null) {
2901
- entity.set(attrs);
2902
- }
2903
- const before = meta.before;
2904
- if (before) {
2905
- funcWithTry(before, [entity], entity, noop);
2906
- }
2907
- staticEmitter2.fire("begin", { bag: entity });
2908
- return entity;
2909
- },
2910
- get(attrs, createNew) {
2911
- let entity;
2912
- let needsUpdate = false;
2913
- if (!createNew) {
2914
- entity = serviceType.cached(attrs);
2915
- }
2916
- if (!entity) {
2917
- entity = serviceType.create(attrs);
2918
- needsUpdate = true;
2919
- }
2920
- return { entity, needsUpdate };
2921
- },
2922
- cached(attrs) {
2923
- const meta = serviceType.meta(attrs);
2924
- const cache = attrs["cache"] | 0 || meta.cache || 0;
2925
- let cacheKey = "";
2926
- if (cache) {
2927
- cacheKey = defaultCacheKey(meta, attrs);
2928
- }
2929
- if (cacheKey) {
2930
- const info = pendingCacheKeys[cacheKey];
2931
- if (info) {
2932
- return info.e;
2933
- }
2934
- const cached = bagCache.get(cacheKey);
2935
- if (cached && cached.cacheInfo) {
2936
- if (now() - cached.cacheInfo.time > cache) {
2937
- bagCache.del(cacheKey);
2938
- return void 0;
2912
+ var Service = class {
2913
+ /** Service instance ID */
2914
+ id = "";
2915
+ /** Whether service is busy (1 = busy) */
2916
+ busy = 0;
2917
+ /** Whether service is destroyed (1 = destroyed) */
2918
+ destroyed = 0;
2919
+ /** Task queue for sequential operations */
2920
+ taskQueue = [];
2921
+ /** Previous dequeue arguments */
2922
+ prevArgs = [];
2923
+ /** Instance event emitter */
2924
+ _emitter = new EventEmitter();
2925
+ constructor() {
2926
+ this.id = generateId("service");
2927
+ }
2928
+ // ============================================================
2929
+ // Instance accessors for type-level data
2930
+ // ============================================================
2931
+ /** Instance event emitter (public accessor) */
2932
+ get emitter() {
2933
+ return this._emitter;
2934
+ }
2935
+ /**
2936
+ * Get internals object for serviceSend compatibility.
2937
+ * References per-type static state from the current class.
2938
+ */
2939
+ get internals() {
2940
+ const ctor = this.constructor;
2941
+ return {
2942
+ metaList: ctor._metaList,
2943
+ payloadCache: ctor._payloadCache,
2944
+ pendingCacheKeys: ctor._pendingCacheKeys,
2945
+ syncFn: ctor._syncFn,
2946
+ staticEmitter: ctor._staticEmitter
2947
+ };
2948
+ }
2949
+ /**
2950
+ * Get type reference (the constructor) for serviceSend compatibility.
2951
+ * Static methods like get/create are accessible via the constructor.
2952
+ */
2953
+ get type() {
2954
+ return this.constructor;
2955
+ }
2956
+ // ============================================================
2957
+ // Instance methods
2958
+ // ============================================================
2959
+ /**
2960
+ * Fetch all endpoints, callback when all complete.
2961
+ * Uses cache when available.
2962
+ */
2963
+ all(attrs, done) {
2964
+ serviceSend(this, attrs, done, FETCH_FLAGS_ALL, false);
2965
+ return this;
2966
+ }
2967
+ /**
2968
+ * Fetch all endpoints, callback on each completion.
2969
+ */
2970
+ one(attrs, done) {
2971
+ serviceSend(this, attrs, done, FETCH_FLAGS_ONE, false);
2972
+ return this;
2973
+ }
2974
+ /**
2975
+ * Fetch all endpoints, skip cache (always request).
2976
+ */
2977
+ save(attrs, done) {
2978
+ serviceSend(this, attrs, done, FETCH_FLAGS_ALL, true);
2979
+ return this;
2980
+ }
2981
+ /**
2982
+ * Enqueue a task for sequential execution.
2983
+ */
2984
+ enqueue(callback) {
2985
+ if (!this.destroyed) {
2986
+ this.taskQueue.push(callback);
2987
+ this.dequeue(...this.prevArgs);
2988
+ }
2989
+ return this;
2990
+ }
2991
+ /**
2992
+ * Dequeue and execute the next task in queue.
2993
+ */
2994
+ dequeue(...args) {
2995
+ if (!this.busy && !this.destroyed) {
2996
+ this.busy = 1;
2997
+ setTimeout(() => {
2998
+ this.busy = 0;
2999
+ if (!this.destroyed) {
3000
+ const task2 = this.taskQueue.shift();
3001
+ if (task2) {
3002
+ this.prevArgs = args;
3003
+ funcWithTry(task2, args, this, noop);
2939
3004
  }
2940
- return cached;
2941
3005
  }
3006
+ }, 0);
3007
+ }
3008
+ }
3009
+ /**
3010
+ * Destroy the service instance.
3011
+ * After destruction, no new requests can be sent.
3012
+ */
3013
+ destroy() {
3014
+ this.destroyed = 1;
3015
+ this.taskQueue = [];
3016
+ }
3017
+ // Instance event methods (delegate to instance emitter)
3018
+ on(event, handler) {
3019
+ this._emitter.on(event, handler);
3020
+ return this;
3021
+ }
3022
+ off(event, handler) {
3023
+ this._emitter.off(event, handler);
3024
+ return this;
3025
+ }
3026
+ fire(event, data) {
3027
+ this._emitter.fire(event, data);
3028
+ return this;
3029
+ }
3030
+ // ============================================================
3031
+ // Per-type static state
3032
+ // ============================================================
3033
+ /** Per-type metadata registry */
3034
+ static _metaList = {};
3035
+ /** Per-type payload cache (LFU with frequency eviction) */
3036
+ static _payloadCache = new Cache({
3037
+ maxSize: 20,
3038
+ bufferSize: 5
3039
+ });
3040
+ /** Per-type pending cache keys for deduplication */
3041
+ static _pendingCacheKeys = {};
3042
+ /** Per-type sync function */
3043
+ static _syncFn = noop;
3044
+ /** Per-type static event emitter */
3045
+ static _staticEmitter = new EventEmitter();
3046
+ /** Per-type cache max size */
3047
+ static _cacheMax = 20;
3048
+ /** Per-type cache buffer size */
3049
+ static _cacheBuffer = 5;
3050
+ // ============================================================
3051
+ // Static methods (operate on per-type state via `this`)
3052
+ // ============================================================
3053
+ /**
3054
+ * Register API endpoint metadata.
3055
+ */
3056
+ static add(attrs) {
3057
+ if (!Array.isArray(attrs)) {
3058
+ attrs = [attrs];
3059
+ }
3060
+ for (const payload of attrs) {
3061
+ if (payload) {
3062
+ const name = payload.name;
3063
+ const cache = payload.cache;
3064
+ payload.cache = cache ? cache | 0 : 0;
3065
+ this._metaList[name] = payload;
2942
3066
  }
2943
- return void 0;
2944
- },
2945
- clear(names) {
2946
- const nameList = (typeof names === "string" ? names : names.join(",")).split(",");
2947
- const nameSet = {};
2948
- for (const n of nameList) {
2949
- nameSet[n] = 1;
3067
+ }
3068
+ }
3069
+ /**
3070
+ * Get metadata for an API endpoint.
3071
+ */
3072
+ static meta(attrs) {
3073
+ const name = typeof attrs === "string" ? attrs : attrs["name"];
3074
+ return this._metaList[name] || attrs;
3075
+ }
3076
+ /**
3077
+ * Create a Payload for an API request.
3078
+ */
3079
+ static create(attrs) {
3080
+ const meta = this.meta(attrs);
3081
+ const cache = attrs["cache"] | 0 || meta.cache || 0;
3082
+ const entity = new Payload();
3083
+ entity.set(meta);
3084
+ entity.cacheInfo = {
3085
+ name: meta.name,
3086
+ after: meta.after,
3087
+ cleans: meta.cleanKeys,
3088
+ key: cache ? defaultCacheKey(meta, attrs) : "",
3089
+ time: 0
3090
+ };
3091
+ if (typeof attrs === "object" && attrs !== null) {
3092
+ entity.set(attrs);
3093
+ }
3094
+ const before = meta.before;
3095
+ if (before) {
3096
+ funcWithTry(before, [entity], entity, noop);
3097
+ }
3098
+ this._staticEmitter.fire("begin", { payload: entity });
3099
+ return entity;
3100
+ }
3101
+ /**
3102
+ * Get or create a Payload for an API request.
3103
+ */
3104
+ static get(attrs, createNew) {
3105
+ let entity;
3106
+ let needsUpdate = false;
3107
+ if (!createNew) {
3108
+ entity = this.cached(attrs);
3109
+ }
3110
+ if (!entity) {
3111
+ entity = this.create(attrs);
3112
+ needsUpdate = true;
3113
+ }
3114
+ return { entity, needsUpdate };
3115
+ }
3116
+ /**
3117
+ * Get cached Payload if available and not expired.
3118
+ */
3119
+ static cached(attrs) {
3120
+ const meta = this.meta(attrs);
3121
+ const cache = attrs["cache"] | 0 || meta.cache || 0;
3122
+ let cacheKey = "";
3123
+ if (cache) {
3124
+ cacheKey = defaultCacheKey(meta, attrs);
3125
+ }
3126
+ if (cacheKey) {
3127
+ const info = this._pendingCacheKeys[cacheKey];
3128
+ if (info) {
3129
+ return info.entity;
2950
3130
  }
2951
- const keysToDelete = [];
2952
- bagCache.forEach((bag) => {
2953
- if (bag?.cacheInfo && nameSet[bag.cacheInfo.name]) {
2954
- if (bag.cacheInfo.key) {
2955
- keysToDelete.push(bag.cacheInfo.key);
2956
- }
3131
+ const cached = this._payloadCache.get(cacheKey);
3132
+ if (cached && cached.cacheInfo) {
3133
+ if (now() - cached.cacheInfo.time > cache) {
3134
+ this._payloadCache.del(cacheKey);
3135
+ return void 0;
2957
3136
  }
2958
- });
2959
- for (const key of keysToDelete) {
2960
- bagCache.del(key);
3137
+ return cached;
2961
3138
  }
2962
- },
2963
- on(event, handler) {
2964
- staticEmitter2.on(event, handler);
2965
- },
2966
- off(event, handler) {
2967
- staticEmitter2.off(event, handler);
2968
- },
2969
- fire(event, data) {
2970
- staticEmitter2.fire(event, data);
2971
- },
2972
- extend(newSyncFn, newCacheMax, newCacheBuffer) {
2973
- return createServiceType(
2974
- newSyncFn,
2975
- newCacheMax || cacheMax,
2976
- newCacheBuffer || cacheBuffer
2977
- );
2978
3139
  }
2979
- };
2980
- const internals = {
2981
- metas,
2982
- bagCache,
2983
- pendingCacheKeys,
2984
- syncFn,
2985
- staticEmitter: staticEmitter2
2986
- };
2987
- function ServiceInstance() {
2988
- this.id = generateId("s");
2989
- this["$e"] = 0;
2990
- this["$d"] = 0;
2991
- this["$g"] = [];
2992
- this["$h"] = [];
2993
- this._emitter = new EventEmitter();
2994
- this._internals = internals;
2995
- this._type = serviceType;
2996
- }
2997
- ServiceInstance.prototype = {
2998
- all(attrs, done) {
2999
- serviceSend(this, attrs, done, FETCH_FLAGS_ALL, false);
3000
- return this;
3001
- },
3002
- one(attrs, done) {
3003
- serviceSend(this, attrs, done, FETCH_FLAGS_ONE, false);
3004
- return this;
3005
- },
3006
- save(attrs, done) {
3007
- serviceSend(this, attrs, done, FETCH_FLAGS_ALL, true);
3008
- return this;
3009
- },
3010
- enqueue(callback) {
3011
- if (!this["$d"]) {
3012
- this["$g"].push(callback);
3013
- this.dequeue(...this["$h"]);
3014
- }
3015
- return this;
3016
- },
3017
- dequeue(...args) {
3018
- if (!this["$e"] && !this["$d"]) {
3019
- this["$e"] = 1;
3020
- setTimeout(() => {
3021
- this["$e"] = 0;
3022
- if (!this["$d"]) {
3023
- const task2 = this["$g"].shift();
3024
- if (task2) {
3025
- this["$h"] = args;
3026
- funcWithTry(task2, args, this, noop);
3027
- }
3028
- }
3029
- }, 0);
3140
+ return void 0;
3141
+ }
3142
+ /**
3143
+ * Clear cached payloads by endpoint name.
3144
+ */
3145
+ static clear(names) {
3146
+ const nameList = (typeof names === "string" ? names : names.join(",")).split(",");
3147
+ const nameSet = {};
3148
+ for (const n of nameList) {
3149
+ nameSet[n] = 1;
3150
+ }
3151
+ const keysToDelete = [];
3152
+ this._payloadCache.forEach((payload) => {
3153
+ if (payload?.cacheInfo && nameSet[payload.cacheInfo.name]) {
3154
+ if (payload.cacheInfo.key) {
3155
+ keysToDelete.push(payload.cacheInfo.key);
3156
+ }
3030
3157
  }
3031
- },
3032
- destroy() {
3033
- this["$d"] = 1;
3034
- this["$g"] = [];
3035
- },
3036
- on(event, handler) {
3037
- this._emitter.on(event, handler);
3038
- return this;
3039
- },
3040
- off(event, handler) {
3041
- this._emitter.off(event, handler);
3042
- return this;
3043
- },
3044
- fire(event, data) {
3045
- this._emitter.fire(event, data);
3046
- return this;
3158
+ });
3159
+ for (const key of keysToDelete) {
3160
+ this._payloadCache.del(key);
3047
3161
  }
3048
- };
3049
- const staticsMap = {
3050
- add: serviceType.add,
3051
- meta: serviceType.meta,
3052
- create: serviceType.create,
3053
- get: serviceType.get,
3054
- cached: serviceType.cached,
3055
- clear: serviceType.clear,
3056
- on: serviceType.on,
3057
- off: serviceType.off,
3058
- fire: serviceType.fire,
3059
- extend: serviceType.extend,
3060
- _internals: internals
3061
- };
3062
- const constructor = Object.assign(
3063
- ServiceInstance,
3064
- staticsMap
3065
- );
3066
- return constructor;
3067
- }
3068
- var Service = createServiceType(noop);
3162
+ }
3163
+ // Static event methods (operate on per-type emitter)
3164
+ static on(event, handler) {
3165
+ this._staticEmitter.on(event, handler);
3166
+ }
3167
+ static off(event, handler) {
3168
+ this._staticEmitter.off(event, handler);
3169
+ }
3170
+ static fire(event, data) {
3171
+ this._staticEmitter.fire(event, data);
3172
+ }
3173
+ /**
3174
+ * Create a new Service subclass with a custom sync function.
3175
+ * Each subclass gets its own per-type state (metaList, cache, etc.)
3176
+ * to ensure isolation between different Service types.
3177
+ */
3178
+ static extend(newSyncFn, newCacheMax, newCacheBuffer) {
3179
+ const ParentService = this;
3180
+ class ChildService extends ParentService {
3181
+ static _metaList = {};
3182
+ static _payloadCache = new Cache({
3183
+ maxSize: newCacheMax || ParentService._cacheMax,
3184
+ bufferSize: newCacheBuffer || ParentService._cacheBuffer
3185
+ });
3186
+ static _pendingCacheKeys = {};
3187
+ static _syncFn = newSyncFn;
3188
+ static _staticEmitter = new EventEmitter();
3189
+ static _cacheMax = newCacheMax || ParentService._cacheMax;
3190
+ static _cacheBuffer = newCacheBuffer || ParentService._cacheBuffer;
3191
+ }
3192
+ return ChildService;
3193
+ }
3194
+ };
3069
3195
  function defaultCacheKey(meta, attrs) {
3070
3196
  return JSON.stringify(attrs) + SPLITTER + JSON.stringify(meta);
3071
3197
  }
3072
3198
  function serviceSend(service, attrs, done, flag, save) {
3073
- if (service["$d"]) return;
3074
- if (service["$e"]) {
3199
+ if (service["destroyed"]) return;
3200
+ if (service["busy"]) {
3075
3201
  service.enqueue(
3076
3202
  serviceSend.bind(null, service, attrs, done, flag, save)
3077
3203
  );
3078
3204
  return;
3079
3205
  }
3080
- service["$e"] = 1;
3206
+ service["busy"] = 1;
3081
3207
  let attrList;
3082
3208
  if (typeof attrs === "string") {
3083
3209
  attrList = [{ name: attrs }];
3084
- } else if (isArray(attrs)) {
3210
+ } else if (Array.isArray(attrs)) {
3085
3211
  attrList = attrs;
3086
3212
  } else {
3087
3213
  attrList = [attrs];
3088
3214
  }
3089
- const internals = service._internals;
3215
+ const internals = service.internals;
3090
3216
  const { syncFn, pendingCacheKeys, staticEmitter: staticEmitter2 } = internals;
3091
3217
  let requestCount = 0;
3092
3218
  const total = attrList.length;
3093
3219
  const doneArr = new Array(total + 1);
3094
3220
  const errorArgs = [];
3095
3221
  const remoteComplete = (idx, error) => {
3096
- const bag = doneArr[idx + 1];
3097
- let newBag = false;
3222
+ const payload = doneArr[idx + 1];
3223
+ let newPayload = false;
3098
3224
  if (error) {
3099
3225
  errorArgs[idx] = error;
3100
- staticEmitter2.fire("fail", { bag, error });
3226
+ staticEmitter2.fire("fail", { payload, error });
3101
3227
  } else {
3102
- newBag = true;
3103
- staticEmitter2.fire("done", { bag });
3228
+ newPayload = true;
3229
+ staticEmitter2.fire("done", { payload });
3104
3230
  }
3105
- if (!service["$d"]) {
3231
+ if (!service["destroyed"]) {
3106
3232
  const finish = requestCount === total;
3107
3233
  if (finish) {
3108
- service["$e"] = 0;
3234
+ service["busy"] = 0;
3109
3235
  if (flag === FETCH_FLAGS_ALL) {
3110
3236
  doneArr[0] = errorArgs;
3111
3237
  funcWithTry(done, doneArr, service, noop);
3112
3238
  }
3113
3239
  }
3114
3240
  if (flag === FETCH_FLAGS_ONE) {
3115
- funcWithTry(done, [error || null, bag, finish, idx], service, noop);
3241
+ funcWithTry(done, [error || null, payload, finish, idx], service, noop);
3116
3242
  }
3117
3243
  }
3118
- if (newBag) {
3119
- staticEmitter2.fire("end", { bag, error });
3244
+ if (newPayload) {
3245
+ staticEmitter2.fire("end", { payload, error });
3120
3246
  }
3121
3247
  };
3122
3248
  for (const attr of attrList) {
3123
3249
  if (!attr) continue;
3124
3250
  const attrObj = typeof attr === "string" ? { name: attr } : attr;
3125
- const bagInfo = service._type.get(attrObj, save);
3126
- const bagEntity = bagInfo.entity;
3127
- const cacheKey = bagEntity.cacheInfo?.key || "";
3251
+ const payloadInfo = service.type.get(
3252
+ attrObj,
3253
+ save
3254
+ );
3255
+ const payloadEntity = payloadInfo.entity;
3256
+ const cacheKey = payloadEntity.cacheInfo?.key || "";
3128
3257
  const complete = remoteComplete.bind(null, requestCount++);
3129
3258
  if (cacheKey && pendingCacheKeys[cacheKey]) {
3130
3259
  pendingCacheKeys[cacheKey].push(complete);
3131
- } else if (bagInfo.needsUpdate) {
3260
+ } else if (payloadInfo.needsUpdate) {
3132
3261
  if (cacheKey) {
3133
3262
  const cacheList = [complete];
3134
- cacheList.e = bagEntity;
3263
+ cacheList.entity = payloadEntity;
3135
3264
  pendingCacheKeys[cacheKey] = cacheList;
3136
3265
  const cacheComplete = () => {
3137
3266
  const list = pendingCacheKeys[cacheKey];
3138
- const entity = list.e;
3267
+ const entity = list.entity;
3139
3268
  if (entity.cacheInfo) {
3140
3269
  entity.cacheInfo.time = now();
3141
3270
  }
3142
- internals.bagCache.set(cacheKey, entity);
3271
+ internals.payloadCache.set(cacheKey, entity);
3143
3272
  Reflect.deleteProperty(pendingCacheKeys, cacheKey);
3144
3273
  for (const cb of list) {
3145
3274
  if (typeof cb === "function") {
@@ -3147,9 +3276,9 @@ function serviceSend(service, attrs, done, flag, save) {
3147
3276
  }
3148
3277
  }
3149
3278
  };
3150
- syncFn(bagEntity, cacheComplete);
3279
+ syncFn(payloadEntity, cacheComplete);
3151
3280
  } else {
3152
- syncFn(bagEntity, complete);
3281
+ syncFn(payloadEntity, complete);
3153
3282
  }
3154
3283
  } else {
3155
3284
  complete();
@@ -3157,9 +3286,117 @@ function serviceSend(service, attrs, done, flag, save) {
3157
3286
  }
3158
3287
  }
3159
3288
 
3289
+ // src/frame-visualizer.ts
3290
+ var MSG_PING = "LARK_VISUALIZER_PING";
3291
+ var MSG_PONG = "LARK_VISUALIZER_PONG";
3292
+ var MSG_REQUEST_TREE = "LARK_VISUALIZER_REQUEST_TREE";
3293
+ var MSG_TREE = "LARK_VISUALIZER_TREE";
3294
+ var MSG_TREE_DELTA = "LARK_VISUALIZER_TREE_DELTA";
3295
+ function serializeView(view) {
3296
+ return {
3297
+ id: view.id,
3298
+ rendered: !!view.rendered,
3299
+ signature: view.signature,
3300
+ observedStateKeys: view.observedStateKeys ?? null,
3301
+ locationObserved: {
3302
+ flag: view.locationObserved.flag,
3303
+ keys: view.locationObserved.keys,
3304
+ observePath: view.locationObserved.observePath
3305
+ },
3306
+ hasTemplate: !!view.template
3307
+ };
3308
+ }
3309
+ function serializeFrame(frameId) {
3310
+ const frame = Frame.get(frameId);
3311
+ if (!frame) return null;
3312
+ const view = frame.view;
3313
+ const children = [];
3314
+ for (const childId of frame.children()) {
3315
+ const childNode = serializeFrame(childId);
3316
+ if (childNode) {
3317
+ children.push(childNode);
3318
+ }
3319
+ }
3320
+ return {
3321
+ id: frame.id,
3322
+ parentId: frame.parentId ?? null,
3323
+ viewPath: frame.viewPath ?? null,
3324
+ childrenCount: frame.childrenCount,
3325
+ readyCount: frame.readyCount,
3326
+ childrenCreated: frame.childrenCreated,
3327
+ childrenAlter: frame.childrenAlter,
3328
+ destroyed: frame.destroyed,
3329
+ view: view ? serializeView(view) : null,
3330
+ children
3331
+ };
3332
+ }
3333
+ function serializeFrameTree() {
3334
+ const root = Frame.root();
3335
+ const rootNode = serializeFrame(root.id);
3336
+ let totalFrames = 0;
3337
+ const countFrames = (node) => {
3338
+ if (!node) return;
3339
+ totalFrames++;
3340
+ for (const child of node.children) {
3341
+ countFrames(child);
3342
+ }
3343
+ };
3344
+ countFrames(rootNode);
3345
+ return {
3346
+ root: rootNode,
3347
+ totalFrames,
3348
+ timestamp: Date.now(),
3349
+ rootId: root.id
3350
+ };
3351
+ }
3352
+ var bridgeInstalled = false;
3353
+ var lastTreeJson = "";
3354
+ function installFrameVisualizerBridge() {
3355
+ if (bridgeInstalled) return;
3356
+ if (typeof window === "undefined") return;
3357
+ bridgeInstalled = true;
3358
+ window.addEventListener("message", (event) => {
3359
+ const data = event.data;
3360
+ if (!data || typeof data !== "object") return;
3361
+ const type = data.type;
3362
+ if (type === MSG_PING) {
3363
+ const source = event.source;
3364
+ if (source) {
3365
+ source.postMessage({ type: MSG_PONG }, { targetOrigin: "*" });
3366
+ }
3367
+ return;
3368
+ }
3369
+ if (type === MSG_REQUEST_TREE) {
3370
+ const tree = serializeFrameTree();
3371
+ const source = event.source;
3372
+ if (source) {
3373
+ source.postMessage(
3374
+ { type: MSG_TREE, data: tree },
3375
+ { targetOrigin: "*" }
3376
+ );
3377
+ }
3378
+ }
3379
+ });
3380
+ Frame.on("add", () => {
3381
+ pushTreeUpdate();
3382
+ });
3383
+ Frame.on("remove", () => {
3384
+ pushTreeUpdate();
3385
+ });
3386
+ }
3387
+ function pushTreeUpdate() {
3388
+ if (window === window.parent) return;
3389
+ const tree = serializeFrameTree();
3390
+ const treeJson = JSON.stringify(tree);
3391
+ if (treeJson !== lastTreeJson) {
3392
+ lastTreeJson = treeJson;
3393
+ window.parent.postMessage({ type: MSG_TREE_DELTA, data: tree }, "*");
3394
+ }
3395
+ }
3396
+
3160
3397
  // src/framework.ts
3161
3398
  var config = {
3162
- rootId: "lark-root",
3399
+ rootId: "root",
3163
3400
  hashbang: "#!",
3164
3401
  error: (error) => {
3165
3402
  throw error;
@@ -3252,7 +3489,12 @@ function dispatcherUpdate(frame, stateKeys) {
3252
3489
  const isChanged = stateKeys ? stateIsObserveChanged(view, stateKeys) : viewIsObserveChanged(view);
3253
3490
  let renderPromise;
3254
3491
  if (isChanged) {
3255
- const renderResult = funcWithTry(view.$b ?? view.render, [], view, noop);
3492
+ const renderResult = funcWithTry(
3493
+ view.renderMethod ?? view.render,
3494
+ [],
3495
+ view,
3496
+ noop
3497
+ );
3256
3498
  if (renderResult && typeof renderResult.then === "function") {
3257
3499
  renderPromise = renderResult;
3258
3500
  }
@@ -3274,13 +3516,13 @@ function dispatcherUpdate(frame, stateKeys) {
3274
3516
  }
3275
3517
  function dispatcherNotifyChange(e) {
3276
3518
  const rootFrame2 = Frame.root();
3277
- const view = e["view"];
3519
+ const view = e.view;
3278
3520
  if (view) {
3279
3521
  const viewPath = typeof view === "object" && view !== null ? String(view.to || "") : String(view);
3280
3522
  rootFrame2.mountView(viewPath);
3281
3523
  } else {
3282
3524
  dispatcherUpdateTag++;
3283
- dispatcherUpdate(rootFrame2, e["keys"]);
3525
+ dispatcherUpdate(rootFrame2, e.keys);
3284
3526
  }
3285
3527
  }
3286
3528
  function dispatchEvent(target, eventType, eventInit) {
@@ -3291,8 +3533,6 @@ function dispatchEvent(target, eventType, eventInit) {
3291
3533
  });
3292
3534
  target.dispatchEvent(event);
3293
3535
  }
3294
- var Base = class extends EventEmitter {
3295
- };
3296
3536
  function use(names, callback) {
3297
3537
  if (!config.require) {
3298
3538
  if (callback) callback();
@@ -3307,7 +3547,7 @@ function use(names, callback) {
3307
3547
  }
3308
3548
  }
3309
3549
  var WAIT_OK = 1;
3310
- var WAIT_TIMEOUT_OR_UNFOUND = 0;
3550
+ var WAIT_TIMEOUT_OR_NOT_FOUND = 0;
3311
3551
  function waitZoneViewsRendered(viewId, timeout) {
3312
3552
  if (timeout == null) {
3313
3553
  timeout = 30 * 1e3;
@@ -3318,7 +3558,7 @@ function waitZoneViewsRendered(viewId, timeout) {
3318
3558
  const check = () => {
3319
3559
  const currentTime = now();
3320
3560
  if (currentTime > endTime || !checkFrame) {
3321
- resolve(WAIT_TIMEOUT_OR_UNFOUND);
3561
+ resolve(WAIT_TIMEOUT_OR_NOT_FOUND);
3322
3562
  } else if (checkFrame.childrenCount === checkFrame.readyCount) {
3323
3563
  resolve(WAIT_OK);
3324
3564
  } else {
@@ -3355,14 +3595,15 @@ var Framework = {
3355
3595
  Router._setConfig(config);
3356
3596
  EventDelegator.setFrameGetter((id) => Frame.get(id));
3357
3597
  Router.on(ROUTER_EVENTS.CHANGED, (data) => {
3358
- dispatcherNotifyChange(data);
3598
+ if (data) dispatcherNotifyChange(data);
3359
3599
  });
3360
3600
  State.on(ROUTER_EVENTS.CHANGED, (data) => {
3361
- dispatcherNotifyChange(data);
3601
+ if (data) dispatcherNotifyChange(data);
3362
3602
  });
3363
3603
  booted3 = true;
3364
3604
  markBooted();
3365
3605
  markRouterBooted();
3606
+ installFrameVisualizerBridge();
3366
3607
  const rootFrame2 = Frame.root(config.rootId);
3367
3608
  Router._bind();
3368
3609
  const defaultView = config.defaultView || "";
@@ -3394,7 +3635,7 @@ var Framework = {
3394
3635
  /** Wait for zone views to be rendered */
3395
3636
  waitZoneViewsRendered,
3396
3637
  WAIT_OK,
3397
- WAIT_TIMEOUT_OR_UNFOUND,
3638
+ WAIT_TIMEOUT_OR_NOT_FOUND,
3398
3639
  /**
3399
3640
  * Convert array to hash map.
3400
3641
  */
@@ -3459,7 +3700,7 @@ var Framework = {
3459
3700
  /**
3460
3701
  * Base class with EventEmitter.
3461
3702
  */
3462
- Base,
3703
+ Base: EventEmitter,
3463
3704
  // ============================================================
3464
3705
  // Module access
3465
3706
  // ============================================================
@@ -3477,10 +3718,11 @@ if (typeof window !== "undefined") {
3477
3718
  window.__lark_State = State;
3478
3719
  window.__lark_Router = Router;
3479
3720
  window.__lark_Frame = Frame;
3721
+ window.__lark_View = View;
3480
3722
  }
3481
3723
 
3482
3724
  // src/store.ts
3483
- var LARK_GLOBAL = "lark_global";
3725
+ var LARK_GLOBAL = "lark-global";
3484
3726
  var Platform = /* @__PURE__ */ ((Platform2) => {
3485
3727
  Platform2["Lark"] = "lark";
3486
3728
  Platform2["React"] = "react";
@@ -3523,8 +3765,10 @@ var Queue = class {
3523
3765
  const flushTickTask = () => {
3524
3766
  while (queue.length > 0) {
3525
3767
  const task2 = queue.shift();
3526
- pendingTasks.delete(task2);
3527
- runTask(task2);
3768
+ if (task2) {
3769
+ pendingTasks.delete(task2);
3770
+ runTask(task2);
3771
+ }
3528
3772
  }
3529
3773
  };
3530
3774
  Promise.resolve().then(flushTickTask);
@@ -3623,9 +3867,11 @@ var setStateConfig = (target, config2) => {
3623
3867
  if (target && isObject(config2)) StateConfigMap.set(target, config2);
3624
3868
  };
3625
3869
  var getStateConfig = (target, key) => {
3626
- if (!StateConfigMap.has(target)) return void 0;
3870
+ if (!StateConfigMap.has(target)) {
3871
+ return void 0;
3872
+ }
3627
3873
  const config2 = StateConfigMap.get(target);
3628
- return key ? config2[key] : config2;
3874
+ return key ? config2?.[key] : config2;
3629
3875
  };
3630
3876
  var isState = (target) => isObject(target) && StateConfigMap.has(target);
3631
3877
  var createLinkKeys = (target, property) => {
@@ -3795,20 +4041,20 @@ function createState(initialData, config2) {
3795
4041
  lazySet(state, initialData);
3796
4042
  return state;
3797
4043
  }
3798
- var currLazySetKey = null;
4044
+ var curLazySetKey = null;
3799
4045
  function lazySet(target, data) {
3800
4046
  if (isObject(data)) {
3801
4047
  Reflect.ownKeys(data).forEach((key) => {
3802
4048
  const strKey = key;
3803
- if (currLazySetKey) throw new Error("[lark-store] lazy set key conflict");
3804
- currLazySetKey = strKey;
4049
+ if (curLazySetKey) throw new Error("[lark-store] lazy set key conflict");
4050
+ curLazySetKey = strKey;
3805
4051
  target[strKey] = data[strKey];
3806
4052
  });
3807
4053
  }
3808
4054
  }
3809
4055
  function isLazySet(property) {
3810
- if (currLazySetKey === property) {
3811
- currLazySetKey = "";
4056
+ if (curLazySetKey === property) {
4057
+ curLazySetKey = "";
3812
4058
  return true;
3813
4059
  }
3814
4060
  return false;
@@ -4192,14 +4438,11 @@ function defineStore(name, creator, config2) {
4192
4438
  const useStore = adapter.useStore;
4193
4439
  const store = new StoreClass(name, config2);
4194
4440
  store[_storeCreate](
4195
- creator(
4196
- store[_innerStore](),
4197
- extendApis
4198
- )
4441
+ creator(store[_innerStore](), extendApis)
4199
4442
  );
4200
4443
  Object.defineProperties(useStore, {
4201
4444
  $storeName: { value: name, configurable: true },
4202
- $del: { value: () => store[_storeDestroy](), configurable: true }
4445
+ $destroyFn: { value: () => store[_storeDestroy](), configurable: true }
4203
4446
  });
4204
4447
  if (!StoreCache.has(name)) {
4205
4448
  StoreCache.set(name, { store, creator, config: config2, useStore });
@@ -4264,7 +4507,7 @@ function observeCell(state, cb, immediate = true) {
4264
4507
  }
4265
4508
  function multi(useStore) {
4266
4509
  const storeName = useStore["$storeName"];
4267
- const flagSym = `lark_comp_${storeName}`;
4510
+ const flagSym = `lark-comp-${storeName}`;
4268
4511
  const map = /* @__PURE__ */ new Map();
4269
4512
  let rootViewPath;
4270
4513
  const getFlag = (viewContext) => {
@@ -4273,7 +4516,7 @@ function multi(useStore) {
4273
4516
  const viewId = owner?.["id"] || "";
4274
4517
  let flag;
4275
4518
  if (viewPath === rootViewPath) {
4276
- flag = `${flagSym}_${viewId}`;
4519
+ flag = `${flagSym}-${viewId}`;
4277
4520
  } else {
4278
4521
  flag = owner?.["viewInitParams"]?.[flagSym];
4279
4522
  }
@@ -4290,19 +4533,18 @@ function multi(useStore) {
4290
4533
  };
4291
4534
  const useFn = ((view) => {
4292
4535
  if (!view)
4293
- throw new Error("[lark-store] multi: cannot find the view instance");
4536
+ throw new Error(
4537
+ "[@lark.js/mvc error] multi: cannot find the view instance"
4538
+ );
4294
4539
  const viewCtx = view;
4295
4540
  const flag = viewCtx[flagSym];
4296
4541
  if (map.has(flag)) return map.get(flag);
4297
- const newFn = cloneStore(
4298
- flag,
4299
- useStore
4300
- );
4542
+ const newFn = cloneStore(flag, useStore);
4301
4543
  map.set(flag, newFn);
4302
4544
  return useFn(view);
4303
4545
  });
4304
4546
  const mixinObj = {
4305
- ctor() {
4547
+ make() {
4306
4548
  if (!rootViewPath) {
4307
4549
  const owner = this["owner"];
4308
4550
  rootViewPath = owner?.["path"] || "";
@@ -4352,17 +4594,17 @@ function restoreComments(source, comments) {
4352
4594
  }
4353
4595
  function processViewEvents(source) {
4354
4596
  return source.replace(
4355
- /v-(\w+)="([^"]+)"/g,
4597
+ /@(\w+)="([^"]+)"/g,
4356
4598
  (fullAttr, eventName, attrValue) => {
4357
4599
  const eventMatch = attrValue.match(/^(\w+)\((.*)\)$/s);
4358
4600
  if (!eventMatch) return fullAttr;
4359
4601
  const handlerName = eventMatch[1];
4360
4602
  const paramsStr = eventMatch[2].trim();
4361
4603
  if (!paramsStr) {
4362
- return `v-${eventName}="${VIEW_ID_PLACEHOLDER}${SPLITTER2}${handlerName}()"`;
4604
+ return `@${eventName}="${VIEW_ID_PLACEHOLDER}${SPLITTER2}${handlerName}()"`;
4363
4605
  }
4364
4606
  const urlParams = jsObjectToUrlParams(paramsStr);
4365
- return `v-${eventName}="${VIEW_ID_PLACEHOLDER}${SPLITTER2}${handlerName}(${urlParams})"`;
4607
+ return `@${eventName}="${VIEW_ID_PLACEHOLDER}${SPLITTER2}${handlerName}(${urlParams})"`;
4366
4608
  }
4367
4609
  );
4368
4610
  }
@@ -4435,7 +4677,7 @@ function convertArtSyntax(source, debug) {
4435
4677
  }
4436
4678
  if (blockStack.length > 0) {
4437
4679
  const unclosed = blockStack.map((b) => `"${b.ctrl}" at line ${b.line}`).join(", ");
4438
- throw new Error(`[@lark/mvc error] unclosed block(s): ${unclosed}`);
4680
+ throw new Error(`[@lark.js/mvc error] unclosed block(s): ${unclosed}`);
4439
4681
  }
4440
4682
  return result.join("");
4441
4683
  }
@@ -4529,12 +4771,12 @@ function convertArtExpression(code, debug, lineNo, blockStack = []) {
4529
4771
  }
4530
4772
  return `${debugPrefix}<%}else{%>`;
4531
4773
  }
4532
- case "each": {
4533
- blockStack.push({ ctrl: "each", line: lineNo });
4774
+ case "forOf": {
4775
+ blockStack.push({ ctrl: "forOf", line: lineNo });
4534
4776
  const object = tokens[0];
4535
4777
  if (tokens.length > 1 && tokens[1] !== "as") {
4536
4778
  throw new Error(
4537
- `[@lark/mvc error] bad each syntax: {{${code}}}. Expected "as" keyword, got "${tokens[1]}". Usage: {{each list as item [index]}}`
4779
+ `[@lark.js/mvc error] bad forOf syntax: {{${code}}}. Expected "as" keyword, got "${tokens[1]}". Usage: {{forOf list as item [index]}}`
4538
4780
  );
4539
4781
  }
4540
4782
  const restTokens = tokens.slice(2);
@@ -4556,12 +4798,12 @@ function convertArtExpression(code, debug, lineNo, blockStack = []) {
4556
4798
  }
4557
4799
  return `${debugPrefix}<%for(let ${index}=0${refExpr},${refObjCount}=${refObj}.length${lastCount};${index}<${refObjCount};${index}++){${firstAndLast}${valueDecl}%>`;
4558
4800
  }
4559
- case "parse": {
4560
- blockStack.push({ ctrl: "parse", line: lineNo });
4801
+ case "forIn": {
4802
+ blockStack.push({ ctrl: "forIn", line: lineNo });
4561
4803
  const object = tokens[0];
4562
4804
  if (tokens.length > 1 && tokens[1] !== "as") {
4563
4805
  throw new Error(
4564
- `[@lark/mvc error] bad parse syntax: {{${code}}}. Expected "as" keyword, got "${tokens[1]}". Usage: {{for-in obj as val [key]}}`
4806
+ `[@lark.js/mvc error] bad forIn syntax: {{${code}}}. Expected "as" keyword, got "${tokens[1]}". Usage: {{for-in obj as val [key]}}`
4565
4807
  );
4566
4808
  }
4567
4809
  const restTokens2 = tokens.slice(2);
@@ -4581,19 +4823,19 @@ function convertArtExpression(code, debug, lineNo, blockStack = []) {
4581
4823
  case "set":
4582
4824
  return `${debugPrefix}<%let ${tokens.join(" ")};%>`;
4583
4825
  case "/if":
4584
- case "/each":
4585
- case "/parse":
4826
+ case "/forOf":
4827
+ case "/forIn":
4586
4828
  case "/for": {
4587
4829
  const expectedCtrl = keyword.substring(1);
4588
4830
  const last = blockStack.pop();
4589
4831
  if (!last) {
4590
4832
  throw new Error(
4591
- `[@lark/mvc error(template] unexpected {{${code}}}: no matching open block`
4833
+ `[@lark.js/mvc error] unexpected {{${code}}}: no matching open block`
4592
4834
  );
4593
4835
  }
4594
4836
  if (last.ctrl !== expectedCtrl) {
4595
4837
  throw new Error(
4596
- `[@lark/mvc error(template] unexpected {{${code}}}: expected {{/${last.ctrl}}} to close block opened at line ${last.line}`
4838
+ `[@lark.js/mvc error] unexpected {{${code}}}: expected {{/${last.ctrl}}} to close block opened at line ${last.line}`
4597
4839
  );
4598
4840
  }
4599
4841
  return `${debugPrefix}<%}%>`;
@@ -4657,7 +4899,7 @@ function parseAsExpr(expr) {
4657
4899
  function compileToFunction(source, debug, file) {
4658
4900
  const matcher = /<%([@=!:])?([\s\S]*?)%>|$/g;
4659
4901
  let index = 0;
4660
- let funcSource = `$p+='`;
4902
+ let funcSource = `$out+='`;
4661
4903
  let hasAtRule = false;
4662
4904
  const escapeSlashRegExp = /\\|'/g;
4663
4905
  const escapeBreakReturnRegExp = /\r|\n/g;
@@ -4683,17 +4925,17 @@ function compileToFunction(source, debug, file) {
4683
4925
  }
4684
4926
  if (operate === "@") {
4685
4927
  hasAtRule = true;
4686
- funcSource += `'+($expr='<%${operate + expr}%>',$i($$ref,${content}))+'`;
4928
+ funcSource += `'+($dbgExpr='<%${operate + expr}%>',$refFn($refAlt,${content}))+'`;
4687
4929
  } else if (operate === "=" || operate === ":") {
4688
- funcSource += `'+($expr='<%${operate + expr}%>',$e(${content}))+'`;
4930
+ funcSource += `'+($dbgExpr='<%${operate + expr}%>',$encHtml(${content}))+'`;
4689
4931
  } else if (operate === "!") {
4690
- if (!content.startsWith("$eu(") || !content.endsWith(")")) {
4691
- content = `$n(${content})`;
4932
+ if (!content.startsWith("$encUri(") || !content.endsWith(")")) {
4933
+ content = `$strSafe(${content})`;
4692
4934
  }
4693
- funcSource += `'+($expr='<%${operate + expr}%>',${content})+'`;
4935
+ funcSource += `'+($dbgExpr='<%${operate + expr}%>',${content})+'`;
4694
4936
  } else if (content) {
4695
4937
  if (line > -1) {
4696
- funcSource += `';$line=${line};$art='${art}';`;
4938
+ funcSource += `';$dbgLine=${line};$dbgArt='${art}';`;
4697
4939
  content = "";
4698
4940
  } else {
4699
4941
  funcSource += `';`;
@@ -4702,19 +4944,19 @@ function compileToFunction(source, debug, file) {
4702
4944
  funcSource = funcSource.substring(0, funcSource.length - 4) + ";";
4703
4945
  }
4704
4946
  if (expr) {
4705
- funcSource += `$expr='<%${expr}%>';`;
4947
+ funcSource += `$dbgExpr='<%${expr}%>';`;
4706
4948
  }
4707
- funcSource += content + `;$p+='`;
4949
+ funcSource += content + `;$out+='`;
4708
4950
  }
4709
4951
  } else {
4710
4952
  if (operate === "@") {
4711
4953
  hasAtRule = true;
4712
- funcSource += `'+$i($$ref,${content})+'`;
4954
+ funcSource += `'+$refFn($refAlt,${content})+'`;
4713
4955
  } else if (operate === "=" || operate === ":") {
4714
- funcSource += `'+$e(${content})+'`;
4956
+ funcSource += `'+$encHtml(${content})+'`;
4715
4957
  } else if (operate === "!") {
4716
- if (!content.startsWith("$eu(") || !content.endsWith(")")) {
4717
- content = `$n(${content})`;
4958
+ if (!content.startsWith("$encUri(") || !content.endsWith(")")) {
4959
+ content = `$strSafe(${content})`;
4718
4960
  }
4719
4961
  funcSource += `'+${content}+'`;
4720
4962
  } else if (content) {
@@ -4722,28 +4964,28 @@ function compileToFunction(source, debug, file) {
4722
4964
  if (funcSource.endsWith(`+'';`)) {
4723
4965
  funcSource = funcSource.substring(0, funcSource.length - 4) + ";";
4724
4966
  }
4725
- funcSource += `${content};$p+='`;
4967
+ funcSource += `${content};$out+='`;
4726
4968
  }
4727
4969
  }
4728
4970
  return match;
4729
4971
  });
4730
4972
  funcSource += `';`;
4731
- funcSource = funcSource.replace(/\$p\+='';/g, "");
4732
- funcSource = funcSource.replace(/\$p\+=''\+/g, "$p+=");
4973
+ funcSource = funcSource.replace(/\$out\+='';/g, "");
4974
+ funcSource = funcSource.replace(/\$out\+=''\+/g, "$out+=");
4733
4975
  if (debug) {
4734
4976
  const filePart = file ? `\\r\\n\\tat file:${file}` : "";
4735
- 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;}`;
4977
+ 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;}`;
4736
4978
  }
4737
4979
  const viewIdRegExp = new RegExp(String.fromCharCode(31), "g");
4738
4980
  funcSource = funcSource.replace(viewIdRegExp, `'+$viewId+'`);
4739
- 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;}}` : "";
4740
- 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)}`;
4741
- 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)}`;
4742
- const encodeQuote = `if(!$eq){let $qr=/['"\\\\]/g;$eq=v=>$n(v).replace($qr,'\\\\$&')}`;
4743
- const refFallback = "if(!$$ref)$$ref=$$;";
4981
+ 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;}}` : "";
4982
+ 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)}`;
4983
+ 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)}`;
4984
+ const encodeQuote = `if(!$encQuote){let $qReg=/['"\\\\]/g;$encQuote=v=>$strSafe(v).replace($qReg,'\\\\$&')}`;
4985
+ const refFallback = "if(!$refAlt)$refAlt=$data;";
4744
4986
  const fns = `${refFallback}${encode}${encodeURIMore}${encodeQuote}${atRule};`;
4745
- const fullSource = `${fns}let $g='\\x1e',$_temp,$p=''{{VARS}};${funcSource}return $p`;
4746
- return `($$,$viewId,$$ref,$e,$n,$eu,$i,$eq)=>{${fullSource}}`;
4987
+ const fullSource = `${fns}let $splitter='\\x1e',$tmp,$out=''{{VARS}};${funcSource}return $out`;
4988
+ return `($data,$viewId,$refAlt,$encHtml,$strSafe,$encUri,$refFn,$encQuote)=>{${fullSource}}`;
4747
4989
  }
4748
4990
  function compileTemplate(source, options = {}) {
4749
4991
  const { debug = false, globalVars = [], file } = options;
@@ -4752,17 +4994,17 @@ function compileTemplate(source, options = {}) {
4752
4994
  const viewEventProcessed = processViewEvents(converted);
4753
4995
  const finalSource = restoreComments(viewEventProcessed, comments);
4754
4996
  const funcBody = compileToFunction(finalSource, debug, file);
4755
- const varDeclarations = globalVars.map((key) => `,${key}=$$.${key}`).join("");
4997
+ const varDeclarations = globalVars.map((key) => `,${key}=$data.${key}`).join("");
4756
4998
  const funcWithVars = funcBody.replace("{{VARS}}", () => varDeclarations);
4757
4999
  return `export default function(data, selfId, refData) {
4758
- let $$ = data || {},
5000
+ let $data = data || {},
4759
5001
  $viewId = selfId || '';
4760
- return (${funcWithVars})($$, $viewId, refData,
4761
- /* $e */ v => String(v == null ? '' : v).replace(/[&<>"'\`]/g, m => '&' + ({'&':'amp','<':'lt','>':'gt','"':'#34',"'":'#39','\`':'#96'})[m] + ';'),
4762
- /* $n */ v => String(v == null ? '' : v),
4763
- /* $eu */ null,
4764
- /* $i */ null,
4765
- /* $eq */ null
5002
+ return (${funcWithVars})($data, $viewId, refData,
5003
+ /* $encHtml */ v => String(v == null ? '' : v).replace(/[&<>"'\`]/g, m => '&' + ({'&':'amp','<':'lt','>':'gt','"':'#34',"'":'#39','\`':'#96'})[m] + ';'),
5004
+ /* $strSafe */ v => String(v == null ? '' : v),
5005
+ /* $encUri */ null,
5006
+ /* $refFn */ null,
5007
+ /* $encQuote */ null
4766
5008
  );
4767
5009
  }`;
4768
5010
  }
@@ -4871,7 +5113,7 @@ function fallbackExtractVariables(source) {
4871
5113
  while ((m = outputRegExp.exec(source)) !== null) {
4872
5114
  vars.add(m[1]);
4873
5115
  }
4874
- const eachRegExp = /\{\{each\s+([a-zA-Z_$][\w$]*)\s+as/g;
5116
+ const eachRegExp = /\{\{forOf\s+([a-zA-Z_$][\w$]*)\s+as/g;
4875
5117
  while ((m = eachRegExp.exec(source)) !== null) {
4876
5118
  vars.add(m[1]);
4877
5119
  }
@@ -4917,77 +5159,88 @@ var BUILTIN_GLOBALS = {
4917
5159
  //
4918
5160
  // These variables appear in the generated template function signature
4919
5161
  // or body. They must be excluded from extractGlobalVars() so that
4920
- // they are not mistaken for user data variables and destructured from $$.
5162
+ // they are not mistaken for user data variables and destructured from $data.
4921
5163
  // SPLITTER character constant (same as \x1e), used as namespace separator
4922
5164
  // for refData keys, event attribute encoding, and internal data structures.
4923
- // Declared as: let $g='\x1e'
4924
- $g: 1,
4925
- // refData — the data object passed from Updater to the template function.
4926
- // User variables are destructured from $$ at the top of the function:
4927
- // let {name, age} = $$;
5165
+ // Declared as: let $splitter='\x1e'
5166
+ $splitter: 1,
5167
+ // Data — the data object passed from Updater to the template function.
5168
+ // User variables are destructured from $data at the top of the function:
5169
+ // let {name, age} = $data;
4928
5170
  // This is the first parameter of the generated arrow function.
4929
- $$: 1,
5171
+ $data: 1,
4930
5172
  // Null-safe toString: v => '' + (v == null ? '' : v)
4931
5173
  // Converts null/undefined to empty string, otherwise calls toString().
4932
5174
  // Wraps every {{!raw}} output to prevent "null" / "undefined" rendering.
4933
- $n: 1,
4934
- // HTML entity encoder: v => $n(v).replace(/[&<>"'`]/g, entityMap)
5175
+ $strSafe: 1,
5176
+ // HTML entity encoder: v => $strSafe(v).replace(/[&<>"'`]/g, entityMap)
4935
5177
  // Encodes &, <, >, ", ', ` to HTML entities (&amp; &lt; etc.)
4936
5178
  // Applied to all {{=escaped}} and {{:binding}} outputs.
4937
- $e: 1,
4938
- // HTML entity map — internal object used by $e:
5179
+ $encHtml: 1,
5180
+ // HTML entity map — internal object used by $encHtml:
4939
5181
  // {'&':'amp','<':'gt','>':'gt','"':'#34','\'':'#39','`':'#96'}
4940
- // Not a standalone function; referenced inside $e's closure.
4941
- $em: 1,
4942
- // HTML entity RegExp — internal regexp used by $e:
5182
+ // Not a standalone function; referenced inside $encHtml's closure.
5183
+ $entMap: 1,
5184
+ // HTML entity RegExp — internal regexp used by $encHtml:
4943
5185
  // /[&<>"'`]/g
4944
- $er: 1,
4945
- // HTML entity replacer function — internal helper used by $e:
4946
- // m => '&' + $em[m] + ';'
4947
- // Maps each matched character to its entity string.
4948
- $ef: 1,
5186
+ $entReg: 1,
5187
+ // HTML entity replacer function — internal helper used by $encHtml:
5188
+ // m => '&' + $entMap[m] + ';'
5189
+ // Maps matched character to its entity string.
5190
+ $entFn: 1,
4949
5191
  // Output buffer — the string accumulator for rendered HTML.
4950
- // All template output is appended via $p += '...'.
4951
- // Declared as: let $p = ''
4952
- $p: 1,
5192
+ // All template output is appended via $out += '...'.
5193
+ // Declared as: let $out = ''
5194
+ $out: 1,
4953
5195
  // Reference lookup: (refData, value) => key
4954
5196
  // Finds or allocates a SPLITTER-prefixed key in refData for a given
4955
5197
  // object reference. Used by {{@ref}} operator for passing object
4956
- // references to child views via lark-view attributes.
4957
- // Aligned with mx.js Updater_Ref.
4958
- $i: 1,
4959
- // URI encoder: v => encodeURIComponent($n(v)).replace(/[!')(*]/g, extraMap)
5198
+ // references to child views via v-lark attributes.
5199
+ $refFn: 1,
5200
+ // URI encoder: v => encodeURIComponent($strSafe(v)).replace(/[!')(*]/g, extraMap)
4960
5201
  // Extends encodeURIComponent with encoding of ! ' ( ) *.
4961
- // Applied to values in v-event URL parameters and {{!uri}} contexts.
4962
- $eu: 1,
4963
- // Quote encoder: v => $n(v).replace(/['"\\]/g, '\\$&')
5202
+ // Applied to values in @event URL parameters and {{!uri}} contexts.
5203
+ $encUri: 1,
5204
+ // URI encode map internal object used by $encUri:
5205
+ // {'!':'%21','\'':'%27','(':'%28',')':'%29','*':'%2A'}
5206
+ $uriMap: 1,
5207
+ // URI encode replacer — internal helper used by $encUri:
5208
+ // m => $uriMap[m]
5209
+ $uriFn: 1,
5210
+ // URI encode regexp — internal regexp used by $encUri:
5211
+ // /[!')(*]/g
5212
+ $uriReg: 1,
5213
+ // Quote encoder: v => $strSafe(v).replace(/['"\\]/g, '\\$&')
4964
5214
  // Escapes quotes and backslashes for safe embedding in HTML attribute
4965
5215
  // values (e.g. data-json='...').
4966
- $eq: 1,
5216
+ $encQuote: 1,
5217
+ // Quote encode regexp — internal regexp used by $encQuote:
5218
+ // /['"\\]/g
5219
+ $qReg: 1,
4967
5220
  // View ID — the unique identifier of the owning View instance.
4968
- // Injected into v-event attribute values at render time so that
5221
+ // Injected into @event attribute values at render time so that
4969
5222
  // EventDelegator can dispatch events to the correct View handler.
4970
5223
  // The \x1f placeholder in compiled output is replaced with '+$viewId+'.
4971
5224
  $viewId: 1,
4972
5225
  // Debug: current expression text — stores the template expression being
4973
5226
  // evaluated, for error reporting. Only present in debug mode.
4974
- // e.g. $expr='<%=user.name%>'
4975
- $expr: 1,
5227
+ // e.g. $dbgExpr='<%=user.name%>'
5228
+ $dbgExpr: 1,
4976
5229
  // Debug: original art syntax — stores the {{}} template syntax before
4977
5230
  // conversion, for error reporting. Only present in debug mode.
4978
- // e.g. $art='{{=user.name}}'
4979
- $art: 1,
5231
+ // e.g. $dbgArt='{{=user.name}}'
5232
+ $dbgArt: 1,
4980
5233
  // Debug: source line number — tracks the current line in the template
4981
5234
  // source, for error reporting. Only present in debug mode.
4982
- $line: 1,
4983
- // refData alias — fallback reference lookup table.
4984
- // Defaults to $$ when no explicit $$ref is provided.
4985
- // Ensures $i() does not crash when @ operator is used without refData.
4986
- $$ref: 1,
5235
+ $dbgLine: 1,
5236
+ // RefData alias — fallback reference lookup table.
5237
+ // Defaults to $data when no explicit $refAlt is provided.
5238
+ // Ensures $refFn() does not crash when @ operator is used without refData.
5239
+ $refAlt: 1,
4987
5240
  // Temporary variable — used by the compiler for intermediate
4988
5241
  // expression results in generated code (e.g. loop variables,
4989
- // conditional branches). Declared as: let $_temp
4990
- $_temp: 1,
5242
+ // conditional branches). Declared as: let $tmp
5243
+ $tmp: 1,
4991
5244
  // JS literals
4992
5245
  undefined: 1,
4993
5246
  null: 1,
@@ -5053,7 +5306,6 @@ var BUILTIN_GLOBALS = {
5053
5306
  var BUILTIN_GLOBAL_SET = new Set(Object.keys(BUILTIN_GLOBALS));
5054
5307
  // Annotate the CommonJS export names for ESM import in node:
5055
5308
  0 && (module.exports = {
5056
- Bag,
5057
5309
  CALL_BREAK_TIME,
5058
5310
  Cache,
5059
5311
  EVENT_METHOD_REGEXP,
@@ -5062,16 +5314,14 @@ var BUILTIN_GLOBAL_SET = new Set(Object.keys(BUILTIN_GLOBALS));
5062
5314
  Frame,
5063
5315
  Framework,
5064
5316
  LARK_VIEW,
5317
+ Payload,
5065
5318
  Platform,
5066
5319
  ROUTER_EVENTS,
5067
5320
  Router,
5068
5321
  SPLITTER,
5069
5322
  Service,
5070
5323
  State,
5071
- TAG_ATTR_KEY,
5072
- TAG_KEY,
5073
5324
  TAG_NAME_REGEXP,
5074
- TAG_VIEW_KEY,
5075
5325
  Updater,
5076
5326
  VIEW_EVENT_METHOD_REGEXP,
5077
5327
  View,
@@ -5102,7 +5352,7 @@ var BUILTIN_GLOBAL_SET = new Set(Object.keys(BUILTIN_GLOBALS));
5102
5352
  getStore,
5103
5353
  getUseStore,
5104
5354
  has,
5105
- isArray,
5355
+ installFrameVisualizerBridge,
5106
5356
  isPlainObject,
5107
5357
  isPrimitive,
5108
5358
  isPrimitiveOrFunc,
@@ -5122,6 +5372,7 @@ var BUILTIN_GLOBAL_SET = new Set(Object.keys(BUILTIN_GLOBALS));
5122
5372
  parseUri,
5123
5373
  registerViewClass,
5124
5374
  safeguard,
5375
+ serializeFrameTree,
5125
5376
  setData,
5126
5377
  shallowSet,
5127
5378
  storeMark,