tutuca 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4982,9 +4982,6 @@ var Step = class {
4982
4982
  lookup(_v, dval = null) {
4983
4983
  return dval;
4984
4984
  }
4985
- setValue(root, _v) {
4986
- return root;
4987
- }
4988
4985
  setDraftValue(_root, _v) {
4989
4986
  }
4990
4987
  enterFrame(stack, _prev, next) {
@@ -5013,9 +5010,6 @@ var BindStep = class _BindStep extends Step {
5013
5010
  lookup(v, _dval) {
5014
5011
  return v;
5015
5012
  }
5016
- setValue(_root, v) {
5017
- return v;
5018
- }
5019
5013
  enterFrame(stack, _prev, next) {
5020
5014
  return stack.enter(next, { ...this.binds }, false);
5021
5015
  }
@@ -5053,9 +5047,6 @@ var FieldStep = class extends Step {
5053
5047
  lookup(v, dval = null) {
5054
5048
  return readKey(v, this.field, dval);
5055
5049
  }
5056
- setValue(root, v) {
5057
- return produce(root, (draft) => this.setDraftValue(draft, v));
5058
- }
5059
5050
  setDraftValue(root, v) {
5060
5051
  writeKey(root, this.field, v);
5061
5052
  }
@@ -5078,9 +5069,6 @@ var SeqStep = class extends Step {
5078
5069
  lookup(v, dval = null) {
5079
5070
  return readSeqKey(readKey(v, this.field, null), this.key, dval);
5080
5071
  }
5081
- setValue(root, v) {
5082
- return produce(root, (draft) => this.setDraftValue(draft, v));
5083
- }
5084
5072
  setDraftValue(root, v) {
5085
5073
  const seq = readKey(root, this.field, null);
5086
5074
  if (seq != null) writeSeqKey(seq, this.key, v);
@@ -5103,9 +5091,6 @@ var SeqAccessStep = class extends Step {
5103
5091
  const key = readKey(v, this.keyField, NONE);
5104
5092
  return key !== NONE && seq !== NONE ? readSeqKey(seq, key, dval) : dval;
5105
5093
  }
5106
- setValue(root, v) {
5107
- return produce(root, (draft) => this.setDraftValue(draft, v));
5108
- }
5109
5094
  setDraftValue(root, v) {
5110
5095
  const seq = readKey(root, this.seqField, NONE);
5111
5096
  const key = readKey(root, this.keyField, NONE);
@@ -5133,9 +5118,6 @@ var EachBindStep = class extends Step {
5133
5118
  lookup(v, _dval) {
5134
5119
  return v;
5135
5120
  }
5136
- setValue(_root, v) {
5137
- return v;
5138
- }
5139
5121
  // Replay the renderer's per-item binds (key, value + any @enrich-with binds)
5140
5122
  // so a rebuilt stack matches the one @each rendered with.
5141
5123
  enterFrame(stack, _prev, next) {
@@ -5171,10 +5153,6 @@ var DynStep = class extends Step {
5171
5153
  warnRawDynStep("lookup", this);
5172
5154
  return dval;
5173
5155
  }
5174
- setValue(root, _v) {
5175
- warnRawDynStep("setValue", this);
5176
- return root;
5177
- }
5178
5156
  enterFrame(stack, _prev, _next) {
5179
5157
  warnRawDynStep("enterFrame", this);
5180
5158
  return stack;
@@ -5245,7 +5223,7 @@ var Path = class _Path {
5245
5223
  }
5246
5224
  // Resolve every field-keyed step (e.g. `SeqAccessStep`) against `root`, freezing the
5247
5225
  // key as it is *now* so a later lookup/setValue lands on the same item even if the
5248
- // keyField changed meanwhile (e.g. the selected tab moved while a request was in
5226
+ // keyField changed meanwhile (e.g. the selected tab moved while an intent was in
5249
5227
  // flight). Returns a new Path with those steps replaced; `this` if nothing pinned.
5250
5228
  // Must be called on a transaction path (no DynSteps — call toTransactionPath first).
5251
5229
  pinKeys(root) {
@@ -5487,7 +5465,6 @@ var K_FIELD = 4;
5487
5465
  var K_BIND = 8;
5488
5466
  var K_DYN = 16;
5489
5467
  var K_NAME = 32;
5490
- var K_TYPE = 64;
5491
5468
  var K_SEQ = 256;
5492
5469
  var K_METHOD = 1024;
5493
5470
  var K_EVENT = 2048;
@@ -5497,7 +5474,7 @@ var G_COMPONENT = K_FIELD | K_SEQ | K_DYN;
5497
5474
  var G_SEQUENCE = K_FIELD | K_DYN;
5498
5475
  var G_PROVIDE = K_FIELD | K_SEQ;
5499
5476
  var G_FIELD = K_FIELD | K_METHOD | K_CONST | K_SEQ;
5500
- var G_VALUE = K_FIELD | K_METHOD | K_BIND | K_DYN | K_NAME | K_TYPE | K_CONST;
5477
+ var G_VALUE = K_FIELD | K_METHOD | K_BIND | K_DYN | K_NAME | K_CONST;
5501
5478
  var G_HANDLER_ARG = G_VALUE & ~K_NAME | K_EVENT;
5502
5479
  var G_ALL = G_VALUE | K_STRTPL | K_SEQ;
5503
5480
  function sizeOf(v) {
@@ -5567,7 +5544,6 @@ function parseToken(s, px) {
5567
5544
  if (m !== null) return new EventMemberVal(s.split(".").slice(1));
5568
5545
  }
5569
5546
  if (c0 >= 97 && c0 <= 122) return mkVal(s, NameVal);
5570
- if (c0 >= 65 && c0 <= 90) return mkVal(s, TypeVal);
5571
5547
  return null;
5572
5548
  }
5573
5549
  function _parseSeqAccess(s, px) {
@@ -5682,7 +5658,6 @@ function kindOf(val) {
5682
5658
  if (val instanceof MethodVal) return K_METHOD;
5683
5659
  if (val instanceof BindVal) return K_BIND;
5684
5660
  if (val instanceof DynVal) return K_DYN;
5685
- if (val instanceof TypeVal) return K_TYPE;
5686
5661
  if (val instanceof NameVal) return K_NAME;
5687
5662
  if (val instanceof EventMemberVal) return K_EVENT;
5688
5663
  return 0;
@@ -5796,9 +5771,6 @@ var NameVal = class extends VarVal {
5796
5771
  super();
5797
5772
  this.name = name;
5798
5773
  }
5799
- eval(stack) {
5800
- return stack.lookupName(this.name);
5801
- }
5802
5774
  toString() {
5803
5775
  return this.name;
5804
5776
  }
@@ -5819,11 +5791,6 @@ var mk404Handler = (stack, type3, name) => function(...args) {
5819
5791
  else console.warn("handler not found", { type: type3, name });
5820
5792
  return this;
5821
5793
  };
5822
- var TypeVal = class extends NameVal {
5823
- eval(stack) {
5824
- return stack.lookupType(this.name);
5825
- }
5826
- };
5827
5794
  var keyIs = (k) => (e) => e.key === k;
5828
5795
  var macCtrl = (e) => isMac && e.metaKey || e.ctrlKey;
5829
5796
  var nullSafe = (fn) => (e, stack) => {
@@ -5956,9 +5923,6 @@ var Attributes = class {
5956
5923
  constructor(items) {
5957
5924
  this.items = items;
5958
5925
  }
5959
- eval(_stack) {
5960
- return {};
5961
- }
5962
5926
  static parse(attributes, px, parseAll = false) {
5963
5927
  return getAttrParser(px).parse(attributes, parseAll);
5964
5928
  }
@@ -5968,11 +5932,26 @@ var Attributes = class {
5968
5932
  };
5969
5933
  var booleanAttrsRaw = "itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly,async,autofocus,autoplay,controls,default,defer,disabled,hidden,inert,loop,open,required,reversed,scoped,seamless,checked,muted,multiple,selected";
5970
5934
  var booleanAttrs = new Set(booleanAttrsRaw.split(","));
5935
+ function parseDirectiveValue(px, directiveName, source, parser) {
5936
+ const val = parser(source, px);
5937
+ if (val === null) {
5938
+ px.onParseIssue("bad-value", {
5939
+ role: "directive",
5940
+ directive: directiveName,
5941
+ value: source
5942
+ });
5943
+ }
5944
+ return val;
5945
+ }
5946
+ function parseIterationDirectives(attributes, px) {
5947
+ const parseNamed = (name) => {
5948
+ const attr = attributes.getNamedItem(`@${name}`);
5949
+ return attr ? parseDirectiveValue(px, name, attr.value, parseAlterHandler) : null;
5950
+ };
5951
+ return { whenVal: parseNamed("when"), loopWithVal: parseNamed("loop-with") };
5952
+ }
5971
5953
  var AttrParser = class {
5972
5954
  constructor(px) {
5973
- this.clear(px);
5974
- }
5975
- clear(px) {
5976
5955
  this.px = px;
5977
5956
  this.attrs = null;
5978
5957
  this.hasDynamic = false;
@@ -6027,12 +6006,7 @@ var AttrParser = class {
6027
6006
  }
6028
6007
  }
6029
6008
  _parseDirectiveValue(directiveName, s, parserFn) {
6030
- const val = parserFn(s, this.px);
6031
- if (val === null) {
6032
- const info = { role: "directive", directive: directiveName, value: s };
6033
- this.px.onParseIssue("bad-value", info);
6034
- }
6035
- return val;
6009
+ return parseDirectiveValue(this.px, directiveName, s, parserFn);
6036
6010
  }
6037
6011
  parseDirective(s, directiveName) {
6038
6012
  switch (directiveName) {
@@ -6196,11 +6170,8 @@ var IfAttr = class extends BaseAttr {
6196
6170
  return this.condVal.eval(stack) ? this.thenVal.eval(stack) : this.elseVal.eval(stack);
6197
6171
  }
6198
6172
  };
6199
- var _attrParser = null;
6200
6173
  function getAttrParser(px) {
6201
- _attrParser ??= new AttrParser(px);
6202
- _attrParser.clear(px);
6203
- return _attrParser;
6174
+ return new AttrParser(px);
6204
6175
  }
6205
6176
  var EventHandler = class _EventHandler {
6206
6177
  constructor(handlerVal, args = []) {
@@ -6224,70 +6195,77 @@ var IntentHandler = class {
6224
6195
  }
6225
6196
  };
6226
6197
 
6227
- // src/cache.js
6228
- var isWeakKey = (k) => k !== null && (typeof k === "object" || typeof k === "function");
6229
- var NullDomCache = class {
6230
- get(_keys, _cacheKey) {
6231
- }
6232
- set(_keys, _cacheKey, _v) {
6233
- }
6234
- evict() {
6235
- return { hit: 0, miss: 0, badKey: 0 };
6236
- }
6198
+ // src/iteration.js
6199
+ var SEQ_INFO = /* @__PURE__ */ Symbol.for("tutuca.seqInfo");
6200
+ var normalizeRange = (start, end, size) => {
6201
+ let s = start == null ? 0 : start < 0 ? size + start : start;
6202
+ let e = end == null ? size : end < 0 ? size + end : end;
6203
+ s = s < 0 ? 0 : s > size ? size : s;
6204
+ e = e < 0 ? 0 : e > size ? size : e;
6205
+ return [s, e < s ? s : e];
6237
6206
  };
6238
- var WeakMapDomCache = class {
6239
- constructor() {
6240
- this.hit = this.miss = this.badKey = 0;
6241
- this.keysByLen = /* @__PURE__ */ new Map();
6242
- }
6243
- _returnValue(r) {
6244
- if (r === void 0) this.miss += 1;
6245
- else this.hit += 1;
6246
- return r;
6247
- }
6248
- get(keys, cacheKey) {
6249
- const len = keys.length;
6250
- let cur = this.keysByLen.get(len);
6251
- if (!cur) return this._returnValue(void 0);
6252
- for (let i = 0; i < len - 1; i++) {
6253
- cur = cur.get(keys[i]);
6254
- if (!cur) return this._returnValue(void 0);
6255
- }
6256
- return this._returnValue(cur.get(keys[len - 1])?.[cacheKey]);
6257
- }
6258
- set(keys, cacheKey, v) {
6259
- const len = keys.length;
6260
- let cur = this.keysByLen.get(len);
6261
- if (!cur) {
6262
- cur = /* @__PURE__ */ new WeakMap();
6263
- this.keysByLen.set(len, cur);
6264
- }
6265
- for (let i = 0; i < len - 1; i++) {
6266
- const key = keys[i];
6267
- let next = cur.get(key);
6268
- if (!next) {
6269
- if (!isWeakKey(key)) {
6270
- this.badKey += 1;
6271
- return;
6272
- }
6273
- next = /* @__PURE__ */ new WeakMap();
6274
- cur.set(key, next);
6275
- }
6276
- cur = next;
6277
- }
6278
- const lastKey = keys[len - 1];
6279
- const leaf = cur.get(lastKey);
6280
- if (leaf) leaf[cacheKey] = v;
6281
- else if (isWeakKey(lastKey)) cur.set(lastKey, { [cacheKey]: v });
6282
- else this.badKey += 1;
6283
- }
6284
- evict() {
6285
- const { hit, miss, badKey } = this;
6286
- this.hit = this.miss = this.badKey = 0;
6287
- this.keysByLen = /* @__PURE__ */ new Map();
6288
- return { hit, miss, badKey };
6207
+ var nativeIndexedIter = (seq, visit, start, end) => {
6208
+ const [s, e] = normalizeRange(start, end, seqSize(seq));
6209
+ for (let i = s; i < e; i++) visit(i, seq[i], "si");
6210
+ };
6211
+ var nativeKeyedIter = (seq, visit, start, end) => {
6212
+ const [s, e] = normalizeRange(start, end, seqSize(seq));
6213
+ let i = 0;
6214
+ for (const [key, value] of seqEntries(seq)) {
6215
+ if (i >= e) break;
6216
+ if (i >= s) visit(key, value, "sk");
6217
+ i++;
6289
6218
  }
6290
6219
  };
6220
+ var unknownIter = () => {
6221
+ };
6222
+ var getSeqInfo = (seq) => isIndexedSeq(seq) ? nativeIndexedIter : isKeyedSeq(seq) || isSetSeq(seq) ? nativeKeyedIter : seq?.[SEQ_INFO] ?? unknownIter;
6223
+ var filterAlwaysTrue = (_key, _value, _iterData) => true;
6224
+ var nullLoopWith = (seq) => ({ iterData: { seq } });
6225
+ var unpackLoopResult = (result, seq) => {
6226
+ const value = result ?? {};
6227
+ return {
6228
+ iterData: value.iterData ?? { seq },
6229
+ start: value.start,
6230
+ end: value.end,
6231
+ keys: value.keys
6232
+ };
6233
+ };
6234
+ var makeLoopCtx = (stack, filter) => ({
6235
+ lookup: (name) => stack.lookupBind(name),
6236
+ filter: (key, value, iterData) => filter.call(stack.it, key, value, iterData)
6237
+ });
6238
+ var callEnricher = (enricher, it, binds, key, value, iterData) => {
6239
+ enricher.call(it, binds, key, value, iterData);
6240
+ console.assert(
6241
+ binds.key === key && binds.value === value,
6242
+ "@enrich-with handlers must not overwrite binds.key or binds.value"
6243
+ );
6244
+ binds.key = key;
6245
+ binds.value = value;
6246
+ };
6247
+ var visitKeys = (seq, keys, visit) => {
6248
+ const attrName = isIndexedSeq(seq) ? "si" : "sk";
6249
+ for (const key of keys) visit(key, seqGet(seq, key), attrName);
6250
+ };
6251
+ function walkLoopBindings({ seq, it, filter, loopWith, enricher, ctx }, visit) {
6252
+ const { iterData, start, end, keys } = unpackLoopResult(loopWith.call(it, seq, ctx), seq);
6253
+ const visitOne = (key, value, attrName) => {
6254
+ const binds = { key, value };
6255
+ if (enricher) callEnricher(enricher, it, binds, key, value, iterData);
6256
+ visit(key, value, attrName, binds);
6257
+ };
6258
+ if (keys) visitKeys(seq, keys, visitOne);
6259
+ else
6260
+ getSeqInfo(seq)(
6261
+ seq,
6262
+ (key, value, attrName) => {
6263
+ if (filter.call(it, key, value, iterData)) visitOne(key, value, attrName);
6264
+ },
6265
+ start,
6266
+ end
6267
+ );
6268
+ }
6291
6269
 
6292
6270
  // src/vdom.js
6293
6271
  var HTML_NS = "http://www.w3.org/1999/xhtml";
@@ -6632,189 +6610,11 @@ function h(tagName, properties, children, namespace) {
6632
6610
  return new VNode(tag, props, normalizedChildren, key, namespace);
6633
6611
  }
6634
6612
 
6635
- // src/renderer.js
6636
- var DATASET_ATTRS = ["nid", "cid", "eid", "vid", "si", "sk"];
6637
- var Renderer = class {
6638
- constructor(comps) {
6639
- this.comps = comps;
6640
- this.cache = new WeakMapDomCache();
6641
- this.renderTag = h;
6642
- }
6643
- renderFragment(childs) {
6644
- return new VFragment(childs);
6645
- }
6646
- renderComment(text) {
6647
- return new VComment(text);
6648
- }
6649
- setNullCache() {
6650
- this.cache = new NullDomCache();
6651
- }
6652
- renderToDOM(stack, val) {
6653
- const rootNode = document.createElement("div");
6654
- const rOpts = { document };
6655
- render(h("DIV", null, [this.renderRoot(stack, val)]), rootNode, rOpts);
6656
- return rootNode.childNodes[0];
6657
- }
6658
- renderToString(stack, val, cleanAttrs = true) {
6659
- const dom = this.renderToDOM(stack, val);
6660
- if (cleanAttrs) {
6661
- const nodes = dom.querySelectorAll("[data-nid],[data-cid],[data-eid]");
6662
- for (const { dataset } of nodes) for (const name of DATASET_ATTRS) delete dataset[name];
6663
- }
6664
- return dom.innerHTML;
6665
- }
6666
- renderRoot(stack, val, viewName = null) {
6667
- const comp = this.comps.getCompFor(val);
6668
- if (comp === null) return null;
6669
- return this._rValComp(stack, val, comp, comp.getView(viewName).anode, "ROOT", viewName);
6670
- }
6671
- renderIt(stack, node, key, viewName) {
6672
- const comp = this.comps.getCompFor(stack.it);
6673
- return comp ? this._rValComp(stack, stack.it, comp, node, key, viewName) : null;
6674
- }
6675
- // `node` is the parse node of the render site (`<x render>` / `render-it` /
6676
- // `render-each`, or the view's root anode for the app root). It keys the
6677
- // cache as a globally-unique object: node ids alone are unique only within a
6678
- // single view, so the same value rendered by two components (e.g. through a
6679
- // shared dynamic-var sequence) would otherwise collide in the cache.
6680
- _rValComp(stack, val, comp, node, key, viewName) {
6681
- const cacheKey = `${viewName ?? ""}${stack.viewsId ?? ""}${key}`;
6682
- const cachePath = [node, val];
6683
- stack._pushDynBindValuesToArray(cachePath, comp);
6684
- const cachedNode = this.cache.get(cachePath, cacheKey);
6685
- if (cachedNode) return cachedNode;
6686
- const view = viewName ? comp.getView(viewName) : stack.lookupBestView(comp.views, "main");
6687
- const body = this.renderView(view, stack);
6688
- if (body == null) return null;
6689
- const meta = this._renderMetadata({
6690
- $: "Comp",
6691
- nid: node?.nodeId ?? null,
6692
- cid: comp.id,
6693
- vid: view.name
6694
- });
6695
- const dom = new VFragment([meta, body]);
6696
- this.cache.set(cachePath, cacheKey, dom);
6697
- return dom;
6698
- }
6699
- pushEachEntry(r, nid, attrName, key, dom) {
6700
- r.push(this._renderMetadata({ $: "Each", nid, [attrName]: key }), dom);
6701
- }
6702
- renderEachWhen(stack, iterInfo, view, nid) {
6703
- const { seq, filter, loopWith, enricher } = iterInfo.eval(stack);
6704
- const r = [];
6705
- const it = stack.it;
6706
- const { iterData, start, end, keys } = unpackLoopResult(
6707
- loopWith.call(it, seq, makeLoopCtx(stack, filter)),
6708
- seq
6709
- );
6710
- const renderOne = (key, value, attrName) => {
6711
- const cachePath = enricher ? [view, it, value] : [view, value];
6712
- const binds = { key, value };
6713
- const cacheKey = `${stack.viewsId ?? ""}${nid}${key}`;
6714
- if (enricher) callEnricher(enricher, it, binds, key, value, iterData);
6715
- const cachedNode = this.cache.get(cachePath, cacheKey);
6716
- if (cachedNode) this.pushEachEntry(r, nid, attrName, key, cachedNode);
6717
- else {
6718
- const dom = this.renderView(view, stack.enter(value, binds, false));
6719
- if (dom != null) this.pushEachEntry(r, nid, attrName, key, dom);
6720
- this.cache.set(cachePath, cacheKey, dom);
6721
- }
6722
- };
6723
- if (keys) keysIter(seq, renderOne, keys);
6724
- else
6725
- getSeqInfo(seq)(
6726
- seq,
6727
- (key, value, attrName) => {
6728
- if (filter.call(it, key, value, iterData)) renderOne(key, value, attrName);
6729
- },
6730
- start,
6731
- end
6732
- );
6733
- return r;
6734
- }
6735
- renderView(view, stack) {
6736
- let n = stack.binds[1];
6737
- while (n !== null) {
6738
- const b = n[0];
6739
- if (b.isFrame) {
6740
- if (stack.it !== b.it) break;
6741
- console.error("recursion detected", stack.it, b.it);
6742
- return new VComment("RECURSION AVOIDED");
6743
- }
6744
- n = n[1];
6745
- }
6746
- return view.render(stack, this);
6747
- }
6748
- _renderMetadata(info) {
6749
- return new VComment(`§${JSON.stringify(info)}§`);
6750
- }
6751
- // Prefix a loop-less @enrich-with subtree with a boundary meta so event-path
6752
- // reconstruction replays its binds (mirrors the §Each§ / §Comp§ metas).
6753
- renderScopeMeta(nid, dom) {
6754
- return new VFragment([this._renderMetadata({ $: "Scope", nid }), dom]);
6755
- }
6756
- };
6757
- var getSeqInfo = (seq) => isIndexedSeq(seq) ? nativeIndexedIter : isKeyedSeq(seq) || isSetSeq(seq) ? nativeKeyedIter : seq?.[SEQ_INFO] ?? unkIter;
6758
- var normalizeRange = (start, end, size) => {
6759
- let s = start == null ? 0 : start < 0 ? size + start : start;
6760
- let e = end == null ? size : end < 0 ? size + end : end;
6761
- s = s < 0 ? 0 : s > size ? size : s;
6762
- e = e < 0 ? 0 : e > size ? size : e;
6763
- return [s, e < s ? s : e];
6764
- };
6765
- var callEnricher = (enricher, it, binds, key, value, iterData) => {
6766
- enricher.call(it, binds, key, value, iterData);
6767
- console.assert(
6768
- binds.key === key && binds.value === value,
6769
- "@enrich-with handlers must not overwrite binds.key or binds.value"
6770
- );
6771
- binds.key = key;
6772
- binds.value = value;
6773
- };
6774
- var filterAlwaysTrue = (_v, _k, _seq) => true;
6775
- var nullLoopWith = (seq) => ({ iterData: { seq } });
6776
- var unpackLoopResult = (result, seq) => {
6777
- const r = result ?? {};
6778
- return { iterData: r.iterData ?? { seq }, start: r.start, end: r.end, keys: r.keys };
6779
- };
6780
- var keysIter = (seq, visit, keys) => {
6781
- const attrName = isIndexedSeq(seq) ? "si" : "sk";
6782
- for (const key of keys) visit(key, seqGet(seq, key), attrName);
6783
- };
6784
- var makeLoopCtx = (stack, filter) => ({
6785
- lookup: (name) => stack.lookupBind(name),
6786
- filter: (key, value, iterData) => filter.call(stack.it, key, value, iterData)
6787
- });
6788
- var nativeIndexedIter = (seq, visit, start, end) => {
6789
- const [s, e] = normalizeRange(start, end, seqSize(seq));
6790
- for (let i = s; i < e; i++) visit(i, seq[i], "si");
6791
- };
6792
- var nativeKeyedIter = (seq, visit, start, end) => {
6793
- const [s, e] = normalizeRange(start, end, seqSize(seq));
6794
- let i = 0;
6795
- for (const [k, v] of seqEntries(seq)) {
6796
- if (i >= e) break;
6797
- if (i >= s) visit(k, v, "sk");
6798
- i++;
6799
- }
6800
- };
6801
- var unkIter = () => {
6802
- };
6803
- var SEQ_INFO = /* @__PURE__ */ Symbol.for("tutuca.seqInfo");
6804
-
6805
6613
  // src/anode.js
6806
6614
  function resolveDynProducer(comp, name) {
6807
- let producerComp, producerProvide;
6808
- const lk = comp?.lookup?.[name];
6809
- if (lk != null) {
6810
- producerComp = comp.scope?.lookupComponent(lk.compName);
6811
- producerProvide = producerComp?.provide?.[lk.provideName];
6812
- } else {
6813
- const p = comp?.provide?.[name];
6814
- if (p == null) return null;
6815
- producerComp = comp;
6816
- producerProvide = p;
6817
- }
6615
+ const own = comp?.provide?.[name];
6616
+ const producerComp = own != null ? comp : comp?.scope?.lookupProvider(name) ?? null;
6617
+ const producerProvide = own ?? producerComp?.provide?.[name];
6818
6618
  if (producerComp == null || producerProvide == null) return null;
6819
6619
  const pi = producerProvide.val?.toPathItem?.() ?? null;
6820
6620
  return { producerCompId: producerComp.id, producerSteps: pi ? [pi] : [] };
@@ -7175,16 +6975,10 @@ function parseRenderEach(px, value, as, attrs) {
7175
6975
  const seqVal = parseXOpVal("render-each", value, px, parseSequence);
7176
6976
  if (seqVal === null) return null;
7177
6977
  const renderIt = px.addNode(RenderItNode, as);
7178
- const attrParser = getAttrParser(px);
7179
- const eachAttr = attrParser.pushWrapper("each", value, seqVal);
7180
- attrParser.eachAttr = eachAttr;
7181
- const when = attrs.getNamedItem("@when");
7182
- if (when) attrParser._parseWhen(when.value);
7183
- const lWith = attrs.getNamedItem("@loop-with");
7184
- if (lWith) attrParser._parseLoopWith(lWith.value);
6978
+ const { whenVal, loopWithVal } = parseIterationDirectives(attrs, px);
7185
6979
  const each2 = px.addNodeIf(EachNode, seqVal);
7186
- each2.iterInfo.whenVal = eachAttr.whenVal ?? null;
7187
- each2.iterInfo.loopWithVal = eachAttr.loopWithVal ?? null;
6980
+ each2.iterInfo.whenVal = whenVal;
6981
+ each2.iterInfo.loopWithVal = loopWithVal;
7188
6982
  each2.fromRenderEach = true;
7189
6983
  each2.wrapNode(renderIt);
7190
6984
  return each2;
@@ -7651,7 +7445,7 @@ var Components = class {
7651
7445
  }
7652
7446
  compileStyles() {
7653
7447
  const styles2 = [];
7654
- for (const comp of this.byId.values()) styles2.push(comp.compileStyle());
7448
+ for (const Comp of this.byId.values()) styles2.push(Comp[COMPONENT].compileStyle());
7655
7449
  return styles2.join("\n");
7656
7450
  }
7657
7451
  };
@@ -7710,32 +7504,39 @@ var ComponentStack = class _ComponentStack {
7710
7504
  lookupComponent(name) {
7711
7505
  return this.byName[name] ?? this.parent?.lookupComponent(name) ?? null;
7712
7506
  }
7507
+ // The component in this scope chain that provides `name`, innermost first. A lookup
7508
+ // names a value without naming its producer, so the render-target teleport
7509
+ // (resolveDynProducer) recovers the producer here instead. Sound because
7510
+ // PROVIDE_NAME_COLLISION keeps a provide name to one producer per chain; with two,
7511
+ // this returns the innermost and the linter has already reported the ambiguity.
7512
+ lookupProvider(name) {
7513
+ for (const compName in this.byName) {
7514
+ const Comp = this.byName[compName];
7515
+ if (Comp.provide?.[name] !== void 0) return Comp;
7516
+ }
7517
+ return this.parent?.lookupProvider(name) ?? null;
7518
+ }
7713
7519
  lookupMacro(name) {
7714
7520
  return this.macros[name] ?? this.parent?.lookupMacro(name) ?? null;
7715
7521
  }
7716
7522
  };
7717
7523
  var ProvideInfo = class {
7718
- constructor(name, val, symbol) {
7524
+ constructor(name, val) {
7719
7525
  this.name = name;
7720
7526
  this.val = val;
7721
- this.symbol = symbol;
7722
7527
  }
7723
7528
  };
7724
7529
  var LookupInfo = class {
7725
- constructor(name, compName, provideName, val) {
7530
+ constructor(name, val) {
7726
7531
  this.name = name;
7727
- this.compName = compName;
7728
- this.provideName = provideName;
7729
7532
  this.val = val;
7730
- this._sym = void 0;
7731
- }
7732
- getProducerSymbol(stack) {
7733
- if (this._sym === void 0)
7734
- this._sym = stack.lookupType(this.compName)?.provide?.[this.provideName]?.symbol ?? null;
7735
- return this._sym;
7736
7533
  }
7737
7534
  };
7738
7535
  var isString = (v) => typeof v === "string";
7536
+ var isTypeName = (s) => {
7537
+ const c = s.charCodeAt(0);
7538
+ return c >= 65 && c <= 90;
7539
+ };
7739
7540
  var _rawSpecKeys = "name view style commonStyle globalStyle receive intent alter views provide lookup fields methods statics";
7740
7541
  var KNOWN_SPEC_KEYS = new Set(_rawSpecKeys.split(" "));
7741
7542
  var _compId = 0;
@@ -7756,8 +7557,9 @@ var Component = class {
7756
7557
  this.views[name] = new View(name, view, style);
7757
7558
  }
7758
7559
  this._rawProvide = o.provide ?? {};
7759
- this._rawLookup = o.lookup ?? {};
7560
+ this._rawLookup = o.lookup ?? [];
7760
7561
  this.provide = {};
7562
+ this.provideType = {};
7761
7563
  this.lookup = {};
7762
7564
  this.scope = null;
7763
7565
  this.spec = o;
@@ -7769,25 +7571,23 @@ var Component = class {
7769
7571
  this.views[name].compile(new ParseContext2(), this.scope, this.id);
7770
7572
  const ctx = this.views.main.ctx;
7771
7573
  for (const key in this._rawProvide) {
7574
+ if (isTypeName(key)) {
7575
+ if (this._rawProvide[key] === "self") this.provideType[key] = this.Class;
7576
+ continue;
7577
+ }
7772
7578
  const val = parseProvide(this._rawProvide[key], ctx);
7773
- if (val) this.provide[key] = new ProvideInfo(key, val, Symbol(key));
7579
+ if (val) this.provide[key] = new ProvideInfo(key, val);
7774
7580
  }
7775
- for (const key in this._rawLookup) {
7776
- const linfo = this._rawLookup[key];
7777
- const forStr = isString(linfo) ? linfo : isString(linfo?.for) ? linfo.for : null;
7778
- const [compName, provideName] = forStr === null ? [] : forStr.split(".");
7779
- if (!isString(compName) || !isString(provideName)) continue;
7780
- const defStr = isString(linfo?.default) ? linfo.default : null;
7781
- const val = defStr === null ? null : parseField(defStr, ctx);
7782
- this.lookup[key] = new LookupInfo(key, compName, provideName, val);
7581
+ for (const entry of this._rawLookup) {
7582
+ const name = isString(entry) ? entry : isString(entry?.name) ? entry.name : null;
7583
+ if (name === null) continue;
7584
+ const defStr = isString(entry?.default) ? entry.default : null;
7585
+ this.lookup[name] = new LookupInfo(name, defStr === null ? null : parseField(defStr, ctx));
7783
7586
  }
7784
7587
  for (const key in this.lookup)
7785
7588
  if (this.provide[key] !== void 0)
7786
7589
  console.warn("name declared in both provide and lookup", this.name, key);
7787
7590
  }
7788
- make(args, opts) {
7789
- return this.Class.make(args, opts ?? { scope: this.scope });
7790
- }
7791
7591
  getView(name) {
7792
7592
  return this.views[name] ?? this.views.main;
7793
7593
  }
@@ -10090,13 +9890,19 @@ var KNOWN_DIRECTIVE_NAMES = /* @__PURE__ */ new Set([
10090
9890
  "then",
10091
9891
  "else"
10092
9892
  ]);
9893
+ var isTypeName2 = (s) => {
9894
+ const c = s.charCodeAt(0);
9895
+ return c >= 65 && c <= 90;
9896
+ };
10093
9897
  var ALT_HANDLER_NOT_DEFINED = "ALT_HANDLER_NOT_DEFINED";
10094
9898
  var ALT_HANDLER_NOT_REFERENCED = "ALT_HANDLER_NOT_REFERENCED";
10095
9899
  var DYN_VAL_NOT_DEFINED = "DYN_VAL_NOT_DEFINED";
10096
9900
  var DYN_ALIAS_NOT_REFERENCED = "DYN_ALIAS_NOT_REFERENCED";
10097
9901
  var PROVIDE_NOT_ADDRESSABLE = "PROVIDE_NOT_ADDRESSABLE";
9902
+ var PROVIDE_TYPE_BAD_SHAPE = "PROVIDE_TYPE_BAD_SHAPE";
9903
+ var PROVIDE_NAME_COLLISION = "PROVIDE_NAME_COLLISION";
10098
9904
  var LOOKUP_BAD_SHAPE = "LOOKUP_BAD_SHAPE";
10099
- var LOOKUP_TARGET_MALFORMED = "LOOKUP_TARGET_MALFORMED";
9905
+ var LOOKUP_NO_PROVIDER = "LOOKUP_NO_PROVIDER";
10100
9906
  var RENDER_IT_OUTSIDE_OF_LOOP = "RENDER_IT_OUTSIDE_OF_LOOP";
10101
9907
  var UNKNOWN_EVENT_MODIFIER = "UNKNOWN_EVENT_MODIFIER";
10102
9908
  var RECEIVE_HANDLER_NOT_IMPLEMENTED = "RECEIVE_HANDLER_NOT_IMPLEMENTED";
@@ -10216,7 +10022,11 @@ function checkComponent(Comp, lx = new LintContext(), { wellKnownExtras = EMPTY_
10216
10022
  checkFieldDeclarations(lx, Comp);
10217
10023
  checkFieldMethodNameCollisions(lx, Comp);
10218
10024
  checkProvidesAreAddressable(lx, Comp);
10025
+ checkProvidedTypes(lx, Comp);
10026
+ checkProvideNameCollisions(lx, Comp);
10219
10027
  checkLookupShapes(lx, Comp);
10028
+ checkLookupTypesResolve(lx, Comp);
10029
+ checkLookupsHaveProviders(lx, Comp);
10220
10030
  checkHandlersNotAsync(lx, Comp);
10221
10031
  checkHandlerNameCollisions(lx, Comp);
10222
10032
  checkScopedStyleTopLevel(lx, Comp);
@@ -10549,17 +10359,7 @@ var ATTR_VAL_CHECKERS = {
10549
10359
  },
10550
10360
  SeqAccessVal({ val, recurse }) {
10551
10361
  recurse(val.seqVal);
10552
- recurse(val.keyVal);
10553
- },
10554
- TypeVal({ lx, val, env, errCtx }) {
10555
- if (env.scope.lookupComponent(val.name) === null)
10556
- reportUnknownName(
10557
- lx,
10558
- UNKNOWN_COMPONENT_NAME,
10559
- val.name,
10560
- scopeKeysAlong(env.scope, "byName"),
10561
- errCtx
10562
- );
10362
+ recurse(val.keyVal);
10563
10363
  },
10564
10364
  // NameVals on a macro call-site attribute are macro-param bindings, not
10565
10365
  // handler args — their role is determined inside the macro body after
@@ -10894,48 +10694,90 @@ function checkScopedStyleTopLevel(lx, Comp) {
10894
10694
  }
10895
10695
  function checkProvidesAreAddressable(lx, Comp) {
10896
10696
  for (const name in Comp._rawProvide) {
10697
+ if (isTypeName2(name)) continue;
10897
10698
  if (Comp.provide[name] === void 0) {
10898
10699
  lx.error(PROVIDE_NOT_ADDRESSABLE, { name, value: Comp._rawProvide[name] });
10899
10700
  }
10900
10701
  }
10901
10702
  }
10902
- var KNOWN_LOOKUP_KEYS = /* @__PURE__ */ new Set(["for", "default"]);
10703
+ function checkProvidedTypes(lx, Comp) {
10704
+ for (const name in Comp._rawProvide) {
10705
+ if (!isTypeName2(name)) continue;
10706
+ const raw = Comp._rawProvide[name];
10707
+ if (raw !== "self") lx.error(PROVIDE_TYPE_BAD_SHAPE, { name, value: raw });
10708
+ }
10709
+ }
10710
+ function checkProvideNameCollisions(lx, Comp) {
10711
+ const scope = Comp.scope;
10712
+ if (!scope) return;
10713
+ for (const name in Comp.provide) {
10714
+ for (let s = scope; s; s = s.parent) {
10715
+ for (const otherName in s.byName) {
10716
+ const Other = s.byName[otherName];
10717
+ if (Other !== Comp && Other.provide?.[name] !== void 0)
10718
+ lx.error(PROVIDE_NAME_COLLISION, { name, other: Other.name });
10719
+ }
10720
+ }
10721
+ }
10722
+ }
10723
+ var KNOWN_LOOKUP_KEYS = /* @__PURE__ */ new Set(["name", "default"]);
10903
10724
  function checkLookupShapes(lx, Comp) {
10904
- for (const name in Comp._rawLookup) {
10905
- const raw = Comp._rawLookup[name];
10906
- let target;
10907
- if (typeof raw === "string") {
10908
- target = raw;
10909
- } else if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
10725
+ const raw = Comp._rawLookup;
10726
+ if (!Array.isArray(raw)) {
10727
+ if (raw !== void 0 && Object.keys(raw).length > 0)
10728
+ lx.error(LOOKUP_BAD_SHAPE, { name: "lookup", problem: "must be a list of names" });
10729
+ return;
10730
+ }
10731
+ for (const entry of raw) {
10732
+ if (typeof entry === "string") continue;
10733
+ if (entry === null || typeof entry !== "object" || Array.isArray(entry)) {
10910
10734
  lx.error(LOOKUP_BAD_SHAPE, {
10911
- name,
10912
- problem: 'must be a "Producer.provideName" string or a { for, default } object'
10735
+ name: String(entry),
10736
+ problem: 'must be a "name" string or a { name, default } object'
10737
+ });
10738
+ continue;
10739
+ }
10740
+ const extra = Object.keys(entry).filter((k) => !KNOWN_LOOKUP_KEYS.has(k));
10741
+ if (extra.length > 0) {
10742
+ lx.error(LOOKUP_BAD_SHAPE, {
10743
+ name: String(entry.name),
10744
+ problem: `unknown key(s): ${extra.join(", ")}`
10913
10745
  });
10914
10746
  continue;
10915
- } else {
10916
- const extra = Object.keys(raw).filter((k) => !KNOWN_LOOKUP_KEYS.has(k));
10917
- if (extra.length > 0) {
10918
- lx.error(LOOKUP_BAD_SHAPE, { name, problem: `unknown key(s): ${extra.join(", ")}` });
10919
- continue;
10920
- }
10921
- if (typeof raw.for !== "string") {
10922
- lx.error(LOOKUP_BAD_SHAPE, { name, problem: "'for' is required and must be a string" });
10923
- continue;
10924
- }
10925
- if (raw.default !== void 0 && typeof raw.default !== "string") {
10926
- lx.error(LOOKUP_BAD_SHAPE, { name, problem: "'default' must be a string" });
10927
- continue;
10928
- }
10929
- target = raw.for;
10930
10747
  }
10931
- const parts = target.split(".");
10932
- if (parts.length !== 2 || !parts[0] || !parts[1]) {
10933
- lx.error(LOOKUP_TARGET_MALFORMED, { name, target });
10748
+ if (typeof entry.name !== "string" || entry.name === "") {
10749
+ lx.error(LOOKUP_BAD_SHAPE, {
10750
+ name: String(entry.name),
10751
+ problem: "'name' is required and must be a string"
10752
+ });
10753
+ continue;
10934
10754
  }
10755
+ if (entry.default !== void 0 && typeof entry.default !== "string")
10756
+ lx.error(LOOKUP_BAD_SHAPE, { name: entry.name, problem: "'default' must be a string" });
10757
+ }
10758
+ }
10759
+ function checkLookupsHaveProviders(lx, Comp) {
10760
+ const scope = Comp.scope;
10761
+ if (!scope) return;
10762
+ for (const name in Comp.lookup) {
10763
+ if (isTypeName2(name)) continue;
10764
+ if (scope.lookupProvider?.(name)) continue;
10765
+ const info = { name, hasDefault: Comp.lookup[name].val != null };
10766
+ if (info.hasDefault) lx.hint(LOOKUP_NO_PROVIDER, info);
10767
+ else lx.error(LOOKUP_NO_PROVIDER, info);
10768
+ }
10769
+ }
10770
+ function checkLookupTypesResolve(lx, Comp) {
10771
+ if (!Comp.scope) return;
10772
+ for (const name in Comp.lookup) {
10773
+ if (!isTypeName2(name)) continue;
10774
+ if (Comp.scope.lookupComponent(name) === null)
10775
+ reportUnknownName(lx, UNKNOWN_COMPONENT_NAME, name, scopeKeysAlong(Comp.scope, "byName"), {});
10935
10776
  }
10936
10777
  }
10937
10778
  function checkUnreferencedDynamics(lx, Comp, referencedDynamics) {
10938
10779
  for (const name in Comp.lookup) {
10780
+ if (isTypeName2(name)) continue;
10939
10781
  if (!referencedDynamics.has(name)) {
10940
10782
  lx.hint(DYN_ALIAS_NOT_REFERENCED, { name });
10941
10783
  }
@@ -11000,7 +10842,7 @@ function dispatchPhase(dispatcher, targetPath, phase, self) {
11000
10842
  const args = resolveArgs(op.args, self);
11001
10843
  switch (op.type) {
11002
10844
  case "send":
11003
- dispatcher.sendAtPath(targetPath, op.name, args, op.opts);
10845
+ dispatcher.sendAtPath(targetPath, op.name, args);
11004
10846
  break;
11005
10847
  case "intent":
11006
10848
  dispatcher.intentAtPath(targetPath, op.name, args, op.opts);
@@ -11012,11 +10854,6 @@ function dispatchPhase(dispatcher, targetPath, phase, self) {
11012
10854
  // src/oo.js
11013
10855
  var BAD_VALUE2 = /* @__PURE__ */ Symbol("BadValue");
11014
10856
  var nullCoercer = (v) => v;
11015
- var isPlainObject3 = (v) => {
11016
- if (v === null || typeof v !== "object") return false;
11017
- const proto = Object.getPrototypeOf(v);
11018
- return proto === Object.prototype || proto === null;
11019
- };
11020
10857
  function defaultToData(v) {
11021
10858
  if (v instanceof Map) return [...v.entries()];
11022
10859
  if (v instanceof Set) return [...v.values()];
@@ -11085,7 +10922,7 @@ var CHECK_TYPE_FLOAT = check(Number.isFinite, "Float expected");
11085
10922
  var CHECK_TYPE_BOOL = check((v) => typeof v === "boolean", "Boolean expected");
11086
10923
  var CHECK_TYPE_STRING = check((v) => typeof v === "string", "String expected");
11087
10924
  var CHECK_TYPE_LIST = check(Array.isArray, "Array expected");
11088
- var CHECK_TYPE_OBJECT = check(isPlainObject3, "Plain object expected");
10925
+ var CHECK_TYPE_OBJECT = check(isPlainObject, "Plain object expected");
11089
10926
  var CHECK_TYPE_MAP = check((v) => v instanceof Map, "Map expected");
11090
10927
  var CHECK_TYPE_SET = check((v) => v instanceof Set, "Set expected");
11091
10928
  var FieldBool = class extends Field {
@@ -11154,7 +10991,7 @@ var FieldObject = class extends Field {
11154
10991
  "object",
11155
10992
  name,
11156
10993
  CHECK_TYPE_OBJECT,
11157
- (v) => isPlainObject3(v) ? { ...v } : null,
10994
+ (v) => isPlainObject(v) ? { ...v } : null,
11158
10995
  defaultValue
11159
10996
  );
11160
10997
  }
@@ -11167,7 +11004,7 @@ var FieldMap = class extends Field {
11167
11004
  CHECK_TYPE_MAP,
11168
11005
  (v) => {
11169
11006
  if (v instanceof Map) return new Map(v);
11170
- if (Array.isArray(v) || isPlainObject3(v))
11007
+ if (Array.isArray(v) || isPlainObject(v))
11171
11008
  return new Map(Array.isArray(v) ? v : Object.entries(v));
11172
11009
  return null;
11173
11010
  },
@@ -11292,7 +11129,7 @@ function classFromData(name, { fields = {}, methods, statics }) {
11292
11129
  b.addField(field, dval, FieldCls);
11293
11130
  } else if (value?.component && value?.args !== void 0)
11294
11131
  b.addCompField(field, value.component, value.args);
11295
- else if (isPlainObject3(value)) b.addField(field, { ...value }, FieldObject);
11132
+ else if (isPlainObject(value)) b.addField(field, { ...value }, FieldObject);
11296
11133
  else {
11297
11134
  const FieldCls = value?.[FIELD_CLASS] ?? FieldAny;
11298
11135
  b.addField(field, value, FieldCls);
@@ -11316,10 +11153,24 @@ function validateDraftFields(current2, draft) {
11316
11153
  }
11317
11154
  }
11318
11155
  }
11319
- var META_KEYS = "name id fields methods views receive intent alter provide lookup spec extra commonStyle globalStyle scope _rawProvide _rawLookup".split(
11156
+ var META_KEYS = "name id fields methods views receive intent alter provide provideType lookup spec extra commonStyle globalStyle scope _rawProvide _rawLookup".split(
11320
11157
  " "
11321
11158
  );
11159
+ var RESERVED_COMPONENT_STATICS = /* @__PURE__ */ new Set([
11160
+ ...META_KEYS,
11161
+ "make",
11162
+ "getMetaClass",
11163
+ ...Object.getOwnPropertyNames(Component.prototype)
11164
+ ]);
11165
+ function assertNoReservedComponentStatics(statics = {}) {
11166
+ for (const name in statics) {
11167
+ if (RESERVED_COMPONENT_STATICS.has(name)) {
11168
+ throw new TypeError(`component static "${name}" is reserved by the framework`);
11169
+ }
11170
+ }
11171
+ }
11322
11172
  Component.fromSpec = (opts) => {
11173
+ assertNoReservedComponentStatics(opts.statics);
11323
11174
  const Class = classFromData(opts.name, opts);
11324
11175
  const comp = new Component(Class, opts);
11325
11176
  const metaClass = Class.getMetaClass();
@@ -11339,7 +11190,7 @@ Component.fromSpec = (opts) => {
11339
11190
  configurable: true
11340
11191
  });
11341
11192
  for (const key of Object.getOwnPropertyNames(Component.prototype))
11342
- if (key !== "constructor" && key !== "make" && !Object.hasOwn(Class, key))
11193
+ if (key !== "constructor" && !Object.hasOwn(Class, key))
11343
11194
  Class[key] = (...args) => comp[key](...args);
11344
11195
  return Class;
11345
11196
  };
@@ -11348,6 +11199,22 @@ var component = (opts) => Component.fromSpec(opts);
11348
11199
  // src/stack.js
11349
11200
  var STOP = /* @__PURE__ */ Symbol("STOP");
11350
11201
  var NEXT = /* @__PURE__ */ Symbol("NEXT");
11202
+ var DEFAULT_LOOKUP_ROUTE = ["dyn", "lex"];
11203
+ function routeLookup(route, lex, dyn) {
11204
+ for (let i = 0; i < route.length; i++) {
11205
+ const leg = route[i];
11206
+ if (leg === "dyn") {
11207
+ const v = dyn();
11208
+ if (v != null) return v;
11209
+ } else if (leg === "lex") {
11210
+ const v = lex();
11211
+ if (v != null) return v;
11212
+ } else {
11213
+ console.warn("unknown lookup route leg", leg, '- expected "dyn" or "lex"');
11214
+ }
11215
+ }
11216
+ return null;
11217
+ }
11351
11218
  function lookup(chain, name, dv = null) {
11352
11219
  let n = chain;
11353
11220
  while (n !== null) {
@@ -11398,14 +11265,21 @@ var Stack = class _Stack {
11398
11265
  this.ctx = ctx;
11399
11266
  }
11400
11267
  // Evaluate every provide the entered component publishes and push them as one
11401
- // dynBinds frame (keyed by each provide's symbol). No-op when there are no provides.
11268
+ // dynBinds frame, keyed by NAME. Published types go in the same frame: a type name
11269
+ // starts A-Z and a value name does not, so the two namespaces cannot collide and
11270
+ // nearest-ancestor-wins falls out of frame order for both. No-op with no provides.
11402
11271
  _pushProvides() {
11403
- const provide = this.comps.getCompFor(this.it)?.provide;
11404
- if (provide == null) return this;
11272
+ const comp = this.comps.getCompFor(this.it);
11273
+ if (comp == null) return this;
11274
+ const { provide, provideType } = comp;
11405
11275
  const dynObj = {};
11406
11276
  let has2 = false;
11407
11277
  for (const k in provide) {
11408
- dynObj[provide[k].symbol] = provide[k].val.eval(this);
11278
+ dynObj[k] = provide[k].val.eval(this);
11279
+ has2 = true;
11280
+ }
11281
+ for (const k in provideType) {
11282
+ dynObj[k] = provideType[k];
11409
11283
  has2 = true;
11410
11284
  }
11411
11285
  if (!has2) return this;
@@ -11430,30 +11304,36 @@ var Stack = class _Stack {
11430
11304
  const newViews = [name, views];
11431
11305
  return new _Stack(comps, it, binds, dynBinds, newViews, computeViewsId(newViews), ctx);
11432
11306
  }
11307
+ // Published types are stable per scope and would only churn the render cache, so
11308
+ // the cache key covers values alone.
11433
11309
  _pushDynBindValuesToArray(arr, comp) {
11434
- for (const k in comp.provide) arr.push(this._lookupProvide(comp.provide[k]));
11435
- for (const k in comp.lookup) arr.push(this._lookupAlias(comp.lookup[k]));
11436
- }
11437
- _lookupProvide(p) {
11438
- return lookup(this.dynBinds, p.symbol) ?? p.val.eval(this) ?? null;
11439
- }
11440
- _lookupAlias(lk) {
11441
- const sym = lk.getProducerSymbol(this);
11442
- return (sym != null ? lookup(this.dynBinds, sym) : null) ?? lk.val?.eval(this) ?? null;
11310
+ for (const k in comp.provide) arr.push(this.lookupDynamic(k));
11311
+ for (const k in comp.lookup) arr.push(this.lookupDynamic(k));
11443
11312
  }
11313
+ // `*name`: the nearest binding above (including this component's own provides,
11314
+ // pushed on entering it), else this component's declared default, else null.
11444
11315
  lookupDynamic(name) {
11316
+ const v = lookup(this.dynBinds, name);
11317
+ if (v != null) return v;
11445
11318
  const comp = this.comps.getCompFor(this.it);
11446
- if (comp == null) return null;
11447
- const lk = comp.lookup[name];
11448
- if (lk !== void 0) return this._lookupAlias(lk);
11449
- const p = comp.provide[name];
11450
- return p !== void 0 ? this._lookupProvide(p) : null;
11319
+ return comp?.lookup[name]?.val?.eval(this) ?? null;
11451
11320
  }
11452
11321
  lookupBind(name) {
11453
11322
  return lookup(this.binds, name);
11454
11323
  }
11455
- lookupType(name) {
11456
- return this.comps.getCompFor(this.it).scope.lookupComponent(name);
11324
+ // The `lex` leg: what a name means in the registration scope of the component being
11325
+ // rendered. The scope chain holds components, so this leg only ever answers for a
11326
+ // type name — for a value name it is a miss, which is why one default route serves
11327
+ // both. Guarded: a non-component `it` has no scope to ask.
11328
+ _lookupLex(name) {
11329
+ return this.comps.getCompFor(this.it)?.scope.lookupComponent(name) ?? null;
11330
+ }
11331
+ lookupRouted(name, route = DEFAULT_LOOKUP_ROUTE) {
11332
+ return routeLookup(
11333
+ route,
11334
+ () => this._lookupLex(name),
11335
+ () => this.lookupDynamic(name)
11336
+ );
11457
11337
  }
11458
11338
  lookupFieldRaw(name) {
11459
11339
  return this.it[name] ?? null;
@@ -11462,12 +11342,6 @@ var Stack = class _Stack {
11462
11342
  const fn = this.it[name];
11463
11343
  return fn instanceof Function ? fn.call(this.it) : null;
11464
11344
  }
11465
- // Bare implicit event names are gone: a sigil-less word cannot reach a
11466
- // handler-arg slot anymore, so this only ever serves stale NameVals parsed
11467
- // before the removal (e.g. macro-attr pass-throughs). Always null.
11468
- lookupName(_name) {
11469
- return null;
11470
- }
11471
11345
  // The dispatched DOM event / drag info, read only by EventMemberVal's
11472
11346
  // `e.<member>` handler args. Null outside a live event transaction.
11473
11347
  lookupEvent() {
@@ -11504,9 +11378,6 @@ var State2 = class {
11504
11378
  this.val = val;
11505
11379
  for (const sub of this.changeSubs) sub({ val, old, info, timestamp: Date.now() });
11506
11380
  }
11507
- update(fn, info) {
11508
- return this.set(fn(this.val), info);
11509
- }
11510
11381
  };
11511
11382
  var Transactor = class {
11512
11383
  constructor(comps, rootValue) {
@@ -11567,7 +11438,7 @@ var Transactor = class {
11567
11438
  // Build and dispatch the observer record for a settled transaction. The
11568
11439
  // resolved handler (`_resolvedHandler`/`_matched`) and per-leaf before/after
11569
11440
  // (`_before`/`_after`) were captured while the handler ran (see callHandler /
11570
- // updateRootValue). No-op when nobody is observing.
11441
+ // Transaction.run). No-op when nobody is observing.
11571
11442
  _emitTransaction(transaction, root) {
11572
11443
  if (this._observers.length === 0) return;
11573
11444
  if (transaction._resolvedHandler === void 0) return;
@@ -11599,8 +11470,13 @@ var Transactor = class {
11599
11470
  }
11600
11471
  return child;
11601
11472
  }
11602
- pushSend(path, name, args = [], opts = {}, parent = null) {
11603
- const t = new SendEvent(path, this, name, args, parent, opts);
11473
+ // `origin` is where the message came FROM, pinned now for the same reason an
11474
+ // intent's answerPath is: a reply must reach the sender that asked even if a key
11475
+ // moved while the message was in flight. Null when nobody is waiting — a host
11476
+ // sendAtRoot or a view's own `@on.*` — and ctx.sendReply refuses on that.
11477
+ pushSend(path, name, args = [], parent = null, origin = null) {
11478
+ const t = new SendEvent(path, this, name, args, parent);
11479
+ t.origin = origin === null ? null : origin.toTransactionPath().pinKeys(this.state.val);
11604
11480
  this.pushTransaction(t);
11605
11481
  return this._link(t, parent);
11606
11482
  }
@@ -11613,9 +11489,9 @@ var Transactor = class {
11613
11489
  walk.advance();
11614
11490
  return walk;
11615
11491
  }
11616
- // Drain queued transactions and await in-flight requests until quiescent. Each
11617
- // awaited request enqueues a ResponseEvent, which may dispatch more work, so we
11618
- // loop. `maxTurns` backstops a pathological non-terminating cascade.
11492
+ // Drain queued transactions and await async intent handlers until quiescent. A
11493
+ // completed handler may enqueue an answer, which may dispatch more work, so we loop.
11494
+ // `maxTurns` backstops a pathological non-terminating cascade.
11619
11495
  async settle(maxTurns = 1e4) {
11620
11496
  while ((this.hasPendingTransactions || this._inflight.size) && maxTurns-- > 0) {
11621
11497
  while (this.hasPendingTransactions) this.transactNext();
@@ -11672,9 +11548,6 @@ var Transaction = class {
11672
11548
  whenSubtreeSettled() {
11673
11549
  return this.completion.whenSubtreeSettled();
11674
11550
  }
11675
- run(rootValue, comps) {
11676
- return this.updateRootValue(rootValue, comps);
11677
- }
11678
11551
  afterTransaction() {
11679
11552
  }
11680
11553
  // Ending a walk and forwarding belong to the two dispatch buckets; the base warns
@@ -11686,12 +11559,6 @@ var Transaction = class {
11686
11559
  forward(_opts) {
11687
11560
  console.warn('ctx.forward() needs a "receive" or "intent" handler - ignored');
11688
11561
  }
11689
- buildRootStack(root, comps) {
11690
- return Stack.root(comps, root);
11691
- }
11692
- buildStack(root, comps) {
11693
- return this.path.toTransactionPath().buildStack(this.buildRootStack(root, comps));
11694
- }
11695
11562
  // The kind reported to observers (see Transactor.observe); null on the base.
11696
11563
  get observeKind() {
11697
11564
  return null;
@@ -11711,12 +11578,11 @@ var Transaction = class {
11711
11578
  return null;
11712
11579
  }
11713
11580
  // The path used to apply the mutation. Teleports dynamic-var renders so it lands on
11714
- // the data's real location (the dispatch `this.path` keeps intermediates). A subclass
11715
- // may override to supply a pre-resolved path (see ResponseEvent's pinned keys).
11581
+ // the data's real location (the dispatch `this.path` keeps intermediates).
11716
11582
  getTransactionPath() {
11717
11583
  return this.path.toTransactionPath().compact();
11718
11584
  }
11719
- updateRootValue(curRoot, comps) {
11585
+ run(curRoot, comps) {
11720
11586
  const txnPath = this.getTransactionPath();
11721
11587
  const curLeaf = txnPath.lookup(curRoot);
11722
11588
  const newLeaf = produce(curLeaf, (draft) => {
@@ -11773,8 +11639,8 @@ var InputEvent = class extends Transaction {
11773
11639
  }
11774
11640
  this.transactor.pushIntent(this.dispatchPath, name, args, rest, this);
11775
11641
  }
11776
- buildRootStack(root, comps) {
11777
- return Stack.root(comps, root, this);
11642
+ buildStack(root, comps) {
11643
+ return this.path.toTransactionPath().buildStack(Stack.root(comps, root, this));
11778
11644
  }
11779
11645
  getHandlerAndArgs(root, _instance, comps) {
11780
11646
  const stack = this.buildStack(root, comps);
@@ -11792,11 +11658,10 @@ var InputEvent = class extends Transaction {
11792
11658
  }
11793
11659
  };
11794
11660
  var NameArgsTransaction = class extends Transaction {
11795
- constructor(path, transactor, name, args, parentTransaction, opts = {}) {
11661
+ constructor(path, transactor, name, args, parentTransaction) {
11796
11662
  super(path, transactor, parentTransaction);
11797
11663
  this.name = name;
11798
11664
  this.args = args;
11799
- this.opts = opts;
11800
11665
  this.targetPath = path;
11801
11666
  }
11802
11667
  handlerProp = null;
@@ -11855,7 +11720,7 @@ var SendEvent = class extends NameArgsTransaction {
11855
11720
  var IntentEvent = class extends NameArgsTransaction {
11856
11721
  handlerProp = "intent";
11857
11722
  constructor(path, transactor, walk) {
11858
- super(path, transactor, walk.name, walk.args, walk.parent, {});
11723
+ super(path, transactor, walk.name, walk.args, walk.parent);
11859
11724
  this.walk = walk;
11860
11725
  this.targetPath = walk.origin;
11861
11726
  }
@@ -11955,7 +11820,7 @@ var IntentWalk = class {
11955
11820
  async _runLex(chain, i) {
11956
11821
  if (this.ended) return;
11957
11822
  if (i >= chain.length) return this.advance();
11958
- const ctx = new IntentContext(this.origin, this.transactor, this.parent);
11823
+ const ctx = new Dispatcher(this.origin, this.transactor, this.parent);
11959
11824
  try {
11960
11825
  const res = await chain[i].fn.apply(null, [...this.args, ctx]);
11961
11826
  if (res === PASS) return this._runLex(chain, i + 1);
@@ -12008,7 +11873,7 @@ var IntentWalk = class {
12008
11873
  this.ended = true;
12009
11874
  if (name === null) return this.release?.();
12010
11875
  const path = this.answerPath ?? this.origin;
12011
- const t = new SendEvent(path, this.transactor, name, args, this.parent, {});
11876
+ const t = new SendEvent(path, this.transactor, name, args, this.parent);
12012
11877
  t._isAnswer = true;
12013
11878
  this.transactor.pushTransaction(t);
12014
11879
  if (this.release) t.completion.whenSubtreeSettled().then(this.release);
@@ -12047,7 +11912,7 @@ var Completion = class {
12047
11912
  this.val = val;
12048
11913
  this._selfResolve?.(val);
12049
11914
  }
12050
- // Settle self even when no handler produced a value (skipSelf / undefined / throw paths).
11915
+ // Settle self even when no handler produced a value (undefined-state / throw paths).
12051
11916
  ensureSelfSettled() {
12052
11917
  if (!this.selfSettled) this.markSelfSettled(this.val);
12053
11918
  }
@@ -12093,12 +11958,64 @@ var Dispatcher = class {
12093
11958
  get at() {
12094
11959
  return new PathChanges(this);
12095
11960
  }
11961
+ // The render-time Stack, rebuilt on demand. A handler does not get one: the stack
11962
+ // that evaluated its arguments is a local in getHandlerAndArgs and is gone by the
11963
+ // time the body runs, and send/intent transactions never build one at all. Both
11964
+ // halves it needs are pinned on this ctx, so the `dyn` leg reconstructs it — and
11965
+ // only the `dyn` leg does, which is why this is lazy rather than eager.
11966
+ //
11967
+ // The path is compacted, so per-item binds (`@each`, `@enrich-with`) are not
11968
+ // replayed; provides are pushed on every component frame either way, so a provide
11969
+ // that reads a loop binding is the one case this cannot reproduce faithfully.
11970
+ _stack() {
11971
+ this._stackMemo ??= this.path.toTransactionPath().buildStack(Stack.root(this.transactor.comps, this.root, this.parent));
11972
+ return this._stackMemo;
11973
+ }
11974
+ // Resolve a name the way the renderer would. `opts.route` takes the same legs in
11975
+ // the same spelling as `ctx.intent` — `["dyn"]` the render ancestry, `["lex"]` the
11976
+ // registration scope, default both.
11977
+ lookup(name, opts) {
11978
+ const route = opts?.route ?? DEFAULT_LOOKUP_ROUTE;
11979
+ return routeLookup(
11980
+ route,
11981
+ () => this._lookupLex(name),
11982
+ () => this._stack()?.lookupDynamic(name) ?? null
11983
+ );
11984
+ }
11985
+ // The `lex` leg without a Stack: the scope of the component whose handler is
11986
+ // running, which is the leaf of this ctx's path.
11987
+ _lookupLex(name) {
11988
+ let Comp = null;
11989
+ this.walkPath((c) => {
11990
+ Comp = c;
11991
+ return false;
11992
+ });
11993
+ return Comp?.scope?.lookupComponent(name) ?? null;
11994
+ }
11995
+ // A component lookup is a value lookup constrained to a component. The `lex` leg
11996
+ // can only ever answer with one; the `dyn` leg reads a binding an ancestor
11997
+ // published, so it is the leg that has to be checked.
11998
+ lookupType(name, opts) {
11999
+ const v = this.lookup(name, opts);
12000
+ if (v == null) {
12001
+ this.transactor.refuse("TYPE_NOT_FOUND", {
12002
+ name,
12003
+ route: opts?.route ?? DEFAULT_LOOKUP_ROUTE
12004
+ });
12005
+ return null;
12006
+ }
12007
+ if (v?.[COMPONENT] == null) {
12008
+ this.transactor.refuse("TYPE_NOT_COMPONENT", { name, got: typeof v });
12009
+ return null;
12010
+ }
12011
+ return v;
12012
+ }
12096
12013
  // A message is ADDRESSED: it names one component and stops there.
12097
- send(name, args, opts) {
12098
- return this.sendAtPath(this.path, name, args, opts);
12014
+ send(name, args) {
12015
+ return this.sendAtPath(this.path, name, args);
12099
12016
  }
12100
- sendAtPath(path, name, args, opts) {
12101
- return this.transactor.pushSend(path, name, args, opts, this.parent);
12017
+ sendAtPath(path, name, args) {
12018
+ return this.transactor.pushSend(path, name, args, this.parent, this.path);
12102
12019
  }
12103
12020
  // An intent is ROUTED: it names a job and walks until something answers. The verb
12104
12021
  // does not decide which scope answers — `opts.route` does, written here at the call
@@ -12109,9 +12026,6 @@ var Dispatcher = class {
12109
12026
  intentAtPath(path, name, args, opts) {
12110
12027
  return this.transactor.pushIntent(path, name, args, opts, this.parent);
12111
12028
  }
12112
- lookupTypeFor(name, inst) {
12113
- return this.transactor.comps.getCompFor(inst).scope.lookupComponent(name);
12114
- }
12115
12029
  };
12116
12030
  var EventContext = class extends Dispatcher {
12117
12031
  get name() {
@@ -12128,6 +12042,19 @@ var EventContext = class extends Dispatcher {
12128
12042
  fail(error) {
12129
12043
  return this.parent.walk === void 0 ? warnNotIntent("fail") : this.parent.walk.answer("Error", error);
12130
12044
  }
12045
+ // Reply to the sender of the MESSAGE being handled. An intent answers under a name
12046
+ // the runtime derives (`<name>Ok`), because the raiser asked a question and declared
12047
+ // arms for it; a message did not, so the replier names the reply itself and the
12048
+ // sender handles it like any other message. Refuses when nobody sent this — a view's
12049
+ // own `@on.*`, or a host sendAtRoot.
12050
+ sendReply(name, args) {
12051
+ const origin = this.parent?.origin ?? null;
12052
+ if (origin == null) {
12053
+ this.transactor.refuse("NO_SENDER", { name });
12054
+ return null;
12055
+ }
12056
+ return this.sendAtPath(origin, name, args);
12057
+ }
12131
12058
  // End the walk answering nothing — "served, and no answer".
12132
12059
  stop() {
12133
12060
  return this.parent.stop();
@@ -12139,8 +12066,6 @@ var EventContext = class extends Dispatcher {
12139
12066
  return this.parent.forward(opts);
12140
12067
  }
12141
12068
  };
12142
- var IntentContext = class extends Dispatcher {
12143
- };
12144
12069
  function warnNotIntent(verb) {
12145
12070
  console.warn(`ctx.${verb}() is only meaningful in an "intent" handler - ignored`);
12146
12071
  }
@@ -12149,8 +12074,8 @@ var PathChanges = class extends PathBuilder {
12149
12074
  super();
12150
12075
  this.dispatcher = dispatcher;
12151
12076
  }
12152
- send(name, args, opts) {
12153
- return this.dispatcher.sendAtPath(this.buildPath(), name, args, opts);
12077
+ send(name, args) {
12078
+ return this.dispatcher.sendAtPath(this.buildPath(), name, args);
12154
12079
  }
12155
12080
  intent(name, args, opts) {
12156
12081
  return this.dispatcher.intentAtPath(this.buildPath(), name, args, opts);
@@ -12707,8 +12632,12 @@ function lintIdToMessage(id, info) {
12707
12632
  return `Provide '${info.name}' value '${info.value}' must be a field ('.f') or seq-access ('.s[.k]') — a method/constant can't be a render target`;
12708
12633
  case "LOOKUP_BAD_SHAPE":
12709
12634
  return `Lookup '${info.name}' has an invalid shape: ${info.problem}`;
12710
- case "LOOKUP_TARGET_MALFORMED":
12711
- return `Lookup '${info.name}' target '${info.target}' must be 'Producer.provideName' (a string, or the 'for' of { for, default })`;
12635
+ case "LOOKUP_NO_PROVIDER":
12636
+ return info.hasDefault ? `Lookup '${info.name}' is provided by no component in scope, so it always resolves to its default` : `Lookup '${info.name}' is provided by no component in scope — add a 'provide' for it, or give this lookup a default`;
12637
+ case "PROVIDE_TYPE_BAD_SHAPE":
12638
+ return `Provide '${info.name}' starts uppercase, so it publishes a component type — its value must be 'self', not '${info.value}'`;
12639
+ case "PROVIDE_NAME_COLLISION":
12640
+ return `Provide '${info.name}' is also provided by '${info.other}' in the same scope — one name, one provider, so a lookup can find it`;
12712
12641
  case "UNKNOWN_MACRO_ARG":
12713
12642
  return `Argument '${info.name}' is not declared in macro '${info.macroName}'`;
12714
12643
  case "UNKNOWN_DIRECTIVE":
@@ -12980,9 +12909,10 @@ var App = class {
12980
12909
  }
12981
12910
  compile() {
12982
12911
  for (const Comp of this.comps.byId.values()) {
12983
- Comp.compile(this.ParseContext);
12984
- for (const key in Comp.views)
12985
- for (const name of Comp.views[key].ctx.genEventNames()) this._eventNames.add(name);
12912
+ const meta = Comp[COMPONENT];
12913
+ meta.compile(this.ParseContext);
12914
+ for (const key in meta.views)
12915
+ for (const name of meta.views[key].ctx.genEventNames()) this._eventNames.add(name);
12986
12916
  }
12987
12917
  this._compiled = true;
12988
12918
  }
@@ -13008,8 +12938,8 @@ var App = class {
13008
12938
  for (const name of this._eventNames)
13009
12939
  this.rootNode.removeEventListener(name, this, listenerOpts(name));
13010
12940
  }
13011
- sendAtRoot(name, args, opts) {
13012
- this.transactor.pushSend(new Path([]), name, args, opts);
12941
+ sendAtRoot(name, args) {
12942
+ this.transactor.pushSend(new Path([]), name, args);
13013
12943
  }
13014
12944
  registerComponents(comps, opts) {
13015
12945
  const scope = this.compStack.enter();
@@ -13085,6 +13015,182 @@ var DragInfo = class {
13085
13015
  }
13086
13016
  };
13087
13017
 
13018
+ // src/cache.js
13019
+ var isWeakKey = (k) => k !== null && (typeof k === "object" || typeof k === "function");
13020
+ var NullDomCache = class {
13021
+ get(_keys, _cacheKey) {
13022
+ }
13023
+ set(_keys, _cacheKey, _v) {
13024
+ }
13025
+ evict() {
13026
+ return { hit: 0, miss: 0, badKey: 0 };
13027
+ }
13028
+ };
13029
+ var WeakMapDomCache = class {
13030
+ constructor() {
13031
+ this.hit = this.miss = this.badKey = 0;
13032
+ this.keysByLen = /* @__PURE__ */ new Map();
13033
+ }
13034
+ _returnValue(r) {
13035
+ if (r === void 0) this.miss += 1;
13036
+ else this.hit += 1;
13037
+ return r;
13038
+ }
13039
+ get(keys, cacheKey) {
13040
+ const len = keys.length;
13041
+ let cur = this.keysByLen.get(len);
13042
+ if (!cur) return this._returnValue(void 0);
13043
+ for (let i = 0; i < len - 1; i++) {
13044
+ cur = cur.get(keys[i]);
13045
+ if (!cur) return this._returnValue(void 0);
13046
+ }
13047
+ return this._returnValue(cur.get(keys[len - 1])?.[cacheKey]);
13048
+ }
13049
+ set(keys, cacheKey, v) {
13050
+ const len = keys.length;
13051
+ let cur = this.keysByLen.get(len);
13052
+ if (!cur) {
13053
+ cur = /* @__PURE__ */ new WeakMap();
13054
+ this.keysByLen.set(len, cur);
13055
+ }
13056
+ for (let i = 0; i < len - 1; i++) {
13057
+ const key = keys[i];
13058
+ let next = cur.get(key);
13059
+ if (!next) {
13060
+ if (!isWeakKey(key)) {
13061
+ this.badKey += 1;
13062
+ return;
13063
+ }
13064
+ next = /* @__PURE__ */ new WeakMap();
13065
+ cur.set(key, next);
13066
+ }
13067
+ cur = next;
13068
+ }
13069
+ const lastKey = keys[len - 1];
13070
+ const leaf = cur.get(lastKey);
13071
+ if (leaf) leaf[cacheKey] = v;
13072
+ else if (isWeakKey(lastKey)) cur.set(lastKey, { [cacheKey]: v });
13073
+ else this.badKey += 1;
13074
+ }
13075
+ evict() {
13076
+ const { hit, miss, badKey } = this;
13077
+ this.hit = this.miss = this.badKey = 0;
13078
+ this.keysByLen = /* @__PURE__ */ new Map();
13079
+ return { hit, miss, badKey };
13080
+ }
13081
+ };
13082
+
13083
+ // src/renderer.js
13084
+ var DATASET_ATTRS = ["nid", "cid", "eid", "vid", "si", "sk"];
13085
+ var Renderer = class {
13086
+ constructor(comps) {
13087
+ this.comps = comps;
13088
+ this.cache = new WeakMapDomCache();
13089
+ this.renderTag = h;
13090
+ }
13091
+ renderFragment(childs) {
13092
+ return new VFragment(childs);
13093
+ }
13094
+ renderComment(text) {
13095
+ return new VComment(text);
13096
+ }
13097
+ setNullCache() {
13098
+ this.cache = new NullDomCache();
13099
+ }
13100
+ renderToDOM(stack, val) {
13101
+ const rootNode = document.createElement("div");
13102
+ const rOpts = { document };
13103
+ render(h("DIV", null, [this.renderRoot(stack, val)]), rootNode, rOpts);
13104
+ return rootNode.childNodes[0];
13105
+ }
13106
+ renderToString(stack, val, cleanAttrs = true) {
13107
+ const dom = this.renderToDOM(stack, val);
13108
+ if (cleanAttrs) {
13109
+ const nodes = dom.querySelectorAll("[data-nid],[data-cid],[data-eid]");
13110
+ for (const { dataset } of nodes) for (const name of DATASET_ATTRS) delete dataset[name];
13111
+ }
13112
+ return dom.innerHTML;
13113
+ }
13114
+ renderRoot(stack, val, viewName = null) {
13115
+ const comp = this.comps.getCompFor(val);
13116
+ if (comp === null) return null;
13117
+ return this._rValComp(stack, val, comp, comp.getView(viewName).anode, "ROOT", viewName);
13118
+ }
13119
+ renderIt(stack, node, key, viewName) {
13120
+ const comp = this.comps.getCompFor(stack.it);
13121
+ return comp ? this._rValComp(stack, stack.it, comp, node, key, viewName) : null;
13122
+ }
13123
+ // `node` is the parse node of the render site (`<x render>` / `render-it` /
13124
+ // `render-each`, or the view's root anode for the app root). It keys the
13125
+ // cache as a globally-unique object: node ids alone are unique only within a
13126
+ // single view, so the same value rendered by two components (e.g. through a
13127
+ // shared dynamic-var sequence) would otherwise collide in the cache.
13128
+ _rValComp(stack, val, comp, node, key, viewName) {
13129
+ const cacheKey = `${viewName ?? ""}${stack.viewsId ?? ""}${key}`;
13130
+ const cachePath = [node, val];
13131
+ stack._pushDynBindValuesToArray(cachePath, comp);
13132
+ const cachedNode = this.cache.get(cachePath, cacheKey);
13133
+ if (cachedNode) return cachedNode;
13134
+ const view = viewName ? comp.getView(viewName) : stack.lookupBestView(comp.views, "main");
13135
+ const body = this.renderView(view, stack);
13136
+ if (body == null) return null;
13137
+ const meta = this._renderMetadata({
13138
+ $: "Comp",
13139
+ nid: node?.nodeId ?? null,
13140
+ cid: comp.id,
13141
+ vid: view.name
13142
+ });
13143
+ const dom = new VFragment([meta, body]);
13144
+ this.cache.set(cachePath, cacheKey, dom);
13145
+ return dom;
13146
+ }
13147
+ pushEachEntry(r, nid, attrName, key, dom) {
13148
+ r.push(this._renderMetadata({ $: "Each", nid, [attrName]: key }), dom);
13149
+ }
13150
+ renderEachWhen(stack, iterInfo, view, nid) {
13151
+ const { seq, filter, loopWith, enricher } = iterInfo.eval(stack);
13152
+ const r = [];
13153
+ const it = stack.it;
13154
+ const renderOne = (key, value, attrName, binds) => {
13155
+ const cachePath = enricher ? [view, it, value] : [view, value];
13156
+ const cacheKey = `${stack.viewsId ?? ""}${nid}${key}`;
13157
+ const cachedNode = this.cache.get(cachePath, cacheKey);
13158
+ if (cachedNode) this.pushEachEntry(r, nid, attrName, key, cachedNode);
13159
+ else {
13160
+ const dom = this.renderView(view, stack.enter(value, binds, false));
13161
+ if (dom != null) this.pushEachEntry(r, nid, attrName, key, dom);
13162
+ this.cache.set(cachePath, cacheKey, dom);
13163
+ }
13164
+ };
13165
+ walkLoopBindings(
13166
+ { seq, it, filter, loopWith, enricher, ctx: makeLoopCtx(stack, filter) },
13167
+ renderOne
13168
+ );
13169
+ return r;
13170
+ }
13171
+ renderView(view, stack) {
13172
+ let n = stack.binds[1];
13173
+ while (n !== null) {
13174
+ const b = n[0];
13175
+ if (b.isFrame) {
13176
+ if (stack.it !== b.it) break;
13177
+ console.error("recursion detected", stack.it, b.it);
13178
+ return new VComment("RECURSION AVOIDED");
13179
+ }
13180
+ n = n[1];
13181
+ }
13182
+ return view.render(stack, this);
13183
+ }
13184
+ _renderMetadata(info) {
13185
+ return new VComment(`§${JSON.stringify(info)}§`);
13186
+ }
13187
+ // Prefix a loop-less @enrich-with subtree with a boundary meta so event-path
13188
+ // reconstruction replays its binds (mirrors the §Each§ / §Comp§ metas).
13189
+ renderScopeMeta(nid, dom) {
13190
+ return new VFragment([this._renderMetadata({ $: "Scope", nid }), dom]);
13191
+ }
13192
+ };
13193
+
13088
13194
  // index.js
13089
13195
  var css = String.raw;
13090
13196
  var html = String.raw;
@@ -13111,24 +13217,6 @@ async function compileClassesToStyleText(app, compileClasses, Ctx = ParseCtxClas
13111
13217
  }
13112
13218
 
13113
13219
  // src/util/testing.js
13114
- var plainArrayIter = (seq, visit, start, end) => {
13115
- const [s, e] = normalizeRange(start, end, seq.length);
13116
- for (let i = s; i < e; i++) visit(i, seq[i]);
13117
- };
13118
- var plainMapIter = (seq, visit, start, end) => {
13119
- const [s, e] = normalizeRange(start, end, seq.size);
13120
- let i = 0;
13121
- for (const [k, v] of seq.entries()) {
13122
- if (i >= e) break;
13123
- if (i >= s) visit(k, v);
13124
- i++;
13125
- }
13126
- };
13127
- function pickIter(seq) {
13128
- if (Array.isArray(seq)) return plainArrayIter;
13129
- if (seq instanceof Map) return plainMapIter;
13130
- return getSeqInfo(seq);
13131
- }
13132
13220
  function resolveAlter(Comp, name) {
13133
13221
  if (name == null) return null;
13134
13222
  const fn = Comp.alter?.[name];
@@ -13146,30 +13234,12 @@ function collectIterBindings(Comp, compInstance, seq, opts = {}) {
13146
13234
  const scope = scopeEnrichFn ? scopeEnrichFn.call(it) ?? {} : opts.scope ?? {};
13147
13235
  const ctx = {
13148
13236
  lookup: (name) => scope[name],
13149
- filter: (key, value, iterData2) => whenFn.call(it, key, value, iterData2)
13237
+ filter: (key, value, iterData) => whenFn.call(it, key, value, iterData)
13150
13238
  };
13151
- const { iterData, start, end, keys } = unpackLoopResult(loopWithFn.call(it, seq, ctx), seq);
13152
13239
  const out = [];
13153
- if (keys) {
13154
- for (const key of keys) {
13155
- const value = seqGet(seq, key);
13156
- const binds = { key, value };
13157
- if (enrichFn) enrichFn.call(it, binds, key, value, iterData);
13158
- out.push(binds);
13159
- }
13160
- return out;
13161
- }
13162
- const iter = pickIter(seq);
13163
- iter(
13164
- seq,
13165
- (key, value) => {
13166
- if (!whenFn.call(it, key, value, iterData)) return;
13167
- const binds = { key, value };
13168
- if (enrichFn) enrichFn.call(it, binds, key, value, iterData);
13169
- out.push(binds);
13170
- },
13171
- start,
13172
- end
13240
+ walkLoopBindings(
13241
+ { seq, it, filter: whenFn, loopWith: loopWithFn, enricher: enrichFn, ctx },
13242
+ (_key, _value, _attrName, binds) => out.push(binds)
13173
13243
  );
13174
13244
  return out;
13175
13245
  }
@@ -13327,7 +13397,7 @@ export {
13327
13397
  HANDLER_NAME_COLLISION,
13328
13398
  IF_NO_BRANCH_SET,
13329
13399
  LOOKUP_BAD_SHAPE,
13330
- LOOKUP_TARGET_MALFORMED,
13400
+ LOOKUP_NO_PROVIDER,
13331
13401
  LintClassCollectorCtx,
13332
13402
  LintComponentResult,
13333
13403
  LintContext,
@@ -13343,7 +13413,9 @@ export {
13343
13413
  ModuleTests,
13344
13414
  PASS,
13345
13415
  PLACEHOLDERLESS_TEMPLATE_STRING,
13416
+ PROVIDE_NAME_COLLISION,
13346
13417
  PROVIDE_NOT_ADDRESSABLE,
13418
+ PROVIDE_TYPE_BAD_SHAPE,
13347
13419
  ParseContext,
13348
13420
  RECEIVE_HANDLER_NOT_IMPLEMENTED,
13349
13421
  REDUNDANT_TEMPLATE_STRING,