tutuca 0.9.26 → 0.9.27

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.
@@ -739,13 +739,10 @@ class ValParser {
739
739
  switch (charCode) {
740
740
  case 94: {
741
741
  const newS = px.frame.macroVars?.[s.slice(1)];
742
- if (newS !== undefined) {
742
+ if (newS !== undefined)
743
743
  return this.parse(newS, px);
744
- }
745
744
  return null;
746
745
  }
747
- case 126:
748
- return this.okStrTpl ? parseConst(s.slice(1), px) : null;
749
746
  case 39:
750
747
  return this.okStrTpl ? parseConst(s.slice(1, -1), px) : null;
751
748
  case 64:
@@ -858,7 +855,7 @@ function getValSubType(s) {
858
855
  return open === 1 && close === 1 ? VAL_SUB_TYPE_SEQ_ACCESS : VAL_SUB_TYPE_INVALID;
859
856
  return -1;
860
857
  }
861
- var VALID_VAL_ID_RE, isValidValId = (name) => VALID_VAL_ID_RE.test(name), VALID_FLOAT_RE, parseStrTemplate = (v, px) => StrTplVal.parse(v, px), parseConst = (v, _) => new ConstVal(v), parseName = (v, _) => isValidValId(v) ? new NameVal(v) : null, parseType = (v, _) => isValidValId(v) ? new TypeVal(v) : null, parseBind = (v, _) => isValidValId(v) ? new BindVal(v) : null, parseDyn = (v, _) => isValidValId(v) ? new DynVal(v) : null, parseField = (v, _) => isValidValId(v) ? new FieldVal(v) : null, parseComp = (v, _) => isValidValId(v) ? new ComputedVal(v) : null, parseReq = (v, _) => isValidValId(v) ? new RequestVal(v) : null, ConstVal, VarVal, StrTplVal, NameVal, InputHandlerNameVal, AlterHandlerNameVal, mk404Handler = (type, name) => function(...args) {
858
+ var VALID_VAL_ID_RE, isValidValId = (name) => VALID_VAL_ID_RE.test(name), VALID_FLOAT_RE, STR_TPL_SPLIT_RE, parseStrTemplate = (v, px) => StrTplVal.parse(v, px), parseConst = (v, _) => new ConstVal(v), parseName = (v, _) => isValidValId(v) ? new NameVal(v) : null, parseType = (v, _) => isValidValId(v) ? new TypeVal(v) : null, parseBind = (v, _) => isValidValId(v) ? new BindVal(v) : null, parseDyn = (v, _) => isValidValId(v) ? new DynVal(v) : null, parseField = (v, _) => isValidValId(v) ? new FieldVal(v) : null, parseComp = (v, _) => isValidValId(v) ? new ComputedVal(v) : null, parseReq = (v, _) => isValidValId(v) ? new RequestVal(v) : null, ConstVal, VarVal, StrTplVal, NameVal, InputHandlerNameVal, AlterHandlerNameVal, mk404Handler = (type, name) => function(...args) {
862
859
  console.warn("handler not found", { type, name, args }, this);
863
860
  return this;
864
861
  }, TypeVal, RequestVal, RawFieldVal, RenderVal, RenderNameVal, BindVal, DynVal, FieldVal, ComputedVal, SeqAccessVal, VAL_SUB_TYPE_STRING_TEMPLATE = 0, VAL_SUB_TYPE_SEQ_ACCESS = 1, VAL_SUB_TYPE_INVALID = 2, VAL_SUB_TYPE_CONST_STRING = 3, vp;
@@ -866,6 +863,7 @@ var init_value = __esm(() => {
866
863
  init_path();
867
864
  VALID_VAL_ID_RE = /^[a-zA-Z][a-zA-Z0-9_]*$/;
868
865
  VALID_FLOAT_RE = /^-?[0-9]+(\.[0-9]+)?$/;
866
+ STR_TPL_SPLIT_RE = /(\{[^}]+\})/g;
869
867
  ConstVal = class ConstVal extends BaseVal {
870
868
  constructor(val) {
871
869
  super();
@@ -899,7 +897,7 @@ var init_value = __esm(() => {
899
897
  return strs.join("");
900
898
  }
901
899
  static parse(s, px) {
902
- const parts = s.split(/(\{[^}]+\})/g);
900
+ const parts = s.split(STR_TPL_SPLIT_RE);
903
901
  const vals = new Array(parts.length);
904
902
  let allConsts = true;
905
903
  for (let i = 0;i < parts.length; i++) {
@@ -1333,9 +1331,8 @@ function optimizeChilds(childs) {
1333
1331
  }
1334
1332
  }
1335
1333
  function optimizeNode(node) {
1336
- if (node.isConstant()) {
1334
+ if (node.isConstant())
1337
1335
  return new RenderOnceNode(node);
1338
- }
1339
1336
  node.optimize();
1340
1337
  return node;
1341
1338
  }
@@ -1401,12 +1398,6 @@ class ParseContext {
1401
1398
  newDOMParser() {
1402
1399
  return new this.DOMParser;
1403
1400
  }
1404
- isTextNode(v) {
1405
- return v instanceof this.Text;
1406
- }
1407
- isCommentNode(v) {
1408
- return v instanceof this.Comment;
1409
- }
1410
1401
  addNodeIf(Class, val, extra) {
1411
1402
  if (val !== null) {
1412
1403
  const nodeId = this.nodes.length;
@@ -1425,21 +1416,18 @@ class ParseContext {
1425
1416
  newMacroNode(macroName, mAttrs, childs) {
1426
1417
  const anySlot = [];
1427
1418
  const slots = { _: new FragmentNode(anySlot) };
1428
- for (const child of childs) {
1429
- if (child instanceof SlotNode) {
1419
+ for (const child of childs)
1420
+ if (child instanceof SlotNode)
1430
1421
  slots[child.val.val] = child.node;
1431
- } else if (!(child instanceof TextNode) || !child.isWhiteSpace()) {
1422
+ else if (!(child instanceof TextNode) || !child.isWhiteSpace())
1432
1423
  anySlot.push(child);
1433
- }
1434
- }
1435
1424
  const node = new MacroNode(macroName, mAttrs, slots, this);
1436
1425
  this.macroNodes.push(node);
1437
1426
  return node;
1438
1427
  }
1439
1428
  compile(scope) {
1440
- for (let i = 0;i < this.macroNodes.length; i++) {
1429
+ for (let i = 0;i < this.macroNodes.length; i++)
1441
1430
  this.macroNodes[i].compile(scope);
1442
- }
1443
1431
  }
1444
1432
  *genEventNames() {
1445
1433
  for (const event of this.events)
@@ -1490,12 +1478,11 @@ class NodeEvents {
1490
1478
  }
1491
1479
  getHandlersFor(eventName) {
1492
1480
  let r = null;
1493
- for (const handler of this.handlers) {
1481
+ for (const handler of this.handlers)
1494
1482
  if (handler.handlesEventName(eventName)) {
1495
1483
  r ??= [];
1496
1484
  r.push(handler);
1497
1485
  }
1498
- }
1499
1486
  return r;
1500
1487
  }
1501
1488
  }
@@ -1629,9 +1616,9 @@ var init_anode = __esm(() => {
1629
1616
  return ANode.fromDOM(nodes[0] ?? new px.Text(""), px);
1630
1617
  }
1631
1618
  static fromDOM(node, px) {
1632
- if (px.isTextNode(node))
1619
+ if (node instanceof px.Text)
1633
1620
  return new TextNode(node.textContent);
1634
- else if (px.isCommentNode(node))
1621
+ else if (node instanceof px.Comment)
1635
1622
  return new CommentNode(node.textContent);
1636
1623
  const { childNodes, attributes: attrs, tagName: tag } = node;
1637
1624
  const childs = new Array(childNodes.length);
@@ -1697,9 +1684,9 @@ var init_anode = __esm(() => {
1697
1684
  if (this.px.isInsideMacro(name))
1698
1685
  throw new Error(`Recursive macro expansion: ${name}`);
1699
1686
  const macro = scope.lookupMacro(name);
1700
- if (macro === null) {
1687
+ if (macro === null)
1701
1688
  this.node = new CommentNode(`bad macro: ${name}`);
1702
- } else {
1689
+ else {
1703
1690
  const vars = { ...macro.defaults, ...attrs };
1704
1691
  this.node = macro.expand(this.px.enterMacro(name, vars, slots));
1705
1692
  for (const key in this.dataAttrs)
@@ -1870,10 +1857,8 @@ var init_anode = __esm(() => {
1870
1857
 
1871
1858
  // src/cache.js
1872
1859
  class NullDomCache {
1873
- get(_k, _cacheKey) {}
1874
- set(_k, _cacheKey, _v) {}
1875
- get2(_k1, _k2, _cacheKey) {}
1876
- set2(_k1, _k2, _cacheKey, _v) {}
1860
+ get(_keys, _cacheKey) {}
1861
+ set(_keys, _cacheKey, _v) {}
1877
1862
  evict() {
1878
1863
  return { hit: 0, miss: 0, badKey: 0 };
1879
1864
  }
@@ -1882,7 +1867,7 @@ class NullDomCache {
1882
1867
  class WeakMapDomCache {
1883
1868
  constructor() {
1884
1869
  this.hit = this.miss = this.badKey = 0;
1885
- this.map = new WeakMap;
1870
+ this.keysByLen = new Map;
1886
1871
  }
1887
1872
  _returnValue(r) {
1888
1873
  if (r === undefined)
@@ -1891,41 +1876,51 @@ class WeakMapDomCache {
1891
1876
  this.hit += 1;
1892
1877
  return r;
1893
1878
  }
1894
- get(k, cacheKey) {
1895
- return this._returnValue(this.map.get(k)?.[cacheKey]);
1896
- }
1897
- set(k, cacheKey, v) {
1898
- const cur = this.map.get(k);
1899
- if (cur)
1900
- cur[cacheKey] = v;
1901
- else if (typeof k === "object")
1902
- this.map.set(k, { [cacheKey]: v });
1879
+ get(keys, cacheKey) {
1880
+ const len = keys.length;
1881
+ let cur = this.keysByLen.get(len);
1882
+ if (!cur)
1883
+ return this._returnValue(undefined);
1884
+ for (let i = 0;i < len - 1; i++) {
1885
+ cur = cur.get(keys[i]);
1886
+ if (!cur)
1887
+ return this._returnValue(undefined);
1888
+ }
1889
+ return this._returnValue(cur.get(keys[len - 1])?.[cacheKey]);
1890
+ }
1891
+ set(keys, cacheKey, v) {
1892
+ const len = keys.length;
1893
+ let cur = this.keysByLen.get(len);
1894
+ if (!cur) {
1895
+ cur = new WeakMap;
1896
+ this.keysByLen.set(len, cur);
1897
+ }
1898
+ for (let i = 0;i < len - 1; i++) {
1899
+ const key = keys[i];
1900
+ let next = cur.get(key);
1901
+ if (!next) {
1902
+ if (typeof key !== "object") {
1903
+ this.badKey += 1;
1904
+ return;
1905
+ }
1906
+ next = new WeakMap;
1907
+ cur.set(key, next);
1908
+ }
1909
+ cur = next;
1910
+ }
1911
+ const lastKey = keys[len - 1];
1912
+ const leaf = cur.get(lastKey);
1913
+ if (leaf)
1914
+ leaf[cacheKey] = v;
1915
+ else if (typeof lastKey === "object")
1916
+ cur.set(lastKey, { [cacheKey]: v });
1903
1917
  else
1904
1918
  this.badKey += 1;
1905
1919
  }
1906
- get2(k1, k2, cacheKey) {
1907
- return this._returnValue(this.map.get(k1)?.get?.(k2)?.[cacheKey]);
1908
- }
1909
- set2(k1, k2, cacheKey, v) {
1910
- const cur1 = this.map.get(k1);
1911
- if (cur1) {
1912
- const cur = cur1.get(k2);
1913
- if (cur)
1914
- cur[cacheKey] = v;
1915
- else
1916
- cur1.set(k2, { [cacheKey]: v });
1917
- } else if (typeof k1 === "object" && typeof k2 === "object") {
1918
- const cur = new WeakMap;
1919
- cur.set(k2, { [cacheKey]: v });
1920
- this.map.set(k1, cur);
1921
- } else {
1922
- this.badKey += 1;
1923
- }
1924
- }
1925
1920
  evict() {
1926
1921
  const { hit, miss, badKey } = this;
1927
1922
  this.hit = this.miss = this.badKey = 0;
1928
- this.map = new WeakMap;
1923
+ this.keysByLen = new Map;
1929
1924
  return { hit, miss, badKey };
1930
1925
  }
1931
1926
  }
@@ -2047,8 +2042,8 @@ class ComponentStack {
2047
2042
  return this.macros[name] ?? this.parent?.lookupMacro(name) ?? null;
2048
2043
  }
2049
2044
  }
2050
- function defaultOnStackEnter(stack) {
2051
- return stack;
2045
+ function defaultOnStackEnter() {
2046
+ return null;
2052
2047
  }
2053
2048
  var init_components = __esm(() => {
2054
2049
  init_attribute();
@@ -2466,7 +2461,7 @@ class Stack {
2466
2461
  this.ctx = ctx;
2467
2462
  }
2468
2463
  _enrichOnEnter() {
2469
- return this.comps.getOnEnterFor(this.it).call(this.it, this) ?? this;
2464
+ return this.withDynamicBindings(this.comps.getOnEnterFor(this.it).call(this.it));
2470
2465
  }
2471
2466
  upToFrameBinds() {
2472
2467
  const { comps, binds, dynBinds, views, viewsId, ctx } = this;
@@ -2481,7 +2476,8 @@ class Stack {
2481
2476
  enter(it, bindings = {}, isFrame = true) {
2482
2477
  const { comps, binds, dynBinds, views, viewsId, ctx } = this;
2483
2478
  const newBinds = [new BindFrame(it, bindings, isFrame), binds];
2484
- return new Stack(comps, it, newBinds, dynBinds, views, viewsId, ctx)._enrichOnEnter();
2479
+ const stack = new Stack(comps, it, newBinds, dynBinds, views, viewsId, ctx);
2480
+ return isFrame ? stack._enrichOnEnter() : stack;
2485
2481
  }
2486
2482
  pushViewName(name) {
2487
2483
  const { comps, it, binds, dynBinds, views, ctx } = this;
@@ -2489,17 +2485,26 @@ class Stack {
2489
2485
  return new Stack(comps, it, binds, dynBinds, newViews, computeViewsId(newViews), ctx);
2490
2486
  }
2491
2487
  withDynamicBindings(dynamics) {
2488
+ if (dynamics == null || dynamics.length === 0)
2489
+ return this;
2492
2490
  const dynObj = {};
2493
2491
  const comp = this.comps.getCompFor(this.it);
2494
2492
  for (const dynName of dynamics)
2495
2493
  comp.dynamic[dynName].evalAndBind(this, dynObj);
2496
- const { comps, it, binds, views, viewsId, ctx } = this;
2497
2494
  const newDynBinds = [new ObjectFrame(dynObj), this.dynBinds];
2495
+ const { comps, it, binds, views, viewsId, ctx } = this;
2498
2496
  return new Stack(comps, it, binds, newDynBinds, views, viewsId, ctx);
2499
2497
  }
2498
+ _pushDynBindValuesToArray(arr, dyns) {
2499
+ for (const k in dyns)
2500
+ arr.push(this._lookupDynamicWithDynVal(dyns[k]));
2501
+ }
2502
+ _lookupDynamicWithDynVal(d) {
2503
+ return lookup(this.dynBinds, d.getSymbol(this)) ?? d.val.eval(this);
2504
+ }
2500
2505
  lookupDynamic(name) {
2501
2506
  const d = this.comps.getCompFor(this.it)?.dynamic[name];
2502
- return d ? lookup(this.dynBinds, d.getSymbol(this)) ?? d.val.eval(this) : null;
2507
+ return d ? this._lookupDynamicWithDynVal(d) : null;
2503
2508
  }
2504
2509
  lookupBind(name) {
2505
2510
  return lookup(this.binds, name);
@@ -7740,13 +7745,15 @@ class Renderer {
7740
7745
  }
7741
7746
  _rValComp(stack, val, comp, nid, key, viewName) {
7742
7747
  const cacheKey = `${viewName ?? stack.viewsId ?? ""}${nid}-${key}`;
7743
- const cachedNode = this.cache.get(val, cacheKey);
7748
+ const cachePath = [val];
7749
+ stack._pushDynBindValuesToArray(cachePath, comp.dynamic);
7750
+ const cachedNode = this.cache.get(cachePath, cacheKey);
7744
7751
  if (cachedNode)
7745
7752
  return cachedNode;
7746
7753
  const view = viewName ? comp.getView(viewName) : stack.lookupBestView(comp.views, "main");
7747
7754
  const meta = this._renderMetadata({ $: "Comp", nid });
7748
7755
  const dom = new VFragment([meta, this.renderView(view, stack)]);
7749
- this.cache.set(val, cacheKey, dom);
7756
+ this.cache.set(cachePath, cacheKey, dom);
7750
7757
  return dom;
7751
7758
  }
7752
7759
  pushEachEntry(r, nid, attrName, key, dom) {
@@ -7758,8 +7765,7 @@ class Renderer {
7758
7765
  const iterData = loopWith.call(stack.it, seq);
7759
7766
  this.getSeqInfo(seq)(seq, (key, value, attrName) => {
7760
7767
  if (filter.call(stack.it, key, value, iterData)) {
7761
- const newStack = stack.enter(value, { key }, true);
7762
- const dom = this.renderIt(newStack, nodeId, key, viewName);
7768
+ const dom = this.renderIt(stack.enter(value, { key }, true), nodeId, key, viewName);
7763
7769
  this.pushEachEntry(r, nodeId, attrName, key, dom);
7764
7770
  }
7765
7771
  });
@@ -7772,25 +7778,19 @@ class Renderer {
7772
7778
  const it = stack.it;
7773
7779
  this.getSeqInfo(seq)(seq, (key, value, attrName) => {
7774
7780
  if (filter.call(it, key, value, iterData)) {
7781
+ const cachePath = enricher ? [it, value] : [value];
7775
7782
  const bindings = { key, value };
7776
7783
  const cacheKey = `${nid}-${key}`;
7777
- let cachedNode;
7778
- if (enricher) {
7784
+ if (enricher)
7779
7785
  enricher.call(it, bindings, key, value, iterData);
7780
- cachedNode = this.cache.get2(it, value, cacheKey);
7781
- } else
7782
- cachedNode = this.cache.get(value, cacheKey);
7783
- if (cachedNode) {
7786
+ const cachedNode = this.cache.get(cachePath, cacheKey);
7787
+ if (cachedNode)
7784
7788
  this.pushEachEntry(r, nid, attrName, key, cachedNode);
7785
- return;
7789
+ else {
7790
+ const dom = this.renderView(view, stack.enter(value, bindings, false));
7791
+ this.pushEachEntry(r, nid, attrName, key, dom);
7792
+ this.cache.set(cachePath, cacheKey, dom);
7786
7793
  }
7787
- const newStack = stack.enter(value, bindings, false);
7788
- const dom = this.renderView(view, newStack);
7789
- this.pushEachEntry(r, nid, attrName, key, dom);
7790
- if (enricher)
7791
- this.cache.set2(it, value, cacheKey, dom);
7792
- else
7793
- this.cache.set(value, cacheKey, dom);
7794
7794
  }
7795
7795
  });
7796
7796
  return r;
@@ -245,6 +245,7 @@ class PathBuilder {
245
245
  var VALID_VAL_ID_RE = /^[a-zA-Z][a-zA-Z0-9_]*$/;
246
246
  var isValidValId = (name) => VALID_VAL_ID_RE.test(name);
247
247
  var VALID_FLOAT_RE = /^-?[0-9]+(\.[0-9]+)?$/;
248
+ var STR_TPL_SPLIT_RE = /(\{[^}]+\})/g;
248
249
  var parseStrTemplate = (v, px) => StrTplVal.parse(v, px);
249
250
  var parseConst = (v, _) => new ConstVal(v);
250
251
  var parseName = (v, _) => isValidValId(v) ? new NameVal(v) : null;
@@ -293,13 +294,10 @@ class ValParser {
293
294
  switch (charCode) {
294
295
  case 94: {
295
296
  const newS = px.frame.macroVars?.[s.slice(1)];
296
- if (newS !== undefined) {
297
+ if (newS !== undefined)
297
298
  return this.parse(newS, px);
298
- }
299
299
  return null;
300
300
  }
301
- case 126:
302
- return this.okStrTpl ? parseConst(s.slice(1), px) : null;
303
301
  case 39:
304
302
  return this.okStrTpl ? parseConst(s.slice(1, -1), px) : null;
305
303
  case 64:
@@ -423,7 +421,7 @@ class StrTplVal extends VarVal {
423
421
  return strs.join("");
424
422
  }
425
423
  static parse(s, px) {
426
- const parts = s.split(/(\{[^}]+\})/g);
424
+ const parts = s.split(STR_TPL_SPLIT_RE);
427
425
  const vals = new Array(parts.length);
428
426
  let allConsts = true;
429
427
  for (let i = 0;i < parts.length; i++) {
@@ -944,9 +942,8 @@ function optimizeChilds(childs) {
944
942
  }
945
943
  }
946
944
  function optimizeNode(node) {
947
- if (node.isConstant()) {
945
+ if (node.isConstant())
948
946
  return new RenderOnceNode(node);
949
- }
950
947
  node.optimize();
951
948
  return node;
952
949
  }
@@ -1013,9 +1010,9 @@ class ANode extends BaseNode {
1013
1010
  return ANode.fromDOM(nodes[0] ?? new px.Text(""), px);
1014
1011
  }
1015
1012
  static fromDOM(node, px) {
1016
- if (px.isTextNode(node))
1013
+ if (node instanceof px.Text)
1017
1014
  return new TextNode(node.textContent);
1018
- else if (px.isCommentNode(node))
1015
+ else if (node instanceof px.Comment)
1019
1016
  return new CommentNode(node.textContent);
1020
1017
  const { childNodes, attributes: attrs, tagName: tag } = node;
1021
1018
  const childs = new Array(childNodes.length);
@@ -1104,9 +1101,9 @@ class MacroNode extends BaseNode {
1104
1101
  if (this.px.isInsideMacro(name))
1105
1102
  throw new Error(`Recursive macro expansion: ${name}`);
1106
1103
  const macro = scope.lookupMacro(name);
1107
- if (macro === null) {
1104
+ if (macro === null)
1108
1105
  this.node = new CommentNode(`bad macro: ${name}`);
1109
- } else {
1106
+ else {
1110
1107
  const vars = { ...macro.defaults, ...attrs };
1111
1108
  this.node = macro.expand(this.px.enterMacro(name, vars, slots));
1112
1109
  for (const key in this.dataAttrs)
@@ -1325,12 +1322,6 @@ class ParseContext {
1325
1322
  newDOMParser() {
1326
1323
  return new this.DOMParser;
1327
1324
  }
1328
- isTextNode(v) {
1329
- return v instanceof this.Text;
1330
- }
1331
- isCommentNode(v) {
1332
- return v instanceof this.Comment;
1333
- }
1334
1325
  addNodeIf(Class, val, extra) {
1335
1326
  if (val !== null) {
1336
1327
  const nodeId = this.nodes.length;
@@ -1349,21 +1340,18 @@ class ParseContext {
1349
1340
  newMacroNode(macroName, mAttrs, childs) {
1350
1341
  const anySlot = [];
1351
1342
  const slots = { _: new FragmentNode(anySlot) };
1352
- for (const child of childs) {
1353
- if (child instanceof SlotNode) {
1343
+ for (const child of childs)
1344
+ if (child instanceof SlotNode)
1354
1345
  slots[child.val.val] = child.node;
1355
- } else if (!(child instanceof TextNode) || !child.isWhiteSpace()) {
1346
+ else if (!(child instanceof TextNode) || !child.isWhiteSpace())
1356
1347
  anySlot.push(child);
1357
- }
1358
- }
1359
1348
  const node = new MacroNode(macroName, mAttrs, slots, this);
1360
1349
  this.macroNodes.push(node);
1361
1350
  return node;
1362
1351
  }
1363
1352
  compile(scope) {
1364
- for (let i = 0;i < this.macroNodes.length; i++) {
1353
+ for (let i = 0;i < this.macroNodes.length; i++)
1365
1354
  this.macroNodes[i].compile(scope);
1366
- }
1367
1355
  }
1368
1356
  *genEventNames() {
1369
1357
  for (const event of this.events)
@@ -1438,12 +1426,11 @@ class NodeEvents {
1438
1426
  }
1439
1427
  getHandlersFor(eventName) {
1440
1428
  let r = null;
1441
- for (const handler of this.handlers) {
1429
+ for (const handler of this.handlers)
1442
1430
  if (handler.handlesEventName(eventName)) {
1443
1431
  r ??= [];
1444
1432
  r.push(handler);
1445
1433
  }
1446
- }
1447
1434
  return r;
1448
1435
  }
1449
1436
  }
@@ -1942,10 +1929,8 @@ function lintIdToMessage(id, info) {
1942
1929
 
1943
1930
  // src/cache.js
1944
1931
  class NullDomCache {
1945
- get(_k, _cacheKey) {}
1946
- set(_k, _cacheKey, _v) {}
1947
- get2(_k1, _k2, _cacheKey) {}
1948
- set2(_k1, _k2, _cacheKey, _v) {}
1932
+ get(_keys, _cacheKey) {}
1933
+ set(_keys, _cacheKey, _v) {}
1949
1934
  evict() {
1950
1935
  return { hit: 0, miss: 0, badKey: 0 };
1951
1936
  }
@@ -1954,7 +1939,7 @@ class NullDomCache {
1954
1939
  class WeakMapDomCache {
1955
1940
  constructor() {
1956
1941
  this.hit = this.miss = this.badKey = 0;
1957
- this.map = new WeakMap;
1942
+ this.keysByLen = new Map;
1958
1943
  }
1959
1944
  _returnValue(r) {
1960
1945
  if (r === undefined)
@@ -1963,41 +1948,51 @@ class WeakMapDomCache {
1963
1948
  this.hit += 1;
1964
1949
  return r;
1965
1950
  }
1966
- get(k, cacheKey) {
1967
- return this._returnValue(this.map.get(k)?.[cacheKey]);
1968
- }
1969
- set(k, cacheKey, v) {
1970
- const cur = this.map.get(k);
1971
- if (cur)
1972
- cur[cacheKey] = v;
1973
- else if (typeof k === "object")
1974
- this.map.set(k, { [cacheKey]: v });
1951
+ get(keys, cacheKey) {
1952
+ const len = keys.length;
1953
+ let cur = this.keysByLen.get(len);
1954
+ if (!cur)
1955
+ return this._returnValue(undefined);
1956
+ for (let i = 0;i < len - 1; i++) {
1957
+ cur = cur.get(keys[i]);
1958
+ if (!cur)
1959
+ return this._returnValue(undefined);
1960
+ }
1961
+ return this._returnValue(cur.get(keys[len - 1])?.[cacheKey]);
1962
+ }
1963
+ set(keys, cacheKey, v) {
1964
+ const len = keys.length;
1965
+ let cur = this.keysByLen.get(len);
1966
+ if (!cur) {
1967
+ cur = new WeakMap;
1968
+ this.keysByLen.set(len, cur);
1969
+ }
1970
+ for (let i = 0;i < len - 1; i++) {
1971
+ const key = keys[i];
1972
+ let next = cur.get(key);
1973
+ if (!next) {
1974
+ if (typeof key !== "object") {
1975
+ this.badKey += 1;
1976
+ return;
1977
+ }
1978
+ next = new WeakMap;
1979
+ cur.set(key, next);
1980
+ }
1981
+ cur = next;
1982
+ }
1983
+ const lastKey = keys[len - 1];
1984
+ const leaf = cur.get(lastKey);
1985
+ if (leaf)
1986
+ leaf[cacheKey] = v;
1987
+ else if (typeof lastKey === "object")
1988
+ cur.set(lastKey, { [cacheKey]: v });
1975
1989
  else
1976
1990
  this.badKey += 1;
1977
1991
  }
1978
- get2(k1, k2, cacheKey) {
1979
- return this._returnValue(this.map.get(k1)?.get?.(k2)?.[cacheKey]);
1980
- }
1981
- set2(k1, k2, cacheKey, v) {
1982
- const cur1 = this.map.get(k1);
1983
- if (cur1) {
1984
- const cur = cur1.get(k2);
1985
- if (cur)
1986
- cur[cacheKey] = v;
1987
- else
1988
- cur1.set(k2, { [cacheKey]: v });
1989
- } else if (typeof k1 === "object" && typeof k2 === "object") {
1990
- const cur = new WeakMap;
1991
- cur.set(k2, { [cacheKey]: v });
1992
- this.map.set(k1, cur);
1993
- } else {
1994
- this.badKey += 1;
1995
- }
1996
- }
1997
1992
  evict() {
1998
1993
  const { hit, miss, badKey } = this;
1999
1994
  this.hit = this.miss = this.badKey = 0;
2000
- this.map = new WeakMap;
1995
+ this.keysByLen = new Map;
2001
1996
  return { hit, miss, badKey };
2002
1997
  }
2003
1998
  }
@@ -2219,8 +2214,8 @@ class Component {
2219
2214
  `);
2220
2215
  }
2221
2216
  }
2222
- function defaultOnStackEnter(stack) {
2223
- return stack;
2217
+ function defaultOnStackEnter() {
2218
+ return null;
2224
2219
  }
2225
2220
 
2226
2221
  // src/stack.js
@@ -2281,7 +2276,7 @@ class Stack {
2281
2276
  this.ctx = ctx;
2282
2277
  }
2283
2278
  _enrichOnEnter() {
2284
- return this.comps.getOnEnterFor(this.it).call(this.it, this) ?? this;
2279
+ return this.withDynamicBindings(this.comps.getOnEnterFor(this.it).call(this.it));
2285
2280
  }
2286
2281
  upToFrameBinds() {
2287
2282
  const { comps, binds, dynBinds, views, viewsId, ctx } = this;
@@ -2296,7 +2291,8 @@ class Stack {
2296
2291
  enter(it, bindings = {}, isFrame = true) {
2297
2292
  const { comps, binds, dynBinds, views, viewsId, ctx } = this;
2298
2293
  const newBinds = [new BindFrame(it, bindings, isFrame), binds];
2299
- return new Stack(comps, it, newBinds, dynBinds, views, viewsId, ctx)._enrichOnEnter();
2294
+ const stack = new Stack(comps, it, newBinds, dynBinds, views, viewsId, ctx);
2295
+ return isFrame ? stack._enrichOnEnter() : stack;
2300
2296
  }
2301
2297
  pushViewName(name) {
2302
2298
  const { comps, it, binds, dynBinds, views, ctx } = this;
@@ -2304,17 +2300,26 @@ class Stack {
2304
2300
  return new Stack(comps, it, binds, dynBinds, newViews, computeViewsId(newViews), ctx);
2305
2301
  }
2306
2302
  withDynamicBindings(dynamics) {
2303
+ if (dynamics == null || dynamics.length === 0)
2304
+ return this;
2307
2305
  const dynObj = {};
2308
2306
  const comp = this.comps.getCompFor(this.it);
2309
2307
  for (const dynName of dynamics)
2310
2308
  comp.dynamic[dynName].evalAndBind(this, dynObj);
2311
- const { comps, it, binds, views, viewsId, ctx } = this;
2312
2309
  const newDynBinds = [new ObjectFrame(dynObj), this.dynBinds];
2310
+ const { comps, it, binds, views, viewsId, ctx } = this;
2313
2311
  return new Stack(comps, it, binds, newDynBinds, views, viewsId, ctx);
2314
2312
  }
2313
+ _pushDynBindValuesToArray(arr, dyns) {
2314
+ for (const k in dyns)
2315
+ arr.push(this._lookupDynamicWithDynVal(dyns[k]));
2316
+ }
2317
+ _lookupDynamicWithDynVal(d) {
2318
+ return lookup(this.dynBinds, d.getSymbol(this)) ?? d.val.eval(this);
2319
+ }
2315
2320
  lookupDynamic(name) {
2316
2321
  const d = this.comps.getCompFor(this.it)?.dynamic[name];
2317
- return d ? lookup(this.dynBinds, d.getSymbol(this)) ?? d.val.eval(this) : null;
2322
+ return d ? this._lookupDynamicWithDynVal(d) : null;
2318
2323
  }
2319
2324
  lookupBind(name) {
2320
2325
  return lookup(this.binds, name);
@@ -8112,13 +8117,15 @@ class Renderer {
8112
8117
  }
8113
8118
  _rValComp(stack, val, comp, nid, key, viewName) {
8114
8119
  const cacheKey = `${viewName ?? stack.viewsId ?? ""}${nid}-${key}`;
8115
- const cachedNode = this.cache.get(val, cacheKey);
8120
+ const cachePath = [val];
8121
+ stack._pushDynBindValuesToArray(cachePath, comp.dynamic);
8122
+ const cachedNode = this.cache.get(cachePath, cacheKey);
8116
8123
  if (cachedNode)
8117
8124
  return cachedNode;
8118
8125
  const view = viewName ? comp.getView(viewName) : stack.lookupBestView(comp.views, "main");
8119
8126
  const meta = this._renderMetadata({ $: "Comp", nid });
8120
8127
  const dom = new VFragment([meta, this.renderView(view, stack)]);
8121
- this.cache.set(val, cacheKey, dom);
8128
+ this.cache.set(cachePath, cacheKey, dom);
8122
8129
  return dom;
8123
8130
  }
8124
8131
  pushEachEntry(r, nid, attrName, key, dom) {
@@ -8130,8 +8137,7 @@ class Renderer {
8130
8137
  const iterData = loopWith.call(stack.it, seq);
8131
8138
  this.getSeqInfo(seq)(seq, (key, value, attrName) => {
8132
8139
  if (filter.call(stack.it, key, value, iterData)) {
8133
- const newStack = stack.enter(value, { key }, true);
8134
- const dom = this.renderIt(newStack, nodeId, key, viewName);
8140
+ const dom = this.renderIt(stack.enter(value, { key }, true), nodeId, key, viewName);
8135
8141
  this.pushEachEntry(r, nodeId, attrName, key, dom);
8136
8142
  }
8137
8143
  });
@@ -8144,25 +8150,19 @@ class Renderer {
8144
8150
  const it = stack.it;
8145
8151
  this.getSeqInfo(seq)(seq, (key, value, attrName) => {
8146
8152
  if (filter.call(it, key, value, iterData)) {
8153
+ const cachePath = enricher ? [it, value] : [value];
8147
8154
  const bindings = { key, value };
8148
8155
  const cacheKey = `${nid}-${key}`;
8149
- let cachedNode;
8150
- if (enricher) {
8156
+ if (enricher)
8151
8157
  enricher.call(it, bindings, key, value, iterData);
8152
- cachedNode = this.cache.get2(it, value, cacheKey);
8153
- } else
8154
- cachedNode = this.cache.get(value, cacheKey);
8155
- if (cachedNode) {
8158
+ const cachedNode = this.cache.get(cachePath, cacheKey);
8159
+ if (cachedNode)
8156
8160
  this.pushEachEntry(r, nid, attrName, key, cachedNode);
8157
- return;
8161
+ else {
8162
+ const dom = this.renderView(view, stack.enter(value, bindings, false));
8163
+ this.pushEachEntry(r, nid, attrName, key, dom);
8164
+ this.cache.set(cachePath, cacheKey, dom);
8158
8165
  }
8159
- const newStack = stack.enter(value, bindings, false);
8160
- const dom = this.renderView(view, newStack);
8161
- this.pushEachEntry(r, nid, attrName, key, dom);
8162
- if (enricher)
8163
- this.cache.set2(it, value, cacheKey, dom);
8164
- else
8165
- this.cache.set(value, cacheKey, dom);
8166
8166
  }
8167
8167
  });
8168
8168
  return r;