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.
@@ -1102,9 +1102,6 @@ var init_path = __esm({
1102
1102
  lookup(_v, dval = null) {
1103
1103
  return dval;
1104
1104
  }
1105
- setValue(root, _v) {
1106
- return root;
1107
- }
1108
1105
  setDraftValue(_root, _v) {
1109
1106
  }
1110
1107
  enterFrame(stack, _prev, next) {
@@ -1133,9 +1130,6 @@ var init_path = __esm({
1133
1130
  lookup(v, _dval) {
1134
1131
  return v;
1135
1132
  }
1136
- setValue(_root, v) {
1137
- return v;
1138
- }
1139
1133
  enterFrame(stack, _prev, next) {
1140
1134
  return stack.enter(next, { ...this.binds }, false);
1141
1135
  }
@@ -1173,9 +1167,6 @@ var init_path = __esm({
1173
1167
  lookup(v, dval = null) {
1174
1168
  return readKey(v, this.field, dval);
1175
1169
  }
1176
- setValue(root, v) {
1177
- return produce(root, (draft) => this.setDraftValue(draft, v));
1178
- }
1179
1170
  setDraftValue(root, v) {
1180
1171
  writeKey(root, this.field, v);
1181
1172
  }
@@ -1198,9 +1189,6 @@ var init_path = __esm({
1198
1189
  lookup(v, dval = null) {
1199
1190
  return readSeqKey(readKey(v, this.field, null), this.key, dval);
1200
1191
  }
1201
- setValue(root, v) {
1202
- return produce(root, (draft) => this.setDraftValue(draft, v));
1203
- }
1204
1192
  setDraftValue(root, v) {
1205
1193
  const seq = readKey(root, this.field, null);
1206
1194
  if (seq != null) writeSeqKey(seq, this.key, v);
@@ -1223,9 +1211,6 @@ var init_path = __esm({
1223
1211
  const key = readKey(v, this.keyField, NONE);
1224
1212
  return key !== NONE && seq !== NONE ? readSeqKey(seq, key, dval) : dval;
1225
1213
  }
1226
- setValue(root, v) {
1227
- return produce(root, (draft) => this.setDraftValue(draft, v));
1228
- }
1229
1214
  setDraftValue(root, v) {
1230
1215
  const seq = readKey(root, this.seqField, NONE);
1231
1216
  const key = readKey(root, this.keyField, NONE);
@@ -1253,9 +1238,6 @@ var init_path = __esm({
1253
1238
  lookup(v, _dval) {
1254
1239
  return v;
1255
1240
  }
1256
- setValue(_root, v) {
1257
- return v;
1258
- }
1259
1241
  // Replay the renderer's per-item binds (key, value + any @enrich-with binds)
1260
1242
  // so a rebuilt stack matches the one @each rendered with.
1261
1243
  enterFrame(stack, _prev, next) {
@@ -1288,10 +1270,6 @@ var init_path = __esm({
1288
1270
  warnRawDynStep("lookup", this);
1289
1271
  return dval;
1290
1272
  }
1291
- setValue(root, _v) {
1292
- warnRawDynStep("setValue", this);
1293
- return root;
1294
- }
1295
1273
  enterFrame(stack, _prev, _next) {
1296
1274
  warnRawDynStep("enterFrame", this);
1297
1275
  return stack;
@@ -1362,7 +1340,7 @@ var init_path = __esm({
1362
1340
  }
1363
1341
  // Resolve every field-keyed step (e.g. `SeqAccessStep`) against `root`, freezing the
1364
1342
  // key as it is *now* so a later lookup/setValue lands on the same item even if the
1365
- // keyField changed meanwhile (e.g. the selected tab moved while a request was in
1343
+ // keyField changed meanwhile (e.g. the selected tab moved while an intent was in
1366
1344
  // flight). Returns a new Path with those steps replaced; `this` if nothing pinned.
1367
1345
  // Must be called on a transaction path (no DynSteps — call toTransactionPath first).
1368
1346
  pinKeys(root) {
@@ -1625,7 +1603,6 @@ function parseToken(s, px) {
1625
1603
  if (m !== null) return new EventMemberVal(s.split(".").slice(1));
1626
1604
  }
1627
1605
  if (c0 >= 97 && c0 <= 122) return mkVal(s, NameVal);
1628
- if (c0 >= 65 && c0 <= 90) return mkVal(s, TypeVal);
1629
1606
  return null;
1630
1607
  }
1631
1608
  function _parseSeqAccess(s, px) {
@@ -1740,12 +1717,11 @@ function kindOf(val) {
1740
1717
  if (val instanceof MethodVal) return K_METHOD;
1741
1718
  if (val instanceof BindVal) return K_BIND;
1742
1719
  if (val instanceof DynVal) return K_DYN;
1743
- if (val instanceof TypeVal) return K_TYPE;
1744
1720
  if (val instanceof NameVal) return K_NAME;
1745
1721
  if (val instanceof EventMemberVal) return K_EVENT;
1746
1722
  return 0;
1747
1723
  }
1748
- var VALID_VAL_ID_RE, isValidValId, VALID_FLOAT_RE, STR_TPL_SPLIT_RE, mkVal, VAL_TOKEN_RE, tokenizeValue, unescapeStr, K_CONST, K_STRTPL, K_FIELD, K_BIND, K_DYN, K_NAME, K_TYPE, K_SEQ, K_METHOD, K_EVENT, G_BOOL, G_TEXT, G_COMPONENT, G_SEQUENCE, G_PROVIDE, G_FIELD, G_VALUE, G_HANDLER_ARG, G_ALL, toNullIfNaN, predTruthy, PREDICATES, BaseVal, ConstVal, NULL_CONST_VAL, PredicateVal, VarVal, StrTplVal, NameVal, HandlerNameVal, mk404Handler, TypeVal, keyIs, macCtrl, nullSafe, EVENT_CONVENIENCES, EventMemberVal, RenderVal, RenderNameVal, BindVal, BindMemberVal, DynVal, FieldVal, MethodVal, SeqAccessVal;
1724
+ var VALID_VAL_ID_RE, isValidValId, VALID_FLOAT_RE, STR_TPL_SPLIT_RE, mkVal, VAL_TOKEN_RE, tokenizeValue, unescapeStr, K_CONST, K_STRTPL, K_FIELD, K_BIND, K_DYN, K_NAME, K_SEQ, K_METHOD, K_EVENT, G_BOOL, G_TEXT, G_COMPONENT, G_SEQUENCE, G_PROVIDE, G_FIELD, G_VALUE, G_HANDLER_ARG, G_ALL, toNullIfNaN, predTruthy, PREDICATES, BaseVal, ConstVal, NULL_CONST_VAL, PredicateVal, VarVal, StrTplVal, NameVal, HandlerNameVal, mk404Handler, keyIs, macCtrl, nullSafe, EVENT_CONVENIENCES, EventMemberVal, RenderVal, RenderNameVal, BindVal, BindMemberVal, DynVal, FieldVal, MethodVal, SeqAccessVal;
1749
1725
  var init_value = __esm({
1750
1726
  "src/value.js"() {
1751
1727
  init_collection();
@@ -1765,7 +1741,6 @@ var init_value = __esm({
1765
1741
  K_BIND = 8;
1766
1742
  K_DYN = 16;
1767
1743
  K_NAME = 32;
1768
- K_TYPE = 64;
1769
1744
  K_SEQ = 256;
1770
1745
  K_METHOD = 1024;
1771
1746
  K_EVENT = 2048;
@@ -1775,7 +1750,7 @@ var init_value = __esm({
1775
1750
  G_SEQUENCE = K_FIELD | K_DYN;
1776
1751
  G_PROVIDE = K_FIELD | K_SEQ;
1777
1752
  G_FIELD = K_FIELD | K_METHOD | K_CONST | K_SEQ;
1778
- G_VALUE = K_FIELD | K_METHOD | K_BIND | K_DYN | K_NAME | K_TYPE | K_CONST;
1753
+ G_VALUE = K_FIELD | K_METHOD | K_BIND | K_DYN | K_NAME | K_CONST;
1779
1754
  G_HANDLER_ARG = G_VALUE & ~K_NAME | K_EVENT;
1780
1755
  G_ALL = G_VALUE | K_STRTPL | K_SEQ;
1781
1756
  toNullIfNaN = (v) => Number.isNaN(v) ? null : v;
@@ -1899,9 +1874,6 @@ var init_value = __esm({
1899
1874
  super();
1900
1875
  this.name = name;
1901
1876
  }
1902
- eval(stack) {
1903
- return stack.lookupName(this.name);
1904
- }
1905
1877
  toString() {
1906
1878
  return this.name;
1907
1879
  }
@@ -1922,11 +1894,6 @@ var init_value = __esm({
1922
1894
  else console.warn("handler not found", { type: type3, name });
1923
1895
  return this;
1924
1896
  };
1925
- TypeVal = class extends NameVal {
1926
- eval(stack) {
1927
- return stack.lookupType(this.name);
1928
- }
1929
- };
1930
1897
  keyIs = (k) => (e) => e.key === k;
1931
1898
  macCtrl = (e) => isMac && e.metaKey || e.ctrlKey;
1932
1899
  nullSafe = (fn) => (e, stack) => {
@@ -2057,12 +2024,28 @@ var init_value = __esm({
2057
2024
  });
2058
2025
 
2059
2026
  // src/attribute.js
2027
+ function parseDirectiveValue(px, directiveName, source, parser) {
2028
+ const val = parser(source, px);
2029
+ if (val === null) {
2030
+ px.onParseIssue("bad-value", {
2031
+ role: "directive",
2032
+ directive: directiveName,
2033
+ value: source
2034
+ });
2035
+ }
2036
+ return val;
2037
+ }
2038
+ function parseIterationDirectives(attributes, px) {
2039
+ const parseNamed = (name) => {
2040
+ const attr = attributes.getNamedItem(`@${name}`);
2041
+ return attr ? parseDirectiveValue(px, name, attr.value, parseAlterHandler) : null;
2042
+ };
2043
+ return { whenVal: parseNamed("when"), loopWithVal: parseNamed("loop-with") };
2044
+ }
2060
2045
  function getAttrParser(px) {
2061
- _attrParser ??= new AttrParser(px);
2062
- _attrParser.clear(px);
2063
- return _attrParser;
2046
+ return new AttrParser(px);
2064
2047
  }
2065
- var Attributes, booleanAttrsRaw, booleanAttrs, AttrParser, ConstAttrs, DynAttrs, BaseAttr, Attr, ConstAttr, RawHtmlAttr, NOT_SET_VAL, IfAttr, _attrParser, EventHandler, IntentHandler;
2048
+ var Attributes, booleanAttrsRaw, booleanAttrs, AttrParser, ConstAttrs, DynAttrs, BaseAttr, Attr, ConstAttr, RawHtmlAttr, NOT_SET_VAL, IfAttr, EventHandler, IntentHandler;
2066
2049
  var init_attribute = __esm({
2067
2050
  "src/attribute.js"() {
2068
2051
  init_value();
@@ -2070,9 +2053,6 @@ var init_attribute = __esm({
2070
2053
  constructor(items) {
2071
2054
  this.items = items;
2072
2055
  }
2073
- eval(_stack) {
2074
- return {};
2075
- }
2076
2056
  static parse(attributes, px, parseAll = false) {
2077
2057
  return getAttrParser(px).parse(attributes, parseAll);
2078
2058
  }
@@ -2084,9 +2064,6 @@ var init_attribute = __esm({
2084
2064
  booleanAttrs = new Set(booleanAttrsRaw.split(","));
2085
2065
  AttrParser = class {
2086
2066
  constructor(px) {
2087
- this.clear(px);
2088
- }
2089
- clear(px) {
2090
2067
  this.px = px;
2091
2068
  this.attrs = null;
2092
2069
  this.hasDynamic = false;
@@ -2141,12 +2118,7 @@ var init_attribute = __esm({
2141
2118
  }
2142
2119
  }
2143
2120
  _parseDirectiveValue(directiveName, s, parserFn) {
2144
- const val = parserFn(s, this.px);
2145
- if (val === null) {
2146
- const info = { role: "directive", directive: directiveName, value: s };
2147
- this.px.onParseIssue("bad-value", info);
2148
- }
2149
- return val;
2121
+ return parseDirectiveValue(this.px, directiveName, s, parserFn);
2150
2122
  }
2151
2123
  parseDirective(s, directiveName) {
2152
2124
  switch (directiveName) {
@@ -2310,7 +2282,6 @@ var init_attribute = __esm({
2310
2282
  return this.condVal.eval(stack) ? this.thenVal.eval(stack) : this.elseVal.eval(stack);
2311
2283
  }
2312
2284
  };
2313
- _attrParser = null;
2314
2285
  EventHandler = class _EventHandler {
2315
2286
  constructor(handlerVal, args = []) {
2316
2287
  this.handlerVal = handlerVal;
@@ -2335,73 +2306,81 @@ var init_attribute = __esm({
2335
2306
  }
2336
2307
  });
2337
2308
 
2338
- // src/cache.js
2339
- var isWeakKey, NullDomCache, WeakMapDomCache;
2340
- var init_cache = __esm({
2341
- "src/cache.js"() {
2342
- isWeakKey = (k) => k !== null && (typeof k === "object" || typeof k === "function");
2343
- NullDomCache = class {
2344
- get(_keys, _cacheKey) {
2345
- }
2346
- set(_keys, _cacheKey, _v) {
2347
- }
2348
- evict() {
2349
- return { hit: 0, miss: 0, badKey: 0 };
2350
- }
2309
+ // src/iteration.js
2310
+ function walkLoopBindings({ seq, it, filter, loopWith, enricher, ctx }, visit) {
2311
+ const { iterData, start, end, keys } = unpackLoopResult(loopWith.call(it, seq, ctx), seq);
2312
+ const visitOne = (key, value, attrName) => {
2313
+ const binds = { key, value };
2314
+ if (enricher) callEnricher(enricher, it, binds, key, value, iterData);
2315
+ visit(key, value, attrName, binds);
2316
+ };
2317
+ if (keys) visitKeys(seq, keys, visitOne);
2318
+ else
2319
+ getSeqInfo(seq)(
2320
+ seq,
2321
+ (key, value, attrName) => {
2322
+ if (filter.call(it, key, value, iterData)) visitOne(key, value, attrName);
2323
+ },
2324
+ start,
2325
+ end
2326
+ );
2327
+ }
2328
+ var SEQ_INFO, normalizeRange, nativeIndexedIter, nativeKeyedIter, unknownIter, getSeqInfo, filterAlwaysTrue, nullLoopWith, unpackLoopResult, makeLoopCtx, callEnricher, visitKeys;
2329
+ var init_iteration = __esm({
2330
+ "src/iteration.js"() {
2331
+ init_collection();
2332
+ SEQ_INFO = /* @__PURE__ */ Symbol.for("tutuca.seqInfo");
2333
+ normalizeRange = (start, end, size) => {
2334
+ let s = start == null ? 0 : start < 0 ? size + start : start;
2335
+ let e = end == null ? size : end < 0 ? size + end : end;
2336
+ s = s < 0 ? 0 : s > size ? size : s;
2337
+ e = e < 0 ? 0 : e > size ? size : e;
2338
+ return [s, e < s ? s : e];
2351
2339
  };
2352
- WeakMapDomCache = class {
2353
- constructor() {
2354
- this.hit = this.miss = this.badKey = 0;
2355
- this.keysByLen = /* @__PURE__ */ new Map();
2356
- }
2357
- _returnValue(r) {
2358
- if (r === void 0) this.miss += 1;
2359
- else this.hit += 1;
2360
- return r;
2361
- }
2362
- get(keys, cacheKey) {
2363
- const len = keys.length;
2364
- let cur = this.keysByLen.get(len);
2365
- if (!cur) return this._returnValue(void 0);
2366
- for (let i = 0; i < len - 1; i++) {
2367
- cur = cur.get(keys[i]);
2368
- if (!cur) return this._returnValue(void 0);
2369
- }
2370
- return this._returnValue(cur.get(keys[len - 1])?.[cacheKey]);
2371
- }
2372
- set(keys, cacheKey, v) {
2373
- const len = keys.length;
2374
- let cur = this.keysByLen.get(len);
2375
- if (!cur) {
2376
- cur = /* @__PURE__ */ new WeakMap();
2377
- this.keysByLen.set(len, cur);
2378
- }
2379
- for (let i = 0; i < len - 1; i++) {
2380
- const key = keys[i];
2381
- let next = cur.get(key);
2382
- if (!next) {
2383
- if (!isWeakKey(key)) {
2384
- this.badKey += 1;
2385
- return;
2386
- }
2387
- next = /* @__PURE__ */ new WeakMap();
2388
- cur.set(key, next);
2389
- }
2390
- cur = next;
2391
- }
2392
- const lastKey = keys[len - 1];
2393
- const leaf = cur.get(lastKey);
2394
- if (leaf) leaf[cacheKey] = v;
2395
- else if (isWeakKey(lastKey)) cur.set(lastKey, { [cacheKey]: v });
2396
- else this.badKey += 1;
2397
- }
2398
- evict() {
2399
- const { hit, miss, badKey } = this;
2400
- this.hit = this.miss = this.badKey = 0;
2401
- this.keysByLen = /* @__PURE__ */ new Map();
2402
- return { hit, miss, badKey };
2340
+ nativeIndexedIter = (seq, visit, start, end) => {
2341
+ const [s, e] = normalizeRange(start, end, seqSize(seq));
2342
+ for (let i = s; i < e; i++) visit(i, seq[i], "si");
2343
+ };
2344
+ nativeKeyedIter = (seq, visit, start, end) => {
2345
+ const [s, e] = normalizeRange(start, end, seqSize(seq));
2346
+ let i = 0;
2347
+ for (const [key, value] of seqEntries(seq)) {
2348
+ if (i >= e) break;
2349
+ if (i >= s) visit(key, value, "sk");
2350
+ i++;
2403
2351
  }
2404
2352
  };
2353
+ unknownIter = () => {
2354
+ };
2355
+ getSeqInfo = (seq) => isIndexedSeq(seq) ? nativeIndexedIter : isKeyedSeq(seq) || isSetSeq(seq) ? nativeKeyedIter : seq?.[SEQ_INFO] ?? unknownIter;
2356
+ filterAlwaysTrue = (_key, _value, _iterData) => true;
2357
+ nullLoopWith = (seq) => ({ iterData: { seq } });
2358
+ unpackLoopResult = (result, seq) => {
2359
+ const value = result ?? {};
2360
+ return {
2361
+ iterData: value.iterData ?? { seq },
2362
+ start: value.start,
2363
+ end: value.end,
2364
+ keys: value.keys
2365
+ };
2366
+ };
2367
+ makeLoopCtx = (stack, filter) => ({
2368
+ lookup: (name) => stack.lookupBind(name),
2369
+ filter: (key, value, iterData) => filter.call(stack.it, key, value, iterData)
2370
+ });
2371
+ callEnricher = (enricher, it, binds, key, value, iterData) => {
2372
+ enricher.call(it, binds, key, value, iterData);
2373
+ console.assert(
2374
+ binds.key === key && binds.value === value,
2375
+ "@enrich-with handlers must not overwrite binds.key or binds.value"
2376
+ );
2377
+ binds.key = key;
2378
+ binds.value = value;
2379
+ };
2380
+ visitKeys = (seq, keys, visit) => {
2381
+ const attrName = isIndexedSeq(seq) ? "si" : "sk";
2382
+ for (const key of keys) visit(key, seqGet(seq, key), attrName);
2383
+ };
2405
2384
  }
2406
2385
  });
2407
2386
 
@@ -2753,197 +2732,11 @@ var init_vdom = __esm({
2753
2732
  }
2754
2733
  });
2755
2734
 
2756
- // src/renderer.js
2757
- var DATASET_ATTRS, Renderer, getSeqInfo, normalizeRange, callEnricher, filterAlwaysTrue, nullLoopWith, unpackLoopResult, keysIter, makeLoopCtx, nativeIndexedIter, nativeKeyedIter, unkIter, SEQ_INFO;
2758
- var init_renderer = __esm({
2759
- "src/renderer.js"() {
2760
- init_cache();
2761
- init_collection();
2762
- init_vdom();
2763
- DATASET_ATTRS = ["nid", "cid", "eid", "vid", "si", "sk"];
2764
- Renderer = class {
2765
- constructor(comps) {
2766
- this.comps = comps;
2767
- this.cache = new WeakMapDomCache();
2768
- this.renderTag = h;
2769
- }
2770
- renderFragment(childs) {
2771
- return new VFragment(childs);
2772
- }
2773
- renderComment(text) {
2774
- return new VComment(text);
2775
- }
2776
- setNullCache() {
2777
- this.cache = new NullDomCache();
2778
- }
2779
- renderToDOM(stack, val) {
2780
- const rootNode = document.createElement("div");
2781
- const rOpts = { document };
2782
- render(h("DIV", null, [this.renderRoot(stack, val)]), rootNode, rOpts);
2783
- return rootNode.childNodes[0];
2784
- }
2785
- renderToString(stack, val, cleanAttrs = true) {
2786
- const dom = this.renderToDOM(stack, val);
2787
- if (cleanAttrs) {
2788
- const nodes = dom.querySelectorAll("[data-nid],[data-cid],[data-eid]");
2789
- for (const { dataset } of nodes) for (const name of DATASET_ATTRS) delete dataset[name];
2790
- }
2791
- return dom.innerHTML;
2792
- }
2793
- renderRoot(stack, val, viewName = null) {
2794
- const comp = this.comps.getCompFor(val);
2795
- if (comp === null) return null;
2796
- return this._rValComp(stack, val, comp, comp.getView(viewName).anode, "ROOT", viewName);
2797
- }
2798
- renderIt(stack, node, key, viewName) {
2799
- const comp = this.comps.getCompFor(stack.it);
2800
- return comp ? this._rValComp(stack, stack.it, comp, node, key, viewName) : null;
2801
- }
2802
- // `node` is the parse node of the render site (`<x render>` / `render-it` /
2803
- // `render-each`, or the view's root anode for the app root). It keys the
2804
- // cache as a globally-unique object: node ids alone are unique only within a
2805
- // single view, so the same value rendered by two components (e.g. through a
2806
- // shared dynamic-var sequence) would otherwise collide in the cache.
2807
- _rValComp(stack, val, comp, node, key, viewName) {
2808
- const cacheKey = `${viewName ?? ""}${stack.viewsId ?? ""}${key}`;
2809
- const cachePath = [node, val];
2810
- stack._pushDynBindValuesToArray(cachePath, comp);
2811
- const cachedNode = this.cache.get(cachePath, cacheKey);
2812
- if (cachedNode) return cachedNode;
2813
- const view = viewName ? comp.getView(viewName) : stack.lookupBestView(comp.views, "main");
2814
- const body = this.renderView(view, stack);
2815
- if (body == null) return null;
2816
- const meta = this._renderMetadata({
2817
- $: "Comp",
2818
- nid: node?.nodeId ?? null,
2819
- cid: comp.id,
2820
- vid: view.name
2821
- });
2822
- const dom = new VFragment([meta, body]);
2823
- this.cache.set(cachePath, cacheKey, dom);
2824
- return dom;
2825
- }
2826
- pushEachEntry(r, nid, attrName, key, dom) {
2827
- r.push(this._renderMetadata({ $: "Each", nid, [attrName]: key }), dom);
2828
- }
2829
- renderEachWhen(stack, iterInfo, view, nid) {
2830
- const { seq, filter, loopWith, enricher } = iterInfo.eval(stack);
2831
- const r = [];
2832
- const it = stack.it;
2833
- const { iterData, start, end, keys } = unpackLoopResult(
2834
- loopWith.call(it, seq, makeLoopCtx(stack, filter)),
2835
- seq
2836
- );
2837
- const renderOne = (key, value, attrName) => {
2838
- const cachePath = enricher ? [view, it, value] : [view, value];
2839
- const binds = { key, value };
2840
- const cacheKey = `${stack.viewsId ?? ""}${nid}${key}`;
2841
- if (enricher) callEnricher(enricher, it, binds, key, value, iterData);
2842
- const cachedNode = this.cache.get(cachePath, cacheKey);
2843
- if (cachedNode) this.pushEachEntry(r, nid, attrName, key, cachedNode);
2844
- else {
2845
- const dom = this.renderView(view, stack.enter(value, binds, false));
2846
- if (dom != null) this.pushEachEntry(r, nid, attrName, key, dom);
2847
- this.cache.set(cachePath, cacheKey, dom);
2848
- }
2849
- };
2850
- if (keys) keysIter(seq, renderOne, keys);
2851
- else
2852
- getSeqInfo(seq)(
2853
- seq,
2854
- (key, value, attrName) => {
2855
- if (filter.call(it, key, value, iterData)) renderOne(key, value, attrName);
2856
- },
2857
- start,
2858
- end
2859
- );
2860
- return r;
2861
- }
2862
- renderView(view, stack) {
2863
- let n = stack.binds[1];
2864
- while (n !== null) {
2865
- const b = n[0];
2866
- if (b.isFrame) {
2867
- if (stack.it !== b.it) break;
2868
- console.error("recursion detected", stack.it, b.it);
2869
- return new VComment("RECURSION AVOIDED");
2870
- }
2871
- n = n[1];
2872
- }
2873
- return view.render(stack, this);
2874
- }
2875
- _renderMetadata(info) {
2876
- return new VComment(`§${JSON.stringify(info)}§`);
2877
- }
2878
- // Prefix a loop-less @enrich-with subtree with a boundary meta so event-path
2879
- // reconstruction replays its binds (mirrors the §Each§ / §Comp§ metas).
2880
- renderScopeMeta(nid, dom) {
2881
- return new VFragment([this._renderMetadata({ $: "Scope", nid }), dom]);
2882
- }
2883
- };
2884
- getSeqInfo = (seq) => isIndexedSeq(seq) ? nativeIndexedIter : isKeyedSeq(seq) || isSetSeq(seq) ? nativeKeyedIter : seq?.[SEQ_INFO] ?? unkIter;
2885
- normalizeRange = (start, end, size) => {
2886
- let s = start == null ? 0 : start < 0 ? size + start : start;
2887
- let e = end == null ? size : end < 0 ? size + end : end;
2888
- s = s < 0 ? 0 : s > size ? size : s;
2889
- e = e < 0 ? 0 : e > size ? size : e;
2890
- return [s, e < s ? s : e];
2891
- };
2892
- callEnricher = (enricher, it, binds, key, value, iterData) => {
2893
- enricher.call(it, binds, key, value, iterData);
2894
- console.assert(
2895
- binds.key === key && binds.value === value,
2896
- "@enrich-with handlers must not overwrite binds.key or binds.value"
2897
- );
2898
- binds.key = key;
2899
- binds.value = value;
2900
- };
2901
- filterAlwaysTrue = (_v, _k, _seq) => true;
2902
- nullLoopWith = (seq) => ({ iterData: { seq } });
2903
- unpackLoopResult = (result, seq) => {
2904
- const r = result ?? {};
2905
- return { iterData: r.iterData ?? { seq }, start: r.start, end: r.end, keys: r.keys };
2906
- };
2907
- keysIter = (seq, visit, keys) => {
2908
- const attrName = isIndexedSeq(seq) ? "si" : "sk";
2909
- for (const key of keys) visit(key, seqGet(seq, key), attrName);
2910
- };
2911
- makeLoopCtx = (stack, filter) => ({
2912
- lookup: (name) => stack.lookupBind(name),
2913
- filter: (key, value, iterData) => filter.call(stack.it, key, value, iterData)
2914
- });
2915
- nativeIndexedIter = (seq, visit, start, end) => {
2916
- const [s, e] = normalizeRange(start, end, seqSize(seq));
2917
- for (let i = s; i < e; i++) visit(i, seq[i], "si");
2918
- };
2919
- nativeKeyedIter = (seq, visit, start, end) => {
2920
- const [s, e] = normalizeRange(start, end, seqSize(seq));
2921
- let i = 0;
2922
- for (const [k, v] of seqEntries(seq)) {
2923
- if (i >= e) break;
2924
- if (i >= s) visit(k, v, "sk");
2925
- i++;
2926
- }
2927
- };
2928
- unkIter = () => {
2929
- };
2930
- SEQ_INFO = /* @__PURE__ */ Symbol.for("tutuca.seqInfo");
2931
- }
2932
- });
2933
-
2934
2735
  // src/anode.js
2935
2736
  function resolveDynProducer(comp, name) {
2936
- let producerComp, producerProvide;
2937
- const lk = comp?.lookup?.[name];
2938
- if (lk != null) {
2939
- producerComp = comp.scope?.lookupComponent(lk.compName);
2940
- producerProvide = producerComp?.provide?.[lk.provideName];
2941
- } else {
2942
- const p = comp?.provide?.[name];
2943
- if (p == null) return null;
2944
- producerComp = comp;
2945
- producerProvide = p;
2946
- }
2737
+ const own = comp?.provide?.[name];
2738
+ const producerComp = own != null ? comp : comp?.scope?.lookupProvider(name) ?? null;
2739
+ const producerProvide = own ?? producerComp?.provide?.[name];
2947
2740
  if (producerComp == null || producerProvide == null) return null;
2948
2741
  const pi = producerProvide.val?.toPathItem?.() ?? null;
2949
2742
  return { producerCompId: producerComp.id, producerSteps: pi ? [pi] : [] };
@@ -3063,16 +2856,10 @@ function parseRenderEach(px, value, as, attrs) {
3063
2856
  const seqVal = parseXOpVal("render-each", value, px, parseSequence);
3064
2857
  if (seqVal === null) return null;
3065
2858
  const renderIt = px.addNode(RenderItNode, as);
3066
- const attrParser = getAttrParser(px);
3067
- const eachAttr = attrParser.pushWrapper("each", value, seqVal);
3068
- attrParser.eachAttr = eachAttr;
3069
- const when = attrs.getNamedItem("@when");
3070
- if (when) attrParser._parseWhen(when.value);
3071
- const lWith = attrs.getNamedItem("@loop-with");
3072
- if (lWith) attrParser._parseLoopWith(lWith.value);
2859
+ const { whenVal, loopWithVal } = parseIterationDirectives(attrs, px);
3073
2860
  const each2 = px.addNodeIf(EachNode, seqVal);
3074
- each2.iterInfo.whenVal = eachAttr.whenVal ?? null;
3075
- each2.iterInfo.loopWithVal = eachAttr.loopWithVal ?? null;
2861
+ each2.iterInfo.whenVal = whenVal;
2862
+ each2.iterInfo.loopWithVal = loopWithVal;
3076
2863
  each2.fromRenderEach = true;
3077
2864
  each2.wrapNode(renderIt);
3078
2865
  return each2;
@@ -3124,8 +2911,8 @@ var init_anode = __esm({
3124
2911
  "src/anode.js"() {
3125
2912
  init_attribute();
3126
2913
  init_collection();
2914
+ init_iteration();
3127
2915
  init_path();
3128
- init_renderer();
3129
2916
  init_env();
3130
2917
  init_value();
3131
2918
  init_vdom();
@@ -3679,7 +3466,7 @@ var init_anode = __esm({
3679
3466
  });
3680
3467
 
3681
3468
  // src/components.js
3682
- var COMPONENT, Components, ComponentStack, ProvideInfo, LookupInfo, isString, _rawSpecKeys, KNOWN_SPEC_KEYS, _compId, Component;
3469
+ var COMPONENT, Components, ComponentStack, ProvideInfo, LookupInfo, isString, isTypeName, _rawSpecKeys, KNOWN_SPEC_KEYS, _compId, Component;
3683
3470
  var init_components = __esm({
3684
3471
  "src/components.js"() {
3685
3472
  init_anode();
@@ -3711,7 +3498,7 @@ var init_components = __esm({
3711
3498
  }
3712
3499
  compileStyles() {
3713
3500
  const styles2 = [];
3714
- for (const comp of this.byId.values()) styles2.push(comp.compileStyle());
3501
+ for (const Comp of this.byId.values()) styles2.push(Comp[COMPONENT].compileStyle());
3715
3502
  return styles2.join("\n");
3716
3503
  }
3717
3504
  };
@@ -3770,32 +3557,39 @@ var init_components = __esm({
3770
3557
  lookupComponent(name) {
3771
3558
  return this.byName[name] ?? this.parent?.lookupComponent(name) ?? null;
3772
3559
  }
3560
+ // The component in this scope chain that provides `name`, innermost first. A lookup
3561
+ // names a value without naming its producer, so the render-target teleport
3562
+ // (resolveDynProducer) recovers the producer here instead. Sound because
3563
+ // PROVIDE_NAME_COLLISION keeps a provide name to one producer per chain; with two,
3564
+ // this returns the innermost and the linter has already reported the ambiguity.
3565
+ lookupProvider(name) {
3566
+ for (const compName in this.byName) {
3567
+ const Comp = this.byName[compName];
3568
+ if (Comp.provide?.[name] !== void 0) return Comp;
3569
+ }
3570
+ return this.parent?.lookupProvider(name) ?? null;
3571
+ }
3773
3572
  lookupMacro(name) {
3774
3573
  return this.macros[name] ?? this.parent?.lookupMacro(name) ?? null;
3775
3574
  }
3776
3575
  };
3777
3576
  ProvideInfo = class {
3778
- constructor(name, val, symbol) {
3577
+ constructor(name, val) {
3779
3578
  this.name = name;
3780
3579
  this.val = val;
3781
- this.symbol = symbol;
3782
3580
  }
3783
3581
  };
3784
3582
  LookupInfo = class {
3785
- constructor(name, compName, provideName, val) {
3583
+ constructor(name, val) {
3786
3584
  this.name = name;
3787
- this.compName = compName;
3788
- this.provideName = provideName;
3789
3585
  this.val = val;
3790
- this._sym = void 0;
3791
- }
3792
- getProducerSymbol(stack) {
3793
- if (this._sym === void 0)
3794
- this._sym = stack.lookupType(this.compName)?.provide?.[this.provideName]?.symbol ?? null;
3795
- return this._sym;
3796
3586
  }
3797
3587
  };
3798
3588
  isString = (v) => typeof v === "string";
3589
+ isTypeName = (s) => {
3590
+ const c = s.charCodeAt(0);
3591
+ return c >= 65 && c <= 90;
3592
+ };
3799
3593
  _rawSpecKeys = "name view style commonStyle globalStyle receive intent alter views provide lookup fields methods statics";
3800
3594
  KNOWN_SPEC_KEYS = new Set(_rawSpecKeys.split(" "));
3801
3595
  _compId = 0;
@@ -3816,8 +3610,9 @@ var init_components = __esm({
3816
3610
  this.views[name] = new View(name, view, style);
3817
3611
  }
3818
3612
  this._rawProvide = o.provide ?? {};
3819
- this._rawLookup = o.lookup ?? {};
3613
+ this._rawLookup = o.lookup ?? [];
3820
3614
  this.provide = {};
3615
+ this.provideType = {};
3821
3616
  this.lookup = {};
3822
3617
  this.scope = null;
3823
3618
  this.spec = o;
@@ -3829,25 +3624,23 @@ var init_components = __esm({
3829
3624
  this.views[name].compile(new ParseContext2(), this.scope, this.id);
3830
3625
  const ctx = this.views.main.ctx;
3831
3626
  for (const key in this._rawProvide) {
3627
+ if (isTypeName(key)) {
3628
+ if (this._rawProvide[key] === "self") this.provideType[key] = this.Class;
3629
+ continue;
3630
+ }
3832
3631
  const val = parseProvide(this._rawProvide[key], ctx);
3833
- if (val) this.provide[key] = new ProvideInfo(key, val, Symbol(key));
3632
+ if (val) this.provide[key] = new ProvideInfo(key, val);
3834
3633
  }
3835
- for (const key in this._rawLookup) {
3836
- const linfo = this._rawLookup[key];
3837
- const forStr = isString(linfo) ? linfo : isString(linfo?.for) ? linfo.for : null;
3838
- const [compName, provideName] = forStr === null ? [] : forStr.split(".");
3839
- if (!isString(compName) || !isString(provideName)) continue;
3840
- const defStr = isString(linfo?.default) ? linfo.default : null;
3841
- const val = defStr === null ? null : parseField(defStr, ctx);
3842
- this.lookup[key] = new LookupInfo(key, compName, provideName, val);
3634
+ for (const entry of this._rawLookup) {
3635
+ const name = isString(entry) ? entry : isString(entry?.name) ? entry.name : null;
3636
+ if (name === null) continue;
3637
+ const defStr = isString(entry?.default) ? entry.default : null;
3638
+ this.lookup[name] = new LookupInfo(name, defStr === null ? null : parseField(defStr, ctx));
3843
3639
  }
3844
3640
  for (const key in this.lookup)
3845
3641
  if (this.provide[key] !== void 0)
3846
3642
  console.warn("name declared in both provide and lookup", this.name, key);
3847
3643
  }
3848
- make(args, opts) {
3849
- return this.Class.make(args, opts ?? { scope: this.scope });
3850
- }
3851
3644
  getView(name) {
3852
3645
  return this.views[name] ?? this.views.main;
3853
3646
  }
@@ -6206,7 +5999,11 @@ function checkComponent(Comp, lx = new LintContext(), { wellKnownExtras = EMPTY_
6206
5999
  checkFieldDeclarations(lx, Comp);
6207
6000
  checkFieldMethodNameCollisions(lx, Comp);
6208
6001
  checkProvidesAreAddressable(lx, Comp);
6002
+ checkProvidedTypes(lx, Comp);
6003
+ checkProvideNameCollisions(lx, Comp);
6209
6004
  checkLookupShapes(lx, Comp);
6005
+ checkLookupTypesResolve(lx, Comp);
6006
+ checkLookupsHaveProviders(lx, Comp);
6210
6007
  checkHandlersNotAsync(lx, Comp);
6211
6008
  checkHandlerNameCollisions(lx, Comp);
6212
6009
  checkScopedStyleTopLevel(lx, Comp);
@@ -6765,53 +6562,95 @@ function checkScopedStyleTopLevel(lx, Comp) {
6765
6562
  }
6766
6563
  function checkProvidesAreAddressable(lx, Comp) {
6767
6564
  for (const name in Comp._rawProvide) {
6565
+ if (isTypeName2(name)) continue;
6768
6566
  if (Comp.provide[name] === void 0) {
6769
6567
  lx.error(PROVIDE_NOT_ADDRESSABLE, { name, value: Comp._rawProvide[name] });
6770
6568
  }
6771
- }
6772
- }
6773
- function checkLookupShapes(lx, Comp) {
6774
- for (const name in Comp._rawLookup) {
6775
- const raw = Comp._rawLookup[name];
6776
- let target;
6777
- if (typeof raw === "string") {
6778
- target = raw;
6779
- } else if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
6569
+ }
6570
+ }
6571
+ function checkProvidedTypes(lx, Comp) {
6572
+ for (const name in Comp._rawProvide) {
6573
+ if (!isTypeName2(name)) continue;
6574
+ const raw = Comp._rawProvide[name];
6575
+ if (raw !== "self") lx.error(PROVIDE_TYPE_BAD_SHAPE, { name, value: raw });
6576
+ }
6577
+ }
6578
+ function checkProvideNameCollisions(lx, Comp) {
6579
+ const scope = Comp.scope;
6580
+ if (!scope) return;
6581
+ for (const name in Comp.provide) {
6582
+ for (let s = scope; s; s = s.parent) {
6583
+ for (const otherName in s.byName) {
6584
+ const Other = s.byName[otherName];
6585
+ if (Other !== Comp && Other.provide?.[name] !== void 0)
6586
+ lx.error(PROVIDE_NAME_COLLISION, { name, other: Other.name });
6587
+ }
6588
+ }
6589
+ }
6590
+ }
6591
+ function checkLookupShapes(lx, Comp) {
6592
+ const raw = Comp._rawLookup;
6593
+ if (!Array.isArray(raw)) {
6594
+ if (raw !== void 0 && Object.keys(raw).length > 0)
6595
+ lx.error(LOOKUP_BAD_SHAPE, { name: "lookup", problem: "must be a list of names" });
6596
+ return;
6597
+ }
6598
+ for (const entry of raw) {
6599
+ if (typeof entry === "string") continue;
6600
+ if (entry === null || typeof entry !== "object" || Array.isArray(entry)) {
6601
+ lx.error(LOOKUP_BAD_SHAPE, {
6602
+ name: String(entry),
6603
+ problem: 'must be a "name" string or a { name, default } object'
6604
+ });
6605
+ continue;
6606
+ }
6607
+ const extra = Object.keys(entry).filter((k) => !KNOWN_LOOKUP_KEYS.has(k));
6608
+ if (extra.length > 0) {
6780
6609
  lx.error(LOOKUP_BAD_SHAPE, {
6781
- name,
6782
- problem: 'must be a "Producer.provideName" string or a { for, default } object'
6610
+ name: String(entry.name),
6611
+ problem: `unknown key(s): ${extra.join(", ")}`
6783
6612
  });
6784
6613
  continue;
6785
- } else {
6786
- const extra = Object.keys(raw).filter((k) => !KNOWN_LOOKUP_KEYS.has(k));
6787
- if (extra.length > 0) {
6788
- lx.error(LOOKUP_BAD_SHAPE, { name, problem: `unknown key(s): ${extra.join(", ")}` });
6789
- continue;
6790
- }
6791
- if (typeof raw.for !== "string") {
6792
- lx.error(LOOKUP_BAD_SHAPE, { name, problem: "'for' is required and must be a string" });
6793
- continue;
6794
- }
6795
- if (raw.default !== void 0 && typeof raw.default !== "string") {
6796
- lx.error(LOOKUP_BAD_SHAPE, { name, problem: "'default' must be a string" });
6797
- continue;
6798
- }
6799
- target = raw.for;
6800
6614
  }
6801
- const parts = target.split(".");
6802
- if (parts.length !== 2 || !parts[0] || !parts[1]) {
6803
- lx.error(LOOKUP_TARGET_MALFORMED, { name, target });
6615
+ if (typeof entry.name !== "string" || entry.name === "") {
6616
+ lx.error(LOOKUP_BAD_SHAPE, {
6617
+ name: String(entry.name),
6618
+ problem: "'name' is required and must be a string"
6619
+ });
6620
+ continue;
6804
6621
  }
6622
+ if (entry.default !== void 0 && typeof entry.default !== "string")
6623
+ lx.error(LOOKUP_BAD_SHAPE, { name: entry.name, problem: "'default' must be a string" });
6624
+ }
6625
+ }
6626
+ function checkLookupsHaveProviders(lx, Comp) {
6627
+ const scope = Comp.scope;
6628
+ if (!scope) return;
6629
+ for (const name in Comp.lookup) {
6630
+ if (isTypeName2(name)) continue;
6631
+ if (scope.lookupProvider?.(name)) continue;
6632
+ const info = { name, hasDefault: Comp.lookup[name].val != null };
6633
+ if (info.hasDefault) lx.hint(LOOKUP_NO_PROVIDER, info);
6634
+ else lx.error(LOOKUP_NO_PROVIDER, info);
6635
+ }
6636
+ }
6637
+ function checkLookupTypesResolve(lx, Comp) {
6638
+ if (!Comp.scope) return;
6639
+ for (const name in Comp.lookup) {
6640
+ if (!isTypeName2(name)) continue;
6641
+ if (Comp.scope.lookupComponent(name) === null)
6642
+ reportUnknownName(lx, UNKNOWN_COMPONENT_NAME, name, scopeKeysAlong(Comp.scope, "byName"), {});
6805
6643
  }
6806
6644
  }
6807
6645
  function checkUnreferencedDynamics(lx, Comp, referencedDynamics) {
6808
6646
  for (const name in Comp.lookup) {
6647
+ if (isTypeName2(name)) continue;
6809
6648
  if (!referencedDynamics.has(name)) {
6810
6649
  lx.hint(DYN_ALIAS_NOT_REFERENCED, { name });
6811
6650
  }
6812
6651
  }
6813
6652
  }
6814
- var KNOWN_COMPONENT_SPEC_KEYS, EMPTY_SET, FRAMEWORK_WELL_KNOWN_EXTRAS, KNOWN_DIRECTIVE_NAMES, ALT_HANDLER_NOT_DEFINED, ALT_HANDLER_NOT_REFERENCED, DYN_VAL_NOT_DEFINED, DYN_ALIAS_NOT_REFERENCED, PROVIDE_NOT_ADDRESSABLE, LOOKUP_BAD_SHAPE, LOOKUP_TARGET_MALFORMED, RENDER_IT_OUTSIDE_OF_LOOP, UNKNOWN_EVENT_MODIFIER, RECEIVE_HANDLER_NOT_IMPLEMENTED, EVENT_HANDLER_METHOD_NOT_ALLOWED, HANDLER_NAME_COLLISION, FIELD_VAL_NOT_DEFINED, FIELD_VAL_IS_METHOD, METHOD_VAL_NOT_DEFINED, METHOD_VAL_IS_FIELD, DUPLICATE_ATTR_DEFINITION, IF_NO_BRANCH_SET, UNKNOWN_COMPONENT_NAME, UNKNOWN_MACRO_ARG, UNKNOWN_DIRECTIVE, UNKNOWN_X_OP, UNKNOWN_X_ATTR, X_OP_IGNORES_CHILDREN, MAYBE_DROP_AT_PREFIX, MAYBE_ADD_AT_PREFIX, BAD_VALUE, UNSUPPORTED_EXPR_SYNTAX, BINDING_MEMBER_TOO_DEEP, SUGGEST_BINDING_MEMBER, REDUNDANT_TEMPLATE_STRING, PLACEHOLDERLESS_TEMPLATE_STRING, CONSTANT_CONDITION, UNKNOWN_COMPONENT_SPEC_KEY, COMP_FIELD_BAD_SHAPE, ASYNC_HANDLER, TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE, GLOBAL_SELECTOR_IN_SCOPED_STYLE, FIELD_METHOD_NAME_COLLISION, X_KNOWN_OP_NAMES, X_KNOWN_ATTR_NAMES, HOST_DIRECTIVE_ONLY_NAMES, LEVEL_WARN2, LEVEL_ERROR2, LEVEL_HINT, PARSE_ISSUES, BINDING_MEMBER_TOO_DEEP_RE, UNSUPPORTED_EXPR_GUIDANCE, HTML_LINT_OPTS, NO_WRAPPERS2, ANY_EVENT_MODIFIERS, fixTo, BOOL_CONDITION_ORIGINS, isBoolConditionCtx, ATTR_VAL_CHECKERS, NODE_KIND_TO_CTX, HANDLER_CHANNELS, ASYNC_HANDLER_HELP, NON_NESTABLE_AT_RULE, GLOBAL_LEADING_SELECTOR, IGNORE_DIRECTIVE, blankRun, STYLE_TO_GLOBAL_HELP, KNOWN_LOOKUP_KEYS, LintContext, LintParseContext;
6653
+ var KNOWN_COMPONENT_SPEC_KEYS, EMPTY_SET, FRAMEWORK_WELL_KNOWN_EXTRAS, KNOWN_DIRECTIVE_NAMES, isTypeName2, ALT_HANDLER_NOT_DEFINED, ALT_HANDLER_NOT_REFERENCED, DYN_VAL_NOT_DEFINED, DYN_ALIAS_NOT_REFERENCED, PROVIDE_NOT_ADDRESSABLE, PROVIDE_TYPE_BAD_SHAPE, PROVIDE_NAME_COLLISION, LOOKUP_BAD_SHAPE, LOOKUP_NO_PROVIDER, RENDER_IT_OUTSIDE_OF_LOOP, UNKNOWN_EVENT_MODIFIER, RECEIVE_HANDLER_NOT_IMPLEMENTED, EVENT_HANDLER_METHOD_NOT_ALLOWED, HANDLER_NAME_COLLISION, FIELD_VAL_NOT_DEFINED, FIELD_VAL_IS_METHOD, METHOD_VAL_NOT_DEFINED, METHOD_VAL_IS_FIELD, DUPLICATE_ATTR_DEFINITION, IF_NO_BRANCH_SET, UNKNOWN_COMPONENT_NAME, UNKNOWN_MACRO_ARG, UNKNOWN_DIRECTIVE, UNKNOWN_X_OP, UNKNOWN_X_ATTR, X_OP_IGNORES_CHILDREN, MAYBE_DROP_AT_PREFIX, MAYBE_ADD_AT_PREFIX, BAD_VALUE, UNSUPPORTED_EXPR_SYNTAX, BINDING_MEMBER_TOO_DEEP, SUGGEST_BINDING_MEMBER, REDUNDANT_TEMPLATE_STRING, PLACEHOLDERLESS_TEMPLATE_STRING, CONSTANT_CONDITION, UNKNOWN_COMPONENT_SPEC_KEY, COMP_FIELD_BAD_SHAPE, ASYNC_HANDLER, TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE, GLOBAL_SELECTOR_IN_SCOPED_STYLE, FIELD_METHOD_NAME_COLLISION, X_KNOWN_OP_NAMES, X_KNOWN_ATTR_NAMES, HOST_DIRECTIVE_ONLY_NAMES, LEVEL_WARN2, LEVEL_ERROR2, LEVEL_HINT, PARSE_ISSUES, BINDING_MEMBER_TOO_DEEP_RE, UNSUPPORTED_EXPR_GUIDANCE, HTML_LINT_OPTS, NO_WRAPPERS2, ANY_EVENT_MODIFIERS, fixTo, BOOL_CONDITION_ORIGINS, isBoolConditionCtx, ATTR_VAL_CHECKERS, NODE_KIND_TO_CTX, HANDLER_CHANNELS, ASYNC_HANDLER_HELP, NON_NESTABLE_AT_RULE, GLOBAL_LEADING_SELECTOR, IGNORE_DIRECTIVE, blankRun, STYLE_TO_GLOBAL_HELP, KNOWN_LOOKUP_KEYS, LintContext, LintParseContext;
6815
6654
  var init_lint_check = __esm({
6816
6655
  "tools/core/lint-check.js"() {
6817
6656
  init_anode();
@@ -6839,13 +6678,19 @@ var init_lint_check = __esm({
6839
6678
  "then",
6840
6679
  "else"
6841
6680
  ]);
6681
+ isTypeName2 = (s) => {
6682
+ const c = s.charCodeAt(0);
6683
+ return c >= 65 && c <= 90;
6684
+ };
6842
6685
  ALT_HANDLER_NOT_DEFINED = "ALT_HANDLER_NOT_DEFINED";
6843
6686
  ALT_HANDLER_NOT_REFERENCED = "ALT_HANDLER_NOT_REFERENCED";
6844
6687
  DYN_VAL_NOT_DEFINED = "DYN_VAL_NOT_DEFINED";
6845
6688
  DYN_ALIAS_NOT_REFERENCED = "DYN_ALIAS_NOT_REFERENCED";
6846
6689
  PROVIDE_NOT_ADDRESSABLE = "PROVIDE_NOT_ADDRESSABLE";
6690
+ PROVIDE_TYPE_BAD_SHAPE = "PROVIDE_TYPE_BAD_SHAPE";
6691
+ PROVIDE_NAME_COLLISION = "PROVIDE_NAME_COLLISION";
6847
6692
  LOOKUP_BAD_SHAPE = "LOOKUP_BAD_SHAPE";
6848
- LOOKUP_TARGET_MALFORMED = "LOOKUP_TARGET_MALFORMED";
6693
+ LOOKUP_NO_PROVIDER = "LOOKUP_NO_PROVIDER";
6849
6694
  RENDER_IT_OUTSIDE_OF_LOOP = "RENDER_IT_OUTSIDE_OF_LOOP";
6850
6695
  UNKNOWN_EVENT_MODIFIER = "UNKNOWN_EVENT_MODIFIER";
6851
6696
  RECEIVE_HANDLER_NOT_IMPLEMENTED = "RECEIVE_HANDLER_NOT_IMPLEMENTED";
@@ -6962,16 +6807,6 @@ var init_lint_check = __esm({
6962
6807
  recurse(val.seqVal);
6963
6808
  recurse(val.keyVal);
6964
6809
  },
6965
- TypeVal({ lx, val, env, errCtx }) {
6966
- if (env.scope.lookupComponent(val.name) === null)
6967
- reportUnknownName(
6968
- lx,
6969
- UNKNOWN_COMPONENT_NAME,
6970
- val.name,
6971
- scopeKeysAlong(env.scope, "byName"),
6972
- errCtx
6973
- );
6974
- },
6975
6810
  // NameVals on a macro call-site attribute are macro-param bindings, not
6976
6811
  // handler args — their role is determined inside the macro body after
6977
6812
  // ^-substitution, where re-parsing handles validation. No checker: a NameVal
@@ -7030,7 +6865,7 @@ var init_lint_check = __esm({
7030
6865
  IGNORE_DIRECTIVE = /\/\*\s*tutuca-lint-ignore\s*\*\//g;
7031
6866
  blankRun = (m) => m.replace(/[^\n]/g, " ");
7032
6867
  STYLE_TO_GLOBAL_HELP = "Move it to the component's 'globalStyle' key, which is injected without the component-scoping wrapper. To suppress a false positive, put a /* tutuca-lint-ignore */ comment on the same line.";
7033
- KNOWN_LOOKUP_KEYS = /* @__PURE__ */ new Set(["for", "default"]);
6868
+ KNOWN_LOOKUP_KEYS = /* @__PURE__ */ new Set(["name", "default"]);
7034
6869
  LintContext = class {
7035
6870
  constructor() {
7036
6871
  this.reports = [];
@@ -7175,13 +7010,25 @@ var init_lint_rules = __esm({
7175
7010
  code: LOOKUP_BAD_SHAPE,
7176
7011
  level: "error",
7177
7012
  group: "Dynamic bindings",
7178
- summary: "`lookup` entry must be a string or `{ for, default }` (known keys, string values)."
7013
+ summary: "`lookup` entry must be a name string or `{ name, default }`."
7014
+ },
7015
+ {
7016
+ code: LOOKUP_NO_PROVIDER,
7017
+ level: "error",
7018
+ group: "Dynamic bindings",
7019
+ summary: "`lookup` name is provided by no component in scope."
7020
+ },
7021
+ {
7022
+ code: PROVIDE_TYPE_BAD_SHAPE,
7023
+ level: "error",
7024
+ group: "Dynamic bindings",
7025
+ summary: 'A PascalCase `provide` publishes a component type; its value must be `"self"`.'
7179
7026
  },
7180
7027
  {
7181
- code: LOOKUP_TARGET_MALFORMED,
7028
+ code: PROVIDE_NAME_COLLISION,
7182
7029
  level: "error",
7183
7030
  group: "Dynamic bindings",
7184
- summary: '`lookup` target must be `"Producer.provideName"` (string or `for`).'
7031
+ summary: "Two components in one scope chain `provide` the same name."
7185
7032
  },
7186
7033
  // Templates / events
7187
7034
  {
@@ -7474,8 +7321,12 @@ function lintIdToMessage(id, info) {
7474
7321
  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`;
7475
7322
  case "LOOKUP_BAD_SHAPE":
7476
7323
  return `Lookup '${info.name}' has an invalid shape: ${info.problem}`;
7477
- case "LOOKUP_TARGET_MALFORMED":
7478
- return `Lookup '${info.name}' target '${info.target}' must be 'Producer.provideName' (a string, or the 'for' of { for, default })`;
7324
+ case "LOOKUP_NO_PROVIDER":
7325
+ 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`;
7326
+ case "PROVIDE_TYPE_BAD_SHAPE":
7327
+ return `Provide '${info.name}' starts uppercase, so it publishes a component type — its value must be 'self', not '${info.value}'`;
7328
+ case "PROVIDE_NAME_COLLISION":
7329
+ return `Provide '${info.name}' is also provided by '${info.other}' in the same scope — one name, one provider, so a lookup can find it`;
7479
7330
  case "UNKNOWN_MACRO_ARG":
7480
7331
  return `Argument '${info.name}' is not declared in macro '${info.macroName}'`;
7481
7332
  case "UNKNOWN_DIRECTIVE":
@@ -12951,6 +12802,21 @@ var init_list = __esm({
12951
12802
  });
12952
12803
 
12953
12804
  // src/stack.js
12805
+ function routeLookup(route, lex, dyn) {
12806
+ for (let i = 0; i < route.length; i++) {
12807
+ const leg = route[i];
12808
+ if (leg === "dyn") {
12809
+ const v = dyn();
12810
+ if (v != null) return v;
12811
+ } else if (leg === "lex") {
12812
+ const v = lex();
12813
+ if (v != null) return v;
12814
+ } else {
12815
+ console.warn("unknown lookup route leg", leg, '- expected "dyn" or "lex"');
12816
+ }
12817
+ }
12818
+ return null;
12819
+ }
12954
12820
  function lookup(chain, name, dv = null) {
12955
12821
  let n = chain;
12956
12822
  while (n !== null) {
@@ -12970,11 +12836,12 @@ function computeViewsId(views) {
12970
12836
  }
12971
12837
  return s === "main" ? "" : s;
12972
12838
  }
12973
- var STOP, NEXT, BindFrame, ObjectFrame, Stack;
12839
+ var STOP, NEXT, DEFAULT_LOOKUP_ROUTE, BindFrame, ObjectFrame, Stack;
12974
12840
  var init_stack = __esm({
12975
12841
  "src/stack.js"() {
12976
12842
  STOP = /* @__PURE__ */ Symbol("STOP");
12977
12843
  NEXT = /* @__PURE__ */ Symbol("NEXT");
12844
+ DEFAULT_LOOKUP_ROUTE = ["dyn", "lex"];
12978
12845
  BindFrame = class {
12979
12846
  constructor(it, binds, isFrame) {
12980
12847
  this.it = it;
@@ -13006,14 +12873,21 @@ var init_stack = __esm({
13006
12873
  this.ctx = ctx;
13007
12874
  }
13008
12875
  // Evaluate every provide the entered component publishes and push them as one
13009
- // dynBinds frame (keyed by each provide's symbol). No-op when there are no provides.
12876
+ // dynBinds frame, keyed by NAME. Published types go in the same frame: a type name
12877
+ // starts A-Z and a value name does not, so the two namespaces cannot collide and
12878
+ // nearest-ancestor-wins falls out of frame order for both. No-op with no provides.
13010
12879
  _pushProvides() {
13011
- const provide = this.comps.getCompFor(this.it)?.provide;
13012
- if (provide == null) return this;
12880
+ const comp = this.comps.getCompFor(this.it);
12881
+ if (comp == null) return this;
12882
+ const { provide, provideType } = comp;
13013
12883
  const dynObj = {};
13014
12884
  let has2 = false;
13015
12885
  for (const k in provide) {
13016
- dynObj[provide[k].symbol] = provide[k].val.eval(this);
12886
+ dynObj[k] = provide[k].val.eval(this);
12887
+ has2 = true;
12888
+ }
12889
+ for (const k in provideType) {
12890
+ dynObj[k] = provideType[k];
13017
12891
  has2 = true;
13018
12892
  }
13019
12893
  if (!has2) return this;
@@ -13038,30 +12912,36 @@ var init_stack = __esm({
13038
12912
  const newViews = [name, views];
13039
12913
  return new _Stack(comps, it, binds, dynBinds, newViews, computeViewsId(newViews), ctx);
13040
12914
  }
12915
+ // Published types are stable per scope and would only churn the render cache, so
12916
+ // the cache key covers values alone.
13041
12917
  _pushDynBindValuesToArray(arr, comp) {
13042
- for (const k in comp.provide) arr.push(this._lookupProvide(comp.provide[k]));
13043
- for (const k in comp.lookup) arr.push(this._lookupAlias(comp.lookup[k]));
13044
- }
13045
- _lookupProvide(p) {
13046
- return lookup(this.dynBinds, p.symbol) ?? p.val.eval(this) ?? null;
13047
- }
13048
- _lookupAlias(lk) {
13049
- const sym = lk.getProducerSymbol(this);
13050
- return (sym != null ? lookup(this.dynBinds, sym) : null) ?? lk.val?.eval(this) ?? null;
12918
+ for (const k in comp.provide) arr.push(this.lookupDynamic(k));
12919
+ for (const k in comp.lookup) arr.push(this.lookupDynamic(k));
13051
12920
  }
12921
+ // `*name`: the nearest binding above (including this component's own provides,
12922
+ // pushed on entering it), else this component's declared default, else null.
13052
12923
  lookupDynamic(name) {
12924
+ const v = lookup(this.dynBinds, name);
12925
+ if (v != null) return v;
13053
12926
  const comp = this.comps.getCompFor(this.it);
13054
- if (comp == null) return null;
13055
- const lk = comp.lookup[name];
13056
- if (lk !== void 0) return this._lookupAlias(lk);
13057
- const p = comp.provide[name];
13058
- return p !== void 0 ? this._lookupProvide(p) : null;
12927
+ return comp?.lookup[name]?.val?.eval(this) ?? null;
13059
12928
  }
13060
12929
  lookupBind(name) {
13061
12930
  return lookup(this.binds, name);
13062
12931
  }
13063
- lookupType(name) {
13064
- return this.comps.getCompFor(this.it).scope.lookupComponent(name);
12932
+ // The `lex` leg: what a name means in the registration scope of the component being
12933
+ // rendered. The scope chain holds components, so this leg only ever answers for a
12934
+ // type name — for a value name it is a miss, which is why one default route serves
12935
+ // both. Guarded: a non-component `it` has no scope to ask.
12936
+ _lookupLex(name) {
12937
+ return this.comps.getCompFor(this.it)?.scope.lookupComponent(name) ?? null;
12938
+ }
12939
+ lookupRouted(name, route = DEFAULT_LOOKUP_ROUTE) {
12940
+ return routeLookup(
12941
+ route,
12942
+ () => this._lookupLex(name),
12943
+ () => this.lookupDynamic(name)
12944
+ );
13065
12945
  }
13066
12946
  lookupFieldRaw(name) {
13067
12947
  return this.it[name] ?? null;
@@ -13070,12 +12950,6 @@ var init_stack = __esm({
13070
12950
  const fn = this.it[name];
13071
12951
  return fn instanceof Function ? fn.call(this.it) : null;
13072
12952
  }
13073
- // Bare implicit event names are gone: a sigil-less word cannot reach a
13074
- // handler-arg slot anymore, so this only ever serves stale NameVals parsed
13075
- // before the removal (e.g. macro-attr pass-throughs). Always null.
13076
- lookupName(_name) {
13077
- return null;
13078
- }
13079
12953
  // The dispatched DOM event / drag info, read only by EventMemberVal's
13080
12954
  // `e.<member>` handler args. Null outside a live event transaction.
13081
12955
  lookupEvent() {
@@ -13136,7 +13010,7 @@ function classFromData(name, { fields = {}, methods, statics }) {
13136
13010
  b.addField(field, dval, FieldCls);
13137
13011
  } else if (value?.component && value?.args !== void 0)
13138
13012
  b.addCompField(field, value.component, value.args);
13139
- else if (isPlainObject4(value)) b.addField(field, { ...value }, FieldObject);
13013
+ else if (isPlainObject(value)) b.addField(field, { ...value }, FieldObject);
13140
13014
  else {
13141
13015
  const FieldCls = value?.[FIELD_CLASS] ?? FieldAny;
13142
13016
  b.addField(field, value, FieldCls);
@@ -13160,18 +13034,21 @@ function validateDraftFields(current2, draft) {
13160
13034
  }
13161
13035
  }
13162
13036
  }
13163
- var BAD_VALUE2, nullCoercer, isPlainObject4, Field, Check, CheckTypeAny, CHECK_TYPE_ANY, FnCheck, check, CHECK_TYPE_INT, CHECK_TYPE_FLOAT, CHECK_TYPE_BOOL, CHECK_TYPE_STRING, CHECK_TYPE_LIST, CHECK_TYPE_OBJECT, CHECK_TYPE_MAP, CHECK_TYPE_SET, FieldBool, FieldAny, FieldString, FieldInt, FieldFloat, getTypeName, CheckTypeName, FieldComp, FieldList, FieldObject, FieldMap, FieldSet, ClassBuilder, FIELD_CLASS, fieldsByTypeName, META_KEYS;
13037
+ function assertNoReservedComponentStatics(statics = {}) {
13038
+ for (const name in statics) {
13039
+ if (RESERVED_COMPONENT_STATICS.has(name)) {
13040
+ throw new TypeError(`component static "${name}" is reserved by the framework`);
13041
+ }
13042
+ }
13043
+ }
13044
+ var BAD_VALUE2, nullCoercer, Field, Check, CheckTypeAny, CHECK_TYPE_ANY, FnCheck, check, CHECK_TYPE_INT, CHECK_TYPE_FLOAT, CHECK_TYPE_BOOL, CHECK_TYPE_STRING, CHECK_TYPE_LIST, CHECK_TYPE_OBJECT, CHECK_TYPE_MAP, CHECK_TYPE_SET, FieldBool, FieldAny, FieldString, FieldInt, FieldFloat, getTypeName, CheckTypeName, FieldComp, FieldList, FieldObject, FieldMap, FieldSet, ClassBuilder, FIELD_CLASS, fieldsByTypeName, META_KEYS, RESERVED_COMPONENT_STATICS;
13164
13045
  var init_oo = __esm({
13165
13046
  "src/oo.js"() {
13047
+ init_collection();
13166
13048
  init_components();
13167
13049
  init_immer2();
13168
13050
  BAD_VALUE2 = /* @__PURE__ */ Symbol("BadValue");
13169
13051
  nullCoercer = (v) => v;
13170
- isPlainObject4 = (v) => {
13171
- if (v === null || typeof v !== "object") return false;
13172
- const proto = Object.getPrototypeOf(v);
13173
- return proto === Object.prototype || proto === null;
13174
- };
13175
13052
  Field = class {
13176
13053
  constructor(type3, name, typeCheck, coercer, defaultValue = null) {
13177
13054
  this.type = type3;
@@ -13235,7 +13112,7 @@ var init_oo = __esm({
13235
13112
  CHECK_TYPE_BOOL = check((v) => typeof v === "boolean", "Boolean expected");
13236
13113
  CHECK_TYPE_STRING = check((v) => typeof v === "string", "String expected");
13237
13114
  CHECK_TYPE_LIST = check(Array.isArray, "Array expected");
13238
- CHECK_TYPE_OBJECT = check(isPlainObject4, "Plain object expected");
13115
+ CHECK_TYPE_OBJECT = check(isPlainObject, "Plain object expected");
13239
13116
  CHECK_TYPE_MAP = check((v) => v instanceof Map, "Map expected");
13240
13117
  CHECK_TYPE_SET = check((v) => v instanceof Set, "Set expected");
13241
13118
  FieldBool = class extends Field {
@@ -13304,7 +13181,7 @@ var init_oo = __esm({
13304
13181
  "object",
13305
13182
  name,
13306
13183
  CHECK_TYPE_OBJECT,
13307
- (v) => isPlainObject4(v) ? { ...v } : null,
13184
+ (v) => isPlainObject(v) ? { ...v } : null,
13308
13185
  defaultValue
13309
13186
  );
13310
13187
  }
@@ -13317,7 +13194,7 @@ var init_oo = __esm({
13317
13194
  CHECK_TYPE_MAP,
13318
13195
  (v) => {
13319
13196
  if (v instanceof Map) return new Map(v);
13320
- if (Array.isArray(v) || isPlainObject4(v))
13197
+ if (Array.isArray(v) || isPlainObject(v))
13321
13198
  return new Map(Array.isArray(v) ? v : Object.entries(v));
13322
13199
  return null;
13323
13200
  },
@@ -13412,10 +13289,17 @@ var init_oo = __esm({
13412
13289
  set: FieldSet,
13413
13290
  any: FieldAny
13414
13291
  };
13415
- META_KEYS = "name id fields methods views receive intent alter provide lookup spec extra commonStyle globalStyle scope _rawProvide _rawLookup".split(
13292
+ META_KEYS = "name id fields methods views receive intent alter provide provideType lookup spec extra commonStyle globalStyle scope _rawProvide _rawLookup".split(
13416
13293
  " "
13417
13294
  );
13295
+ RESERVED_COMPONENT_STATICS = /* @__PURE__ */ new Set([
13296
+ ...META_KEYS,
13297
+ "make",
13298
+ "getMetaClass",
13299
+ ...Object.getOwnPropertyNames(Component.prototype)
13300
+ ]);
13418
13301
  Component.fromSpec = (opts) => {
13302
+ assertNoReservedComponentStatics(opts.statics);
13419
13303
  const Class = classFromData(opts.name, opts);
13420
13304
  const comp = new Component(Class, opts);
13421
13305
  const metaClass = Class.getMetaClass();
@@ -13435,7 +13319,7 @@ var init_oo = __esm({
13435
13319
  configurable: true
13436
13320
  });
13437
13321
  for (const key of Object.getOwnPropertyNames(Component.prototype))
13438
- if (key !== "constructor" && key !== "make" && !Object.hasOwn(Class, key))
13322
+ if (key !== "constructor" && !Object.hasOwn(Class, key))
13439
13323
  Class[key] = (...args) => comp[key](...args);
13440
13324
  return Class;
13441
13325
  };
@@ -13452,9 +13336,10 @@ function warnNotIntent(verb) {
13452
13336
  function rootDispatcher(transactor) {
13453
13337
  return new Dispatcher(new Path([]), transactor, null);
13454
13338
  }
13455
- var State2, Transactor, Transaction, InputEvent, NameArgsTransaction, SendEvent, IntentEvent, PASS, REFUSAL_RING_CAP, DEFAULT_ROUTE, INTENT_DEPTH, IntentWalk, Completion, Dispatcher, EventContext, IntentContext, PathChanges;
13339
+ var State2, Transactor, Transaction, InputEvent, NameArgsTransaction, SendEvent, IntentEvent, PASS, REFUSAL_RING_CAP, DEFAULT_ROUTE, INTENT_DEPTH, IntentWalk, Completion, Dispatcher, EventContext, PathChanges;
13456
13340
  var init_transactor = __esm({
13457
13341
  "src/transactor.js"() {
13342
+ init_components();
13458
13343
  init_immer2();
13459
13344
  init_oo();
13460
13345
  init_path();
@@ -13472,9 +13357,6 @@ var init_transactor = __esm({
13472
13357
  this.val = val;
13473
13358
  for (const sub of this.changeSubs) sub({ val, old, info, timestamp: Date.now() });
13474
13359
  }
13475
- update(fn, info) {
13476
- return this.set(fn(this.val), info);
13477
- }
13478
13360
  };
13479
13361
  Transactor = class {
13480
13362
  constructor(comps, rootValue) {
@@ -13535,7 +13417,7 @@ var init_transactor = __esm({
13535
13417
  // Build and dispatch the observer record for a settled transaction. The
13536
13418
  // resolved handler (`_resolvedHandler`/`_matched`) and per-leaf before/after
13537
13419
  // (`_before`/`_after`) were captured while the handler ran (see callHandler /
13538
- // updateRootValue). No-op when nobody is observing.
13420
+ // Transaction.run). No-op when nobody is observing.
13539
13421
  _emitTransaction(transaction, root) {
13540
13422
  if (this._observers.length === 0) return;
13541
13423
  if (transaction._resolvedHandler === void 0) return;
@@ -13567,8 +13449,13 @@ var init_transactor = __esm({
13567
13449
  }
13568
13450
  return child;
13569
13451
  }
13570
- pushSend(path, name, args = [], opts = {}, parent = null) {
13571
- const t = new SendEvent(path, this, name, args, parent, opts);
13452
+ // `origin` is where the message came FROM, pinned now for the same reason an
13453
+ // intent's answerPath is: a reply must reach the sender that asked even if a key
13454
+ // moved while the message was in flight. Null when nobody is waiting — a host
13455
+ // sendAtRoot or a view's own `@on.*` — and ctx.sendReply refuses on that.
13456
+ pushSend(path, name, args = [], parent = null, origin = null) {
13457
+ const t = new SendEvent(path, this, name, args, parent);
13458
+ t.origin = origin === null ? null : origin.toTransactionPath().pinKeys(this.state.val);
13572
13459
  this.pushTransaction(t);
13573
13460
  return this._link(t, parent);
13574
13461
  }
@@ -13581,9 +13468,9 @@ var init_transactor = __esm({
13581
13468
  walk.advance();
13582
13469
  return walk;
13583
13470
  }
13584
- // Drain queued transactions and await in-flight requests until quiescent. Each
13585
- // awaited request enqueues a ResponseEvent, which may dispatch more work, so we
13586
- // loop. `maxTurns` backstops a pathological non-terminating cascade.
13471
+ // Drain queued transactions and await async intent handlers until quiescent. A
13472
+ // completed handler may enqueue an answer, which may dispatch more work, so we loop.
13473
+ // `maxTurns` backstops a pathological non-terminating cascade.
13587
13474
  async settle(maxTurns = 1e4) {
13588
13475
  while ((this.hasPendingTransactions || this._inflight.size) && maxTurns-- > 0) {
13589
13476
  while (this.hasPendingTransactions) this.transactNext();
@@ -13637,9 +13524,6 @@ var init_transactor = __esm({
13637
13524
  whenSubtreeSettled() {
13638
13525
  return this.completion.whenSubtreeSettled();
13639
13526
  }
13640
- run(rootValue, comps) {
13641
- return this.updateRootValue(rootValue, comps);
13642
- }
13643
13527
  afterTransaction() {
13644
13528
  }
13645
13529
  // Ending a walk and forwarding belong to the two dispatch buckets; the base warns
@@ -13651,12 +13535,6 @@ var init_transactor = __esm({
13651
13535
  forward(_opts) {
13652
13536
  console.warn('ctx.forward() needs a "receive" or "intent" handler - ignored');
13653
13537
  }
13654
- buildRootStack(root, comps) {
13655
- return Stack.root(comps, root);
13656
- }
13657
- buildStack(root, comps) {
13658
- return this.path.toTransactionPath().buildStack(this.buildRootStack(root, comps));
13659
- }
13660
13538
  // The kind reported to observers (see Transactor.observe); null on the base.
13661
13539
  get observeKind() {
13662
13540
  return null;
@@ -13676,12 +13554,11 @@ var init_transactor = __esm({
13676
13554
  return null;
13677
13555
  }
13678
13556
  // The path used to apply the mutation. Teleports dynamic-var renders so it lands on
13679
- // the data's real location (the dispatch `this.path` keeps intermediates). A subclass
13680
- // may override to supply a pre-resolved path (see ResponseEvent's pinned keys).
13557
+ // the data's real location (the dispatch `this.path` keeps intermediates).
13681
13558
  getTransactionPath() {
13682
13559
  return this.path.toTransactionPath().compact();
13683
13560
  }
13684
- updateRootValue(curRoot, comps) {
13561
+ run(curRoot, comps) {
13685
13562
  const txnPath = this.getTransactionPath();
13686
13563
  const curLeaf = txnPath.lookup(curRoot);
13687
13564
  const newLeaf = produce(curLeaf, (draft) => {
@@ -13738,8 +13615,8 @@ var init_transactor = __esm({
13738
13615
  }
13739
13616
  this.transactor.pushIntent(this.dispatchPath, name, args, rest, this);
13740
13617
  }
13741
- buildRootStack(root, comps) {
13742
- return Stack.root(comps, root, this);
13618
+ buildStack(root, comps) {
13619
+ return this.path.toTransactionPath().buildStack(Stack.root(comps, root, this));
13743
13620
  }
13744
13621
  getHandlerAndArgs(root, _instance, comps) {
13745
13622
  const stack = this.buildStack(root, comps);
@@ -13757,11 +13634,10 @@ var init_transactor = __esm({
13757
13634
  }
13758
13635
  };
13759
13636
  NameArgsTransaction = class extends Transaction {
13760
- constructor(path, transactor, name, args, parentTransaction, opts = {}) {
13637
+ constructor(path, transactor, name, args, parentTransaction) {
13761
13638
  super(path, transactor, parentTransaction);
13762
13639
  this.name = name;
13763
13640
  this.args = args;
13764
- this.opts = opts;
13765
13641
  this.targetPath = path;
13766
13642
  }
13767
13643
  handlerProp = null;
@@ -13820,7 +13696,7 @@ var init_transactor = __esm({
13820
13696
  IntentEvent = class extends NameArgsTransaction {
13821
13697
  handlerProp = "intent";
13822
13698
  constructor(path, transactor, walk) {
13823
- super(path, transactor, walk.name, walk.args, walk.parent, {});
13699
+ super(path, transactor, walk.name, walk.args, walk.parent);
13824
13700
  this.walk = walk;
13825
13701
  this.targetPath = walk.origin;
13826
13702
  }
@@ -13920,7 +13796,7 @@ var init_transactor = __esm({
13920
13796
  async _runLex(chain, i) {
13921
13797
  if (this.ended) return;
13922
13798
  if (i >= chain.length) return this.advance();
13923
- const ctx = new IntentContext(this.origin, this.transactor, this.parent);
13799
+ const ctx = new Dispatcher(this.origin, this.transactor, this.parent);
13924
13800
  try {
13925
13801
  const res = await chain[i].fn.apply(null, [...this.args, ctx]);
13926
13802
  if (res === PASS) return this._runLex(chain, i + 1);
@@ -13973,7 +13849,7 @@ var init_transactor = __esm({
13973
13849
  this.ended = true;
13974
13850
  if (name === null) return this.release?.();
13975
13851
  const path = this.answerPath ?? this.origin;
13976
- const t = new SendEvent(path, this.transactor, name, args, this.parent, {});
13852
+ const t = new SendEvent(path, this.transactor, name, args, this.parent);
13977
13853
  t._isAnswer = true;
13978
13854
  this.transactor.pushTransaction(t);
13979
13855
  if (this.release) t.completion.whenSubtreeSettled().then(this.release);
@@ -14012,7 +13888,7 @@ var init_transactor = __esm({
14012
13888
  this.val = val;
14013
13889
  this._selfResolve?.(val);
14014
13890
  }
14015
- // Settle self even when no handler produced a value (skipSelf / undefined / throw paths).
13891
+ // Settle self even when no handler produced a value (undefined-state / throw paths).
14016
13892
  ensureSelfSettled() {
14017
13893
  if (!this.selfSettled) this.markSelfSettled(this.val);
14018
13894
  }
@@ -14058,12 +13934,64 @@ var init_transactor = __esm({
14058
13934
  get at() {
14059
13935
  return new PathChanges(this);
14060
13936
  }
13937
+ // The render-time Stack, rebuilt on demand. A handler does not get one: the stack
13938
+ // that evaluated its arguments is a local in getHandlerAndArgs and is gone by the
13939
+ // time the body runs, and send/intent transactions never build one at all. Both
13940
+ // halves it needs are pinned on this ctx, so the `dyn` leg reconstructs it — and
13941
+ // only the `dyn` leg does, which is why this is lazy rather than eager.
13942
+ //
13943
+ // The path is compacted, so per-item binds (`@each`, `@enrich-with`) are not
13944
+ // replayed; provides are pushed on every component frame either way, so a provide
13945
+ // that reads a loop binding is the one case this cannot reproduce faithfully.
13946
+ _stack() {
13947
+ this._stackMemo ??= this.path.toTransactionPath().buildStack(Stack.root(this.transactor.comps, this.root, this.parent));
13948
+ return this._stackMemo;
13949
+ }
13950
+ // Resolve a name the way the renderer would. `opts.route` takes the same legs in
13951
+ // the same spelling as `ctx.intent` — `["dyn"]` the render ancestry, `["lex"]` the
13952
+ // registration scope, default both.
13953
+ lookup(name, opts) {
13954
+ const route = opts?.route ?? DEFAULT_LOOKUP_ROUTE;
13955
+ return routeLookup(
13956
+ route,
13957
+ () => this._lookupLex(name),
13958
+ () => this._stack()?.lookupDynamic(name) ?? null
13959
+ );
13960
+ }
13961
+ // The `lex` leg without a Stack: the scope of the component whose handler is
13962
+ // running, which is the leaf of this ctx's path.
13963
+ _lookupLex(name) {
13964
+ let Comp = null;
13965
+ this.walkPath((c) => {
13966
+ Comp = c;
13967
+ return false;
13968
+ });
13969
+ return Comp?.scope?.lookupComponent(name) ?? null;
13970
+ }
13971
+ // A component lookup is a value lookup constrained to a component. The `lex` leg
13972
+ // can only ever answer with one; the `dyn` leg reads a binding an ancestor
13973
+ // published, so it is the leg that has to be checked.
13974
+ lookupType(name, opts) {
13975
+ const v = this.lookup(name, opts);
13976
+ if (v == null) {
13977
+ this.transactor.refuse("TYPE_NOT_FOUND", {
13978
+ name,
13979
+ route: opts?.route ?? DEFAULT_LOOKUP_ROUTE
13980
+ });
13981
+ return null;
13982
+ }
13983
+ if (v?.[COMPONENT] == null) {
13984
+ this.transactor.refuse("TYPE_NOT_COMPONENT", { name, got: typeof v });
13985
+ return null;
13986
+ }
13987
+ return v;
13988
+ }
14061
13989
  // A message is ADDRESSED: it names one component and stops there.
14062
- send(name, args, opts) {
14063
- return this.sendAtPath(this.path, name, args, opts);
13990
+ send(name, args) {
13991
+ return this.sendAtPath(this.path, name, args);
14064
13992
  }
14065
- sendAtPath(path, name, args, opts) {
14066
- return this.transactor.pushSend(path, name, args, opts, this.parent);
13993
+ sendAtPath(path, name, args) {
13994
+ return this.transactor.pushSend(path, name, args, this.parent, this.path);
14067
13995
  }
14068
13996
  // An intent is ROUTED: it names a job and walks until something answers. The verb
14069
13997
  // does not decide which scope answers — `opts.route` does, written here at the call
@@ -14074,9 +14002,6 @@ var init_transactor = __esm({
14074
14002
  intentAtPath(path, name, args, opts) {
14075
14003
  return this.transactor.pushIntent(path, name, args, opts, this.parent);
14076
14004
  }
14077
- lookupTypeFor(name, inst) {
14078
- return this.transactor.comps.getCompFor(inst).scope.lookupComponent(name);
14079
- }
14080
14005
  };
14081
14006
  EventContext = class extends Dispatcher {
14082
14007
  get name() {
@@ -14093,6 +14018,19 @@ var init_transactor = __esm({
14093
14018
  fail(error) {
14094
14019
  return this.parent.walk === void 0 ? warnNotIntent("fail") : this.parent.walk.answer("Error", error);
14095
14020
  }
14021
+ // Reply to the sender of the MESSAGE being handled. An intent answers under a name
14022
+ // the runtime derives (`<name>Ok`), because the raiser asked a question and declared
14023
+ // arms for it; a message did not, so the replier names the reply itself and the
14024
+ // sender handles it like any other message. Refuses when nobody sent this — a view's
14025
+ // own `@on.*`, or a host sendAtRoot.
14026
+ sendReply(name, args) {
14027
+ const origin = this.parent?.origin ?? null;
14028
+ if (origin == null) {
14029
+ this.transactor.refuse("NO_SENDER", { name });
14030
+ return null;
14031
+ }
14032
+ return this.sendAtPath(origin, name, args);
14033
+ }
14096
14034
  // End the walk answering nothing — "served, and no answer".
14097
14035
  stop() {
14098
14036
  return this.parent.stop();
@@ -14104,15 +14042,13 @@ var init_transactor = __esm({
14104
14042
  return this.parent.forward(opts);
14105
14043
  }
14106
14044
  };
14107
- IntentContext = class extends Dispatcher {
14108
- };
14109
14045
  PathChanges = class extends PathBuilder {
14110
14046
  constructor(dispatcher) {
14111
14047
  super();
14112
14048
  this.dispatcher = dispatcher;
14113
14049
  }
14114
- send(name, args, opts) {
14115
- return this.dispatcher.sendAtPath(this.buildPath(), name, args, opts);
14050
+ send(name, args) {
14051
+ return this.dispatcher.sendAtPath(this.buildPath(), name, args);
14116
14052
  }
14117
14053
  intent(name, args, opts) {
14118
14054
  return this.dispatcher.intentAtPath(this.buildPath(), name, args, opts);
@@ -14310,9 +14246,10 @@ var init_app = __esm({
14310
14246
  }
14311
14247
  compile() {
14312
14248
  for (const Comp of this.comps.byId.values()) {
14313
- Comp.compile(this.ParseContext);
14314
- for (const key in Comp.views)
14315
- for (const name of Comp.views[key].ctx.genEventNames()) this._eventNames.add(name);
14249
+ const meta = Comp[COMPONENT];
14250
+ meta.compile(this.ParseContext);
14251
+ for (const key in meta.views)
14252
+ for (const name of meta.views[key].ctx.genEventNames()) this._eventNames.add(name);
14316
14253
  }
14317
14254
  this._compiled = true;
14318
14255
  }
@@ -14338,8 +14275,8 @@ var init_app = __esm({
14338
14275
  for (const name of this._eventNames)
14339
14276
  this.rootNode.removeEventListener(name, this, listenerOpts(name));
14340
14277
  }
14341
- sendAtRoot(name, args, opts) {
14342
- this.transactor.pushSend(new Path([]), name, args, opts);
14278
+ sendAtRoot(name, args) {
14279
+ this.transactor.pushSend(new Path([]), name, args);
14343
14280
  }
14344
14281
  registerComponents(comps, opts) {
14345
14282
  const scope = this.compStack.enter();
@@ -14399,7 +14336,7 @@ function dispatchPhase(dispatcher, targetPath, phase, self) {
14399
14336
  const args = resolveArgs(op.args, self);
14400
14337
  switch (op.type) {
14401
14338
  case "send":
14402
- dispatcher.sendAtPath(targetPath, op.name, args, op.opts);
14339
+ dispatcher.sendAtPath(targetPath, op.name, args);
14403
14340
  break;
14404
14341
  case "intent":
14405
14342
  dispatcher.intentAtPath(targetPath, op.name, args, op.opts);
@@ -14414,6 +14351,195 @@ var init_on = __esm({
14414
14351
  }
14415
14352
  });
14416
14353
 
14354
+ // src/cache.js
14355
+ var isWeakKey, NullDomCache, WeakMapDomCache;
14356
+ var init_cache = __esm({
14357
+ "src/cache.js"() {
14358
+ isWeakKey = (k) => k !== null && (typeof k === "object" || typeof k === "function");
14359
+ NullDomCache = class {
14360
+ get(_keys, _cacheKey) {
14361
+ }
14362
+ set(_keys, _cacheKey, _v) {
14363
+ }
14364
+ evict() {
14365
+ return { hit: 0, miss: 0, badKey: 0 };
14366
+ }
14367
+ };
14368
+ WeakMapDomCache = class {
14369
+ constructor() {
14370
+ this.hit = this.miss = this.badKey = 0;
14371
+ this.keysByLen = /* @__PURE__ */ new Map();
14372
+ }
14373
+ _returnValue(r) {
14374
+ if (r === void 0) this.miss += 1;
14375
+ else this.hit += 1;
14376
+ return r;
14377
+ }
14378
+ get(keys, cacheKey) {
14379
+ const len = keys.length;
14380
+ let cur = this.keysByLen.get(len);
14381
+ if (!cur) return this._returnValue(void 0);
14382
+ for (let i = 0; i < len - 1; i++) {
14383
+ cur = cur.get(keys[i]);
14384
+ if (!cur) return this._returnValue(void 0);
14385
+ }
14386
+ return this._returnValue(cur.get(keys[len - 1])?.[cacheKey]);
14387
+ }
14388
+ set(keys, cacheKey, v) {
14389
+ const len = keys.length;
14390
+ let cur = this.keysByLen.get(len);
14391
+ if (!cur) {
14392
+ cur = /* @__PURE__ */ new WeakMap();
14393
+ this.keysByLen.set(len, cur);
14394
+ }
14395
+ for (let i = 0; i < len - 1; i++) {
14396
+ const key = keys[i];
14397
+ let next = cur.get(key);
14398
+ if (!next) {
14399
+ if (!isWeakKey(key)) {
14400
+ this.badKey += 1;
14401
+ return;
14402
+ }
14403
+ next = /* @__PURE__ */ new WeakMap();
14404
+ cur.set(key, next);
14405
+ }
14406
+ cur = next;
14407
+ }
14408
+ const lastKey = keys[len - 1];
14409
+ const leaf = cur.get(lastKey);
14410
+ if (leaf) leaf[cacheKey] = v;
14411
+ else if (isWeakKey(lastKey)) cur.set(lastKey, { [cacheKey]: v });
14412
+ else this.badKey += 1;
14413
+ }
14414
+ evict() {
14415
+ const { hit, miss, badKey } = this;
14416
+ this.hit = this.miss = this.badKey = 0;
14417
+ this.keysByLen = /* @__PURE__ */ new Map();
14418
+ return { hit, miss, badKey };
14419
+ }
14420
+ };
14421
+ }
14422
+ });
14423
+
14424
+ // src/renderer.js
14425
+ var DATASET_ATTRS, Renderer;
14426
+ var init_renderer = __esm({
14427
+ "src/renderer.js"() {
14428
+ init_cache();
14429
+ init_iteration();
14430
+ init_vdom();
14431
+ DATASET_ATTRS = ["nid", "cid", "eid", "vid", "si", "sk"];
14432
+ Renderer = class {
14433
+ constructor(comps) {
14434
+ this.comps = comps;
14435
+ this.cache = new WeakMapDomCache();
14436
+ this.renderTag = h;
14437
+ }
14438
+ renderFragment(childs) {
14439
+ return new VFragment(childs);
14440
+ }
14441
+ renderComment(text) {
14442
+ return new VComment(text);
14443
+ }
14444
+ setNullCache() {
14445
+ this.cache = new NullDomCache();
14446
+ }
14447
+ renderToDOM(stack, val) {
14448
+ const rootNode = document.createElement("div");
14449
+ const rOpts = { document };
14450
+ render(h("DIV", null, [this.renderRoot(stack, val)]), rootNode, rOpts);
14451
+ return rootNode.childNodes[0];
14452
+ }
14453
+ renderToString(stack, val, cleanAttrs = true) {
14454
+ const dom = this.renderToDOM(stack, val);
14455
+ if (cleanAttrs) {
14456
+ const nodes = dom.querySelectorAll("[data-nid],[data-cid],[data-eid]");
14457
+ for (const { dataset } of nodes) for (const name of DATASET_ATTRS) delete dataset[name];
14458
+ }
14459
+ return dom.innerHTML;
14460
+ }
14461
+ renderRoot(stack, val, viewName = null) {
14462
+ const comp = this.comps.getCompFor(val);
14463
+ if (comp === null) return null;
14464
+ return this._rValComp(stack, val, comp, comp.getView(viewName).anode, "ROOT", viewName);
14465
+ }
14466
+ renderIt(stack, node, key, viewName) {
14467
+ const comp = this.comps.getCompFor(stack.it);
14468
+ return comp ? this._rValComp(stack, stack.it, comp, node, key, viewName) : null;
14469
+ }
14470
+ // `node` is the parse node of the render site (`<x render>` / `render-it` /
14471
+ // `render-each`, or the view's root anode for the app root). It keys the
14472
+ // cache as a globally-unique object: node ids alone are unique only within a
14473
+ // single view, so the same value rendered by two components (e.g. through a
14474
+ // shared dynamic-var sequence) would otherwise collide in the cache.
14475
+ _rValComp(stack, val, comp, node, key, viewName) {
14476
+ const cacheKey = `${viewName ?? ""}${stack.viewsId ?? ""}${key}`;
14477
+ const cachePath = [node, val];
14478
+ stack._pushDynBindValuesToArray(cachePath, comp);
14479
+ const cachedNode = this.cache.get(cachePath, cacheKey);
14480
+ if (cachedNode) return cachedNode;
14481
+ const view = viewName ? comp.getView(viewName) : stack.lookupBestView(comp.views, "main");
14482
+ const body = this.renderView(view, stack);
14483
+ if (body == null) return null;
14484
+ const meta = this._renderMetadata({
14485
+ $: "Comp",
14486
+ nid: node?.nodeId ?? null,
14487
+ cid: comp.id,
14488
+ vid: view.name
14489
+ });
14490
+ const dom = new VFragment([meta, body]);
14491
+ this.cache.set(cachePath, cacheKey, dom);
14492
+ return dom;
14493
+ }
14494
+ pushEachEntry(r, nid, attrName, key, dom) {
14495
+ r.push(this._renderMetadata({ $: "Each", nid, [attrName]: key }), dom);
14496
+ }
14497
+ renderEachWhen(stack, iterInfo, view, nid) {
14498
+ const { seq, filter, loopWith, enricher } = iterInfo.eval(stack);
14499
+ const r = [];
14500
+ const it = stack.it;
14501
+ const renderOne = (key, value, attrName, binds) => {
14502
+ const cachePath = enricher ? [view, it, value] : [view, value];
14503
+ const cacheKey = `${stack.viewsId ?? ""}${nid}${key}`;
14504
+ const cachedNode = this.cache.get(cachePath, cacheKey);
14505
+ if (cachedNode) this.pushEachEntry(r, nid, attrName, key, cachedNode);
14506
+ else {
14507
+ const dom = this.renderView(view, stack.enter(value, binds, false));
14508
+ if (dom != null) this.pushEachEntry(r, nid, attrName, key, dom);
14509
+ this.cache.set(cachePath, cacheKey, dom);
14510
+ }
14511
+ };
14512
+ walkLoopBindings(
14513
+ { seq, it, filter, loopWith, enricher, ctx: makeLoopCtx(stack, filter) },
14514
+ renderOne
14515
+ );
14516
+ return r;
14517
+ }
14518
+ renderView(view, stack) {
14519
+ let n = stack.binds[1];
14520
+ while (n !== null) {
14521
+ const b = n[0];
14522
+ if (b.isFrame) {
14523
+ if (stack.it !== b.it) break;
14524
+ console.error("recursion detected", stack.it, b.it);
14525
+ return new VComment("RECURSION AVOIDED");
14526
+ }
14527
+ n = n[1];
14528
+ }
14529
+ return view.render(stack, this);
14530
+ }
14531
+ _renderMetadata(info) {
14532
+ return new VComment(`§${JSON.stringify(info)}§`);
14533
+ }
14534
+ // Prefix a loop-less @enrich-with subtree with a boundary meta so event-path
14535
+ // reconstruction replays its binds (mirrors the §Each§ / §Comp§ metas).
14536
+ renderScopeMeta(nid, dom) {
14537
+ return new VFragment([this._renderMetadata({ $: "Scope", nid }), dom]);
14538
+ }
14539
+ };
14540
+ }
14541
+ });
14542
+
14417
14543
  // src/util/render.js
14418
14544
  function reindexComponents(comps) {
14419
14545
  for (let i = 0; i < comps.length; i++) {