tutuca 0.13.2 → 0.14.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.
@@ -1243,8 +1243,8 @@ function hasProperty(obj, name) {
1243
1243
  return name in Object(obj);
1244
1244
  }
1245
1245
  __name(hasProperty, "hasProperty");
1246
- function parsePath(path) {
1247
- const str = path.replace(/([^\\])\[/g, "$1.[");
1246
+ function parsePath(path2) {
1247
+ const str = path2.replace(/([^\\])\[/g, "$1.[");
1248
1248
  const parts = str.match(/(\\\.|[^.]+?)+/g);
1249
1249
  return parts.map((value) => {
1250
1250
  if (value === "constructor" || value === "__proto__" || value === "prototype") {
@@ -1282,8 +1282,8 @@ function internalGetPathValue(obj, parsed, pathDepth) {
1282
1282
  return res;
1283
1283
  }
1284
1284
  __name(internalGetPathValue, "internalGetPathValue");
1285
- function getPathInfo(obj, path) {
1286
- const parsed = parsePath(path);
1285
+ function getPathInfo(obj, path2) {
1286
+ const parsed = parsePath(path2);
1287
1287
  const last = parsed[parsed.length - 1];
1288
1288
  const info = {
1289
1289
  parent: parsed.length > 1 ? internalGetPathValue(obj, parsed, parsed.length - 1) : obj,
@@ -4158,8 +4158,8 @@ function jestMatchers(chai, utils) {
4158
4158
  expected
4159
4159
  );
4160
4160
  });
4161
- m("toHaveProperty", function(path, ...rest) {
4162
- const keys = Array.isArray(path) ? path : String(path).split(".");
4161
+ m("toHaveProperty", function(path2, ...rest) {
4162
+ const keys = Array.isArray(path2) ? path2 : String(path2).split(".");
4163
4163
  let cur = this._obj;
4164
4164
  let found = true;
4165
4165
  for (const k of keys) {
@@ -4174,7 +4174,7 @@ function jestMatchers(chai, utils) {
4174
4174
  pass,
4175
4175
  "expected #{this} to have property #{exp}",
4176
4176
  "expected #{this} not to have property #{exp}",
4177
- path
4177
+ path2
4178
4178
  );
4179
4179
  });
4180
4180
  m("toBeInstanceOf", function(ctor) {
@@ -4493,7 +4493,7 @@ function processResult(result, scope) {
4493
4493
  }
4494
4494
  return result !== NOTHING ? result : void 0;
4495
4495
  }
4496
- function finalize(rootScope, value, path) {
4496
+ function finalize(rootScope, value, path2) {
4497
4497
  if (isFrozen(value))
4498
4498
  return value;
4499
4499
  const useStrictIteration = rootScope.immer_.shouldUseStrictIteration();
@@ -4501,7 +4501,7 @@ function finalize(rootScope, value, path) {
4501
4501
  if (!state) {
4502
4502
  each(
4503
4503
  value,
4504
- (key, childValue) => finalizeProperty(rootScope, state, value, key, childValue, path),
4504
+ (key, childValue) => finalizeProperty(rootScope, state, value, key, childValue, path2),
4505
4505
  useStrictIteration
4506
4506
  );
4507
4507
  return value;
@@ -4531,16 +4531,16 @@ function finalize(rootScope, value, path) {
4531
4531
  result,
4532
4532
  key,
4533
4533
  childValue,
4534
- path,
4534
+ path2,
4535
4535
  isSet2
4536
4536
  ),
4537
4537
  useStrictIteration
4538
4538
  );
4539
4539
  maybeFreeze(rootScope, result, false);
4540
- if (path && rootScope.patches_) {
4540
+ if (path2 && rootScope.patches_) {
4541
4541
  getPlugin("Patches").generatePatches_(
4542
4542
  state,
4543
- path,
4543
+ path2,
4544
4544
  rootScope.patches_,
4545
4545
  rootScope.inversePatches_
4546
4546
  );
@@ -4562,9 +4562,9 @@ function finalizeProperty(rootScope, parentState, targetObject, prop, childValue
4562
4562
  if (childValue === targetObject)
4563
4563
  die(5);
4564
4564
  if (isDraft(childValue)) {
4565
- const path = rootPath && parentState && parentState.type_ !== 3 && // Set objects are atomic since they have no keys.
4565
+ const path2 = rootPath && parentState && parentState.type_ !== 3 && // Set objects are atomic since they have no keys.
4566
4566
  !has(parentState.assigned_, prop) ? rootPath.concat(prop) : void 0;
4567
- const res = finalize(rootScope, childValue, path);
4567
+ const res = finalize(rootScope, childValue, path2);
4568
4568
  set2(targetObject, prop, res);
4569
4569
  if (isDraft(res)) {
4570
4570
  rootScope.canAutoFreeze_ = false;
@@ -4979,8 +4979,11 @@ var Step = class {
4979
4979
  }
4980
4980
  setDraftValue(_root, _v) {
4981
4981
  }
4982
- enterFrame(stack, next) {
4983
- return stack.enter(next, {}, true);
4982
+ // Re-enter this step while rebuilding a stack. `renderPath` is the dispatch
4983
+ // position AFTER this step: a rebuilt frame must carry the same render path
4984
+ // the renderer had there, or the provides it publishes would be located wrong.
4985
+ enterFrame(stack, next, renderPath) {
4986
+ return stack.enter(next, {}, true, renderPath);
4984
4987
  }
4985
4988
  toAbstractPathStep() {
4986
4989
  return this;
@@ -5005,8 +5008,8 @@ var BindStep = class _BindStep extends Step {
5005
5008
  lookup(v, _dval) {
5006
5009
  return v;
5007
5010
  }
5008
- enterFrame(stack, next) {
5009
- return stack.enter(next, { ...this.binds }, false);
5011
+ enterFrame(stack, next, renderPath) {
5012
+ return stack.enter(next, { ...this.binds }, false, renderPath);
5010
5013
  }
5011
5014
  withIndex(i) {
5012
5015
  return new _BindStep({ ...this.binds, key: i });
@@ -5023,9 +5026,9 @@ var ScopeBindStep = class _ScopeBindStep extends BindStep {
5023
5026
  super(binds);
5024
5027
  this.val = val;
5025
5028
  }
5026
- enterFrame(stack, next) {
5029
+ enterFrame(stack, next, renderPath) {
5027
5030
  const dyn = this.val.evalAsHandler(stack)?.call(stack.it) ?? {};
5028
- return stack.enter(next, { ...this.binds, ...dyn }, false);
5031
+ return stack.enter(next, { ...this.binds, ...dyn }, false, renderPath);
5029
5032
  }
5030
5033
  withIndex(i) {
5031
5034
  return new _ScopeBindStep(this.val, { ...this.binds, key: i });
@@ -5068,8 +5071,8 @@ var SeqStep = class extends Step {
5068
5071
  const seq = readKey(root, this.field, null);
5069
5072
  if (seq != null) writeSeqKey(seq, this.key, v);
5070
5073
  }
5071
- enterFrame(stack, next) {
5072
- return stack.enter(next, { key: this.key }, true);
5074
+ enterFrame(stack, next, renderPath) {
5075
+ return stack.enter(next, { key: this.key }, true, renderPath);
5073
5076
  }
5074
5077
  toKey() {
5075
5078
  return { field: this.field, key: this.key };
@@ -5115,60 +5118,52 @@ var EachBindStep = class extends Step {
5115
5118
  }
5116
5119
  // Replay the renderer's per-item binds (key, value + any @enrich-with binds)
5117
5120
  // so a rebuilt stack matches the one @each rendered with.
5118
- enterFrame(stack, next) {
5119
- return stack.enter(next, this.iterInfo.enrichBinds(stack, this.key), false);
5121
+ enterFrame(stack, next, renderPath) {
5122
+ return stack.enter(next, this.iterInfo.enrichBinds(stack, this.key), false, renderPath);
5120
5123
  }
5121
5124
  toAbstractPathStep() {
5122
5125
  return null;
5123
5126
  }
5124
5127
  };
5125
5128
  var EachRenderItStep = class extends SeqStep {
5126
- enterFrame(stack, next) {
5127
- return stack.enter(next, { key: this.key, value: next }, false).enter(next, {}, true);
5129
+ enterFrame(stack, next, renderPath) {
5130
+ return stack.enter(next, { key: this.key, value: next }, false, renderPath).enter(next, {}, true, renderPath);
5128
5131
  }
5129
5132
  toAbstractPathStep() {
5130
5133
  return new SeqStep(this.field, this.key);
5131
5134
  }
5132
5135
  };
5133
- function warnRawDynStep(op, step) {
5134
- console.warn(`Path.${op} reached a DynStep: call toTransactionPath() first`, step);
5136
+ function stepToJson(step) {
5137
+ if (step instanceof SeqStep) return { f: step.field, k: step.key };
5138
+ if (step instanceof FieldStep) return { f: step.field };
5139
+ if (step instanceof SeqAccessStep) return { f: step.seqField, a: step.keyField };
5140
+ return null;
5135
5141
  }
5136
- var DynStep = class extends Step {
5137
- constructor(producerCompId, producerSteps) {
5138
- super();
5139
- this.producerCompId = producerCompId;
5140
- this.producerSteps = producerSteps;
5141
- this.interiorCids = /* @__PURE__ */ new Set();
5142
- }
5143
- // Steps spliced into the transaction path in place of this marker.
5144
- teleportSteps() {
5145
- return this.producerSteps;
5146
- }
5147
- lookup(_v, dval = null) {
5148
- warnRawDynStep("lookup", this);
5149
- return dval;
5150
- }
5151
- enterFrame(stack, _next) {
5152
- warnRawDynStep("enterFrame", this);
5153
- return stack;
5154
- }
5155
- };
5156
- var DynEachStep = class extends DynStep {
5157
- constructor(producerCompId, producerSteps, key) {
5158
- super(producerCompId, producerSteps);
5159
- this.key = key;
5142
+ function stepFromJson(j) {
5143
+ if (j == null || typeof j.f !== "string") return null;
5144
+ if (j.k !== void 0) return new SeqStep(j.f, j.k);
5145
+ if (j.a !== void 0) return new SeqAccessStep(j.f, j.a);
5146
+ return new FieldStep(j.f);
5147
+ }
5148
+ function pathToJson(path2) {
5149
+ const out = [];
5150
+ for (const step of path2.steps) {
5151
+ const j = stepToJson(step);
5152
+ if (j === null) return null;
5153
+ out.push(j);
5160
5154
  }
5161
- teleportSteps() {
5162
- const { producerSteps, key } = this;
5163
- if (producerSteps.length === 0) return producerSteps;
5164
- const last = producerSteps[producerSteps.length - 1];
5165
- if (!(last instanceof FieldStep)) {
5166
- console.warn("DynEachStep: seq-access dynamic cannot be iterated", this);
5167
- return producerSteps;
5168
- }
5169
- return producerSteps.slice(0, -1).concat(new SeqStep(last.field, key));
5155
+ return out;
5156
+ }
5157
+ function pathFromJson(j) {
5158
+ if (!Array.isArray(j)) return null;
5159
+ const steps = [];
5160
+ for (const item of j) {
5161
+ const step = stepFromJson(item);
5162
+ if (step === null) return null;
5163
+ steps.push(step);
5170
5164
  }
5171
- };
5165
+ return new Path(steps);
5166
+ }
5172
5167
  var Path = class _Path {
5173
5168
  constructor(steps = []) {
5174
5169
  this.steps = steps;
@@ -5179,40 +5174,13 @@ var Path = class _Path {
5179
5174
  popStep() {
5180
5175
  return new _Path(this.steps.slice(0, -1));
5181
5176
  }
5182
- // The dispatch path: frame-only steps removed, one step per crossed component
5183
- // (DynStep included). `popStep` over it bubbles through every component.
5177
+ // Frame-only steps removed, one step per crossed component: `popStep` over the
5178
+ // result bubbles through every component.
5184
5179
  compact() {
5185
5180
  const out = [];
5186
5181
  for (const step of this.steps) {
5187
5182
  const s = step.toAbstractPathStep();
5188
- if (s !== null) {
5189
- if (s !== step) s._originCid = step._originCid;
5190
- out.push(s);
5191
- }
5192
- }
5193
- return new _Path(out);
5194
- }
5195
- // The abstract path used to apply a transaction: every DynStep is teleported —
5196
- // the steps interior to its producer..consumer span are dropped and the
5197
- // producer's own path spliced in — so a mutation lands on the data's real
5198
- // location. A path with no DynStep is returned unchanged.
5199
- toTransactionPath() {
5200
- let hasDyn = false;
5201
- for (const step of this.steps)
5202
- if (step instanceof DynStep) {
5203
- hasDyn = true;
5204
- break;
5205
- }
5206
- if (!hasDyn) return this;
5207
- const out = [];
5208
- for (const step of this.steps) {
5209
- if (step instanceof DynStep) {
5210
- while (out.length > 0 && step.interiorCids.has(out[out.length - 1]._originCid)) out.pop();
5211
- for (const ts of step.teleportSteps()) {
5212
- ts._originCid = step.producerCompId;
5213
- out.push(ts);
5214
- }
5215
- } else out.push(step);
5183
+ if (s !== null) out.push(s);
5216
5184
  }
5217
5185
  return new _Path(out);
5218
5186
  }
@@ -5220,7 +5188,6 @@ var Path = class _Path {
5220
5188
  // key as it is *now* so a later lookup/setValue lands on the same item even if the
5221
5189
  // keyField changed meanwhile (e.g. the selected tab moved while an intent was in
5222
5190
  // flight). Returns a new Path with those steps replaced; `this` if nothing pinned.
5223
- // Must be called on a transaction path (no DynSteps — call toTransactionPath first).
5224
5191
  pinKeys(root) {
5225
5192
  let curVal = root;
5226
5193
  let out = null;
@@ -5243,8 +5210,8 @@ var Path = class _Path {
5243
5210
  }
5244
5211
  // The values entered along the path, root→leaf (root included): index 0 is `root`,
5245
5212
  // the last entry is the leaf this path resolves to. Stops early at the first
5246
- // unresolvable step. Call on a transaction path (no DynSteps). Used to walk the
5247
- // component instances on a dispatch path (filter via Components.getCompFor).
5213
+ // unresolvable step. Used to walk the component instances on a dispatch path
5214
+ // (filter via Components.getCompFor).
5248
5215
  resolveChain(root) {
5249
5216
  const out = [root];
5250
5217
  let curVal = root;
@@ -5258,7 +5225,7 @@ var Path = class _Path {
5258
5225
  // A flat `[{ field, key? }]` list of the addressing steps, skipping frame-only
5259
5226
  // steps (binds). Generic path introspection so tooling (e.g. the storybook
5260
5227
  // activity log) can identify which subtree a transaction touched without
5261
- // depending on Step internals. Call on a transaction path (no DynSteps).
5228
+ // depending on Step internals.
5262
5229
  toKeys() {
5263
5230
  const out = [];
5264
5231
  for (const step of this.steps) {
@@ -5279,62 +5246,147 @@ var Path = class _Path {
5279
5246
  });
5280
5247
  }
5281
5248
  buildStack(stack) {
5282
- let prev = stack.it;
5283
- for (const step of this.steps) {
5284
- const next = step.lookup(prev, NONE);
5285
- if (next === NONE) {
5286
- console.warn("bad PathItem", { root: stack.it, step, path: this });
5287
- return null;
5249
+ return walkItems(stack, this.steps, stack.renderPath ?? new DispatchPath(), this)?.[0] ?? null;
5250
+ }
5251
+ };
5252
+ function walkItems(stack, items, renderPath, path2) {
5253
+ let prev = stack.it;
5254
+ for (const step of items) {
5255
+ const next = step.lookup(prev, NONE);
5256
+ if (next === NONE) {
5257
+ console.warn("bad PathItem", { root: stack.it, step, path: path2 });
5258
+ return null;
5259
+ }
5260
+ renderPath = renderPath.pushItem(step);
5261
+ stack = step.enterFrame(stack, next, renderPath);
5262
+ prev = next;
5263
+ }
5264
+ return [stack, renderPath];
5265
+ }
5266
+ var EMPTY_PATH = new Path([]);
5267
+ var DispatchPath = class _DispatchPath {
5268
+ constructor(frames = [{ base: EMPTY_PATH, items: [] }]) {
5269
+ this.frames = frames;
5270
+ }
5271
+ // Plain addressing steps in one frame based at the root: what a caller means
5272
+ // by "this position" when it has no continuation of its own.
5273
+ static ofSteps(steps) {
5274
+ return new _DispatchPath([{ base: EMPTY_PATH, items: steps.slice() }]);
5275
+ }
5276
+ get top() {
5277
+ return this.frames[this.frames.length - 1];
5278
+ }
5279
+ _withTopItems(items) {
5280
+ const frames = this.frames.slice();
5281
+ frames[frames.length - 1] = { base: this.top.base, items };
5282
+ return new _DispatchPath(frames);
5283
+ }
5284
+ concat(steps) {
5285
+ if (this.frames.length === 0) return _DispatchPath.ofSteps(steps);
5286
+ return this._withTopItems(this.top.items.concat(steps));
5287
+ }
5288
+ pushItem(step) {
5289
+ return this.concat([step]);
5290
+ }
5291
+ pushFrame(base) {
5292
+ return new _DispatchPath(this.frames.concat({ base, items: [] }));
5293
+ }
5294
+ // Whether bubbling has anywhere left to go: another step in this frame, or a
5295
+ // visual caller underneath it.
5296
+ canPop() {
5297
+ const n = this.frames.length;
5298
+ return n > 1 || n === 1 && this.frames[0].items.length > 0;
5299
+ }
5300
+ isRoot() {
5301
+ return this.toTransactionPath().steps.length === 0;
5302
+ }
5303
+ // One component closer to the root. At the top of a frame that is popping back
5304
+ // to the visual caller, not to the producer's own parent — the caller is where
5305
+ // the `*name` was written, and where an unhandled message should keep going.
5306
+ popStep() {
5307
+ const n = this.frames.length;
5308
+ if (n === 0) return this;
5309
+ const top = this.frames[n - 1];
5310
+ if (top.items.length > 0) return this._withTopItems(top.items.slice(0, -1));
5311
+ if (n > 1) return new _DispatchPath(this.frames.slice(0, -1));
5312
+ return this;
5313
+ }
5314
+ // Drop frame-only steps inside every frame independently; a frame's base is
5315
+ // already addressing-only.
5316
+ compact() {
5317
+ return new _DispatchPath(
5318
+ this.frames.map(({ base, items }) => ({ base, items: new Path(items).compact().steps }))
5319
+ );
5320
+ }
5321
+ // A stable string for the ADDRESS this path denotes, for the render cache. The
5322
+ // same immutable value can sit at two places in the tree, and a subtree rendered
5323
+ // at one of them bakes that address in — the provides it publishes are located
5324
+ // there. Frame-only steps address nothing, so they are compacted out: two sites
5325
+ // that differ only in binds do render the same subtree.
5326
+ get addressKey() {
5327
+ this._addressKey ??= renderPathText(this.toTransactionPath().compact());
5328
+ return this._addressKey;
5329
+ }
5330
+ // The active transaction address: the top frame's absolute base followed by
5331
+ // its ordinary descendant steps. This is where a mutation lands.
5332
+ toTransactionPath() {
5333
+ const top = this.top;
5334
+ return top === void 0 ? EMPTY_PATH : top.base.concat(top.items);
5335
+ }
5336
+ // Rebuild the render stack this path was dispatched from. A frame with a base
5337
+ // re-enters at that absolute value first — replaying the resume a `*name`
5338
+ // render performed — and then walks its ordinary items.
5339
+ buildStack(stack) {
5340
+ let renderPath = new _DispatchPath();
5341
+ for (let i = 0; i < this.frames.length; i++) {
5342
+ const { base, items } = this.frames[i];
5343
+ if (i > 0 || base.steps.length > 0) {
5344
+ const baseValue = base.lookup(stack.root, NONE);
5345
+ if (baseValue === NONE) {
5346
+ console.warn("bad frame base", { base, path: this });
5347
+ return null;
5348
+ }
5349
+ renderPath = renderPath.pushFrame(base);
5350
+ stack = stack.enter(baseValue, {}, true, renderPath);
5288
5351
  }
5289
- stack = step.enterFrame(stack, next);
5290
- prev = next;
5352
+ const walked = walkItems(stack, items, renderPath, this);
5353
+ if (walked === null) return null;
5354
+ [stack, renderPath] = walked;
5291
5355
  }
5292
5356
  return stack;
5293
5357
  }
5294
5358
  static fromNodeAndEventName(node, eventName, rootNode, maxDepth, comps, stopOnNoEvent = true) {
5295
- const pathSteps = [];
5296
- const pendingDyns = [];
5359
+ const parts = [];
5297
5360
  const bubbles = BUBBLING_EVENTS.has(eventName);
5298
5361
  let depth = 0;
5299
5362
  let eventIds = [];
5300
5363
  let handlers = null;
5301
- let nodeIds = [];
5364
+ let nodeRefs = [];
5302
5365
  let isLeafComponent = true;
5303
5366
  const crossComponent = (cidNum, vid) => {
5304
5367
  const comp = comps.getComponentForId(cidNum);
5305
- let pushStep = true;
5368
+ let pushPart = true;
5306
5369
  if (handlers === null && (isLeafComponent || bubbles)) {
5307
5370
  handlers = findHandlers(comp, eventIds, vid, eventName);
5308
5371
  if (handlers === null) {
5309
5372
  if (isLeafComponent && stopOnNoEvent && !bubbles) return false;
5310
5373
  } else if (!isLeafComponent) {
5311
- pathSteps.length = 0;
5312
- pendingDyns.length = 0;
5313
- pushStep = false;
5374
+ parts.length = 0;
5375
+ pushPart = false;
5314
5376
  }
5315
5377
  }
5316
5378
  isLeafComponent = false;
5317
- for (const dyn of pendingDyns) dyn.interiorCids.add(cidNum);
5318
- if (pushStep) {
5319
- const step = resolvePathStep(comp, nodeIds, vid);
5320
- if (step) {
5321
- step._originCid = cidNum;
5322
- pathSteps.push(step);
5323
- if (step instanceof DynStep) {
5324
- step.interiorCids.add(cidNum);
5325
- pendingDyns.push(step);
5326
- }
5327
- }
5379
+ if (pushPart) {
5380
+ const part = resolvePathPart(comp, nodeRefs, vid);
5381
+ if (part) parts.push(part);
5328
5382
  }
5329
- for (let i = pendingDyns.length - 1; i >= 0; i--)
5330
- if (pendingDyns[i].producerCompId === cidNum) pendingDyns.splice(i, 1);
5331
5383
  eventIds = [];
5332
- nodeIds = [];
5384
+ nodeRefs = [];
5333
5385
  return true;
5334
5386
  };
5335
5387
  while (node && node !== rootNode && depth < maxDepth) {
5336
5388
  if (node?.dataset) {
5337
- const { eid, cid, vid } = node.dataset;
5389
+ const { eid, cid, vid, rp } = node.dataset;
5338
5390
  if (eid !== void 0) eventIds.push(eid);
5339
5391
  const metas = metaChain(node.previousSibling);
5340
5392
  let sawComp = false;
@@ -5342,21 +5394,47 @@ var Path = class _Path {
5342
5394
  if (m.$ === "Comp") {
5343
5395
  sawComp = true;
5344
5396
  if (!crossComponent(m.cid, m.vid)) return NO_EVENT_INFO;
5345
- nodeIds.push({ nid: m.nid });
5397
+ nodeRefs.push({ nid: m.nid, base: pathFromJson(m.base) });
5346
5398
  } else {
5347
- nodeIds.push({ nid: m.nid, si: m.si, sk: m.sk });
5399
+ nodeRefs.push({ nid: m.nid, si: m.si, sk: m.sk });
5400
+ }
5401
+ }
5402
+ if (!sawComp && cid !== void 0) {
5403
+ if (!crossComponent(+cid, vid)) return NO_EVENT_INFO;
5404
+ if (rp !== void 0) {
5405
+ const base = parseRenderPath(rp);
5406
+ if (base !== null) nodeRefs.push({ base });
5348
5407
  }
5349
5408
  }
5350
- if (!sawComp && cid !== void 0 && !crossComponent(+cid, vid)) return NO_EVENT_INFO;
5351
5409
  }
5352
5410
  depth += 1;
5353
5411
  node = node.parentNode;
5354
5412
  }
5355
- if (pendingDyns.length > 0)
5356
- console.warn("event reconstruction: dynamic-var producer not found", pendingDyns);
5357
- return [new _Path(pathSteps.reverse()), handlers];
5413
+ parts.reverse();
5414
+ let path2 = new _DispatchPath();
5415
+ for (const part of parts)
5416
+ path2 = part.base !== void 0 ? path2.pushFrame(part.base) : path2.pushItem(part.step);
5417
+ return [path2, handlers];
5358
5418
  }
5359
5419
  };
5420
+ function keyedPath(path2, key) {
5421
+ const steps = path2.steps;
5422
+ const last = steps[steps.length - 1];
5423
+ if (last instanceof SeqStep || last instanceof FieldStep)
5424
+ return new Path(steps.slice(0, -1).concat(new SeqStep(last.field, key)));
5425
+ return null;
5426
+ }
5427
+ function renderPathText(path2) {
5428
+ return JSON.stringify(pathToJson(path2));
5429
+ }
5430
+ function parseRenderPath(text) {
5431
+ try {
5432
+ return pathFromJson(JSON.parse(text));
5433
+ } catch (err) {
5434
+ console.warn("bad render path", err, text);
5435
+ return null;
5436
+ }
5437
+ }
5360
5438
  function metaChain(n) {
5361
5439
  const out = [];
5362
5440
  while (n?.nodeType === 8 && n.textContent[0] === "§") {
@@ -5409,20 +5487,27 @@ var StepCtx = class _StepCtx {
5409
5487
  return pi;
5410
5488
  }
5411
5489
  };
5412
- function resolvePathStep(comp, nodeIds, vid) {
5413
- for (let i = 0; i < nodeIds.length; i++) {
5414
- const ctx = new StepCtx(comp, nodeIds, i, vid);
5415
- const step = ctx.resolveNode().toPathStep(ctx);
5416
- if (step !== null) return step;
5490
+ function resolvePathPart(comp, nodeRefs, vid) {
5491
+ for (let i = 0; i < nodeRefs.length; i++) {
5492
+ const ref = nodeRefs[i];
5493
+ if (ref.base != null) return { base: ref.base };
5494
+ if (ref.nid === void 0 || ref.nid === null) continue;
5495
+ const ctx = new StepCtx(comp, nodeRefs, i, vid);
5496
+ const step = ctx.resolveNode()?.toPathStep(ctx) ?? null;
5497
+ if (step !== null) return { step };
5417
5498
  }
5418
5499
  return null;
5419
5500
  }
5420
5501
  var NO_EVENT_INFO = [null, null];
5421
5502
  var BUBBLING_EVENTS = /* @__PURE__ */ new Set(["drop"]);
5503
+ var path = () => new PathBuilder();
5422
5504
  var PathBuilder = class {
5423
5505
  constructor() {
5424
5506
  this.pathChanges = [];
5425
5507
  }
5508
+ toPath() {
5509
+ return new Path(this.pathChanges);
5510
+ }
5426
5511
  add(pathChange) {
5427
5512
  this.pathChanges.push(pathChange);
5428
5513
  return this;
@@ -5559,31 +5644,14 @@ function parseBool(s, px) {
5559
5644
  const val = parseToken(tokens[0], px);
5560
5645
  return val !== null && kindOf(val) & G_BOOL ? val : null;
5561
5646
  }
5562
- function parseText(s, px) {
5563
- return _parseSingle(s, px, G_TEXT);
5564
- }
5565
- function parseComponent(s, px) {
5566
- return _parseSingle(s, px, G_COMPONENT);
5567
- }
5568
- function parseSequence(s, px) {
5569
- return _parseSingle(s, px, G_SEQUENCE);
5570
- }
5571
- function parseField(s, px) {
5572
- return _parseSingle(s, px, G_FIELD);
5573
- }
5574
- function parseProvide(s, px) {
5575
- return _parseSingle(s, px, G_PROVIDE);
5576
- }
5577
- function parseMacroAttr(s, px) {
5578
- return _parseSingle(s, px, G_ALL);
5579
- }
5580
- function parseReceiveHandler(s, px) {
5581
- return _parseHandler(s, px, "receive", true, true, false);
5582
- }
5583
- function parseAlterHandler(s, px) {
5584
- const r = _parseHandler(s, px, "alter", false, false, true);
5585
- return r === null ? null : r.handlerVal;
5586
- }
5647
+ var parseText = (s, px) => _parseSingle(s, px, G_TEXT);
5648
+ var parseComponent = (s, px) => _parseSingle(s, px, G_COMPONENT);
5649
+ var parseSequence = (s, px) => _parseSingle(s, px, G_SEQUENCE);
5650
+ var parseField = (s, px) => _parseSingle(s, px, G_FIELD);
5651
+ var parseProvide = (s, px) => _parseSingle(s, px, G_PROVIDE);
5652
+ var parseMacroAttr = (s, px) => _parseSingle(s, px, G_ALL);
5653
+ var parseReceiveHandler = (s, px) => _parseHandler(s, px, "receive", true, true, false);
5654
+ var parseAlterHandler = (s, px) => _parseHandler(s, px, "alter", false, false, true)?.handlerVal ?? null;
5587
5655
  function _parseHandler(s, px, namespace, allowArgs, report, allowMethod) {
5588
5656
  const tokens = tokenizeValue(s.trim());
5589
5657
  const headTok = tokens[0] ?? "";
@@ -6272,19 +6340,9 @@ function childOpts(vnode, ns, opts) {
6272
6340
  const target = ns === SVG_NS && isForeignObject(vnode.tag) ? null : ns;
6273
6341
  return target === (opts.namespace ?? null) ? opts : { ...opts, namespace: target };
6274
6342
  }
6275
- var NEVER_ASSIGN = /* @__PURE__ */ new Set([
6276
- "width",
6277
- "height",
6278
- "href",
6279
- "list",
6280
- "form",
6281
- "tabIndex",
6282
- "download",
6283
- "rowSpan",
6284
- "colSpan",
6285
- "role",
6286
- "popover"
6287
- ]);
6343
+ var NEVER_ASSIGN = new Set(
6344
+ "width height href list form tabIndex download rowSpan colSpan role popover".split(" ")
6345
+ );
6288
6346
  var PROP_ATTR_NAME = { className: "class", htmlFor: "for" };
6289
6347
  function applyProperties(node, props) {
6290
6348
  const namespaced = isNamespaced(node);
@@ -6563,6 +6621,10 @@ function morphChildren(parentDom, oldChilds, newChilds, opts) {
6563
6621
  if (!used2[i] && domNodes[i].parentNode === parentDom) parentDom.removeChild(domNodes[i]);
6564
6622
  }
6565
6623
  function render(vnode, container, options, prev) {
6624
+ if (vnode == null) {
6625
+ container.replaceChildren();
6626
+ return { vnode: null, dom: null };
6627
+ }
6566
6628
  const isFragment = vnode instanceof VFragment;
6567
6629
  if (prev && prev.vnode instanceof VFragment === isFragment) {
6568
6630
  const oldDom = isFragment ? container : prev.dom;
@@ -6602,13 +6664,16 @@ function h(tagName, properties, children, namespace) {
6602
6664
  }
6603
6665
 
6604
6666
  // src/anode.js
6605
- function resolveDynProducer(comp, name) {
6606
- const own = comp?.provide?.[name];
6607
- const producerComp = own != null ? comp : comp?.scope?.lookupProvider(name) ?? null;
6608
- const producerProvide = own ?? producerComp?.provide?.[name];
6609
- if (producerComp == null || producerProvide == null) return null;
6610
- const pi = producerProvide.val?.toPathItem?.() ?? null;
6611
- return { producerCompId: producerComp.id, producerSteps: pi ? [pi] : [] };
6667
+ function renderTarget(val, stack) {
6668
+ if (val instanceof DynVal) {
6669
+ const loc = stack.lookupDynamicLocated(val.name);
6670
+ if (loc?.path == null) return [loc?.value ?? null, stack.renderPath, null];
6671
+ return [loc.value, stack.renderPath.pushFrame(loc.path), loc.path];
6672
+ }
6673
+ const step = val.toPathItem?.() ?? null;
6674
+ if (step === null) return [val.eval(stack), stack.renderPath, null];
6675
+ const path2 = stack.renderPath.pushItem(step);
6676
+ return [val.eval(stack), path2, stack.pendingFrame ? path2.toTransactionPath() : null];
6612
6677
  }
6613
6678
  var BaseNode = class {
6614
6679
  render(_stack, _rx) {
@@ -6930,33 +6995,31 @@ var RenderViewId = class extends ANode {
6930
6995
  setDataAttr(_key, _val) {
6931
6996
  }
6932
6997
  };
6933
- function dynRenderStep(comp, name, key) {
6934
- const p = resolveDynProducer(comp, name);
6935
- if (!p) return null;
6936
- return key === void 0 ? new DynStep(p.producerCompId, p.producerSteps) : new DynEachStep(p.producerCompId, p.producerSteps, key);
6937
- }
6938
6998
  var RenderNode = class extends RenderViewId {
6939
6999
  render(stack, rx) {
6940
- const newStack = stack.enter(this.val.eval(stack), {}, true);
6941
- return rx.renderIt(newStack, this, "", this.evalViewName(stack));
7000
+ const [value, renderPath, base] = renderTarget(this.val, stack);
7001
+ const newStack = stack.enter(value, {}, true, renderPath, false);
7002
+ return rx.renderIt(newStack, this, "", this.evalViewName(stack), base);
6942
7003
  }
7004
+ // A `*name` target contributes no step: the site recorded the absolute base it
7005
+ // resumed at, and event reconstruction turns that into a continuation frame.
6943
7006
  toPathStep(ctx) {
6944
- if (this.val instanceof DynVal) return dynRenderStep(ctx.comp, this.val.name);
7007
+ if (this.val instanceof DynVal) return null;
6945
7008
  return super.toPathStep(ctx);
6946
7009
  }
6947
7010
  };
6948
7011
  var RenderItNode = class extends RenderViewId {
6949
7012
  render(stack, rx) {
6950
- const newStack = stack.enter(stack.it, {}, true);
6951
- return rx.renderIt(newStack, this, "", this.evalViewName(stack));
7013
+ const base = stack.pendingFrame ? stack.renderPath.toTransactionPath() : null;
7014
+ const newStack = stack.enter(stack.it, {}, true, stack.renderPath, false);
7015
+ return rx.renderIt(newStack, this, "", this.evalViewName(stack), base);
6952
7016
  }
6953
7017
  toPathStep(ctx) {
6954
7018
  const next = ctx.next();
6955
7019
  if (next === null) return null;
6956
7020
  const nextNode = next.resolveNode();
6957
7021
  if (nextNode instanceof EachNode && next.hasKey) {
6958
- if (nextNode.val instanceof DynVal)
6959
- return dynRenderStep(ctx.comp, nextNode.val.name, next.key);
7022
+ if (nextNode.val instanceof DynVal) return null;
6960
7023
  return new EachRenderItStep(nextNode.val.name, next.key);
6961
7024
  }
6962
7025
  return null;
@@ -7058,11 +7121,19 @@ var EachNode = class extends WrapperNode {
7058
7121
  this.iterInfo = new IterInfo(val, null, null, null);
7059
7122
  }
7060
7123
  render(stack, rx) {
7061
- return rx.renderEachWhen(stack, this.iterInfo, this.node, this.nodeId);
7124
+ return rx.renderEachWhen(stack, this);
7062
7125
  }
7063
7126
  toPathStep(ctx) {
7064
7127
  return ctx.hasKey ? new EachBindStep(this.iterInfo, ctx.key) : null;
7065
7128
  }
7129
+ // Where one item lives, for the render path. `@each` re-binds `it` to the item
7130
+ // whether or not the body is a component, so the position moves either way and
7131
+ // the step has to address it — `.rows` iterated at `key` IS `rows[key]`.
7132
+ // Null for a dynamic sequence: `*rows` carries its own absolute path and enters
7133
+ // a continuation frame instead (see Renderer.renderEachWhen).
7134
+ itemStep(key) {
7135
+ return this.val instanceof FieldVal ? new SeqStep(this.val.name, key) : null;
7136
+ }
7066
7137
  static register = true;
7067
7138
  };
7068
7139
  var IterInfo = class {
@@ -7401,6 +7472,215 @@ function collectAppClassesInSet(app) {
7401
7472
  return classes;
7402
7473
  }
7403
7474
 
7475
+ // src/stack.js
7476
+ var STOP = /* @__PURE__ */ Symbol("STOP");
7477
+ var NEXT = /* @__PURE__ */ Symbol("NEXT");
7478
+ var DEFAULT_ROUTE = ["dyn", "lex"];
7479
+ function routeLookup(route, lex, dyn) {
7480
+ for (let i = 0; i < route.length; i++) {
7481
+ const leg = route[i];
7482
+ if (leg === "dyn") {
7483
+ const v = dyn();
7484
+ if (v != null) return v;
7485
+ } else if (leg === "lex") {
7486
+ const v = lex();
7487
+ if (v != null) return v;
7488
+ } else {
7489
+ console.warn("unknown lookup route leg", leg, '- expected "dyn" or "lex"');
7490
+ }
7491
+ }
7492
+ return null;
7493
+ }
7494
+ var isTypeName = (s) => {
7495
+ const c = s.charCodeAt(0);
7496
+ return c >= 65 && c <= 90;
7497
+ };
7498
+ function lookup(chain, name, dv = null) {
7499
+ let n = chain;
7500
+ while (n !== null) {
7501
+ const r = n[0].lookup(name);
7502
+ if (r === STOP) return dv;
7503
+ if (r !== NEXT) return r;
7504
+ n = n[1];
7505
+ }
7506
+ return dv;
7507
+ }
7508
+ var BindFrame = class {
7509
+ constructor(it, binds, isFrame) {
7510
+ this.it = it;
7511
+ this.binds = binds;
7512
+ this.isFrame = isFrame;
7513
+ }
7514
+ lookup(name) {
7515
+ const v = this.binds[name];
7516
+ return v === void 0 ? this.isFrame ? STOP : NEXT : v;
7517
+ }
7518
+ };
7519
+ var DynFrame = class {
7520
+ constructor(binds, types) {
7521
+ this.binds = binds;
7522
+ this.types = types;
7523
+ }
7524
+ lookup(name) {
7525
+ const v = (isTypeName(name) ? this.types : this.binds)[name];
7526
+ return v === void 0 ? NEXT : v;
7527
+ }
7528
+ };
7529
+ function computeViewsId(views) {
7530
+ let s = "";
7531
+ let n = views;
7532
+ while (n !== null) {
7533
+ s += n[0];
7534
+ n = n[1];
7535
+ }
7536
+ return s === "main" ? "" : s;
7537
+ }
7538
+ var Stack = class _Stack {
7539
+ constructor(fields) {
7540
+ Object.assign(this, fields);
7541
+ }
7542
+ _with(patch) {
7543
+ return new _Stack({ ...this, ...patch });
7544
+ }
7545
+ // Evaluate every provide the entered component publishes and push them as one
7546
+ // dynBinds frame, keyed by NAME. A value is published together with the absolute
7547
+ // path it lives at: the same declaration is read as `*name` AND resumed at by
7548
+ // `<x render="*name">`, so a consumer needs both halves. Types go in the same
7549
+ // frame's other map. No-op with no provides.
7550
+ _pushProvides() {
7551
+ const comp = this.comps.getCompFor(this.it);
7552
+ if (comp == null) return this;
7553
+ const { provide, provideType } = comp;
7554
+ const binds = {};
7555
+ const types = {};
7556
+ let has2 = false;
7557
+ const base = this._publishBase();
7558
+ for (const k in provide) {
7559
+ const step = provide[k].val.toPathItem?.() ?? null;
7560
+ if (step === null) continue;
7561
+ const value = provide[k].val.eval(this);
7562
+ binds[k] = { value, path: base === null ? null : base.concat([step]) };
7563
+ has2 = true;
7564
+ }
7565
+ for (const k in provideType) {
7566
+ types[k] = provideType[k];
7567
+ has2 = true;
7568
+ }
7569
+ if (!has2) return this;
7570
+ return this._with({ dynBinds: [new DynFrame(binds, types), this.dynBinds] });
7571
+ }
7572
+ // The absolute address of the component being entered, or null when this
7573
+ // position cannot be written down as one. Frame-only steps carry bindings and
7574
+ // address nothing, so they are compacted away first; what is left is checked
7575
+ // against the value actually being rendered, because a scope CAN move the
7576
+ // render position without contributing an addressing step (a plain `@each`
7577
+ // body re-binds `it` to the item while its rebuild step is an identity).
7578
+ //
7579
+ // A null base still publishes the VALUE — `*name` reads it fine — but there is
7580
+ // nowhere to resume, so `<x render="*name">` renders nothing rather than
7581
+ // editing whatever happens to live at the address we guessed.
7582
+ _publishBase() {
7583
+ const base = this.renderPath.toTransactionPath().compact();
7584
+ return base.lookup(this.root, NOT_FOUND) === this.it ? base : null;
7585
+ }
7586
+ static root(comps, it, ctx = null) {
7587
+ return new _Stack({
7588
+ comps,
7589
+ root: it,
7590
+ it,
7591
+ binds: [new BindFrame(it, {}, true), null],
7592
+ dynBinds: [new DynFrame({}, {}), null],
7593
+ views: ["main", null],
7594
+ viewsId: "",
7595
+ renderPath: new DispatchPath(),
7596
+ pendingFrame: false,
7597
+ ctx
7598
+ })._pushProvides();
7599
+ }
7600
+ // `renderPath` defaults to this stack's own: an ordinary scope does not move.
7601
+ // `pendingFrame` clears on a component frame (which emits the base) and is
7602
+ // inherited by transparent scopes, which have to carry it to the next boundary.
7603
+ enter(it, bindings = {}, isFrame = true, renderPath = this.renderPath, pendingFrame = null) {
7604
+ const stack = this._with({
7605
+ it,
7606
+ binds: [new BindFrame(it, bindings, isFrame), this.binds],
7607
+ renderPath,
7608
+ pendingFrame: pendingFrame ?? (isFrame ? false : this.pendingFrame)
7609
+ });
7610
+ return isFrame ? stack._pushProvides() : stack;
7611
+ }
7612
+ pushViewName(name) {
7613
+ const views = [name, this.views];
7614
+ return this._with({ views, viewsId: computeViewsId(views) });
7615
+ }
7616
+ // Published types are stable per scope and would only churn the render cache, so
7617
+ // the cache key covers values alone.
7618
+ _pushDynBindValuesToArray(arr, comp) {
7619
+ for (const k in comp.provide) arr.push(this.lookupDynamic(k));
7620
+ for (const k in comp.lookup) arr.push(this.lookupDynamic(k));
7621
+ }
7622
+ // `*name`: the nearest binding above (including this component's own provides,
7623
+ // pushed on entering it), else a path registered in the component's lexical
7624
+ // scope, else this component's declared default, else null.
7625
+ //
7626
+ // One chain walk and no producer resolution: a lookup names what it WANTS, so the
7627
+ // frame it wants is keyed by that name. The default belongs to the CONSUMER's
7628
+ // declaration and is evaluated against the consumer's stack, which is why it is
7629
+ // consulted only after the whole chain has missed.
7630
+ lookupDynamicLocated(name) {
7631
+ if (isTypeName(name)) return null;
7632
+ const v = lookup(this.dynBinds, name);
7633
+ if (v != null) return v;
7634
+ const comp = this.comps.getCompFor(this.it);
7635
+ if (comp == null) return null;
7636
+ const path2 = comp.scope?.lookupPath?.(name) ?? null;
7637
+ if (path2 !== null) {
7638
+ const value2 = path2.lookup(this.root, NOT_FOUND);
7639
+ if (value2 !== NOT_FOUND) return { value: value2, path: path2 };
7640
+ }
7641
+ const dval = comp.lookup[name]?.val ?? null;
7642
+ if (dval === null) return null;
7643
+ const step = dval.toPathItem?.() ?? null;
7644
+ const value = dval.eval(this);
7645
+ return step === null ? { value, path: null } : { value, path: this.renderPath.toTransactionPath().concat([step]) };
7646
+ }
7647
+ lookupDynamic(name) {
7648
+ if (isTypeName(name)) return lookup(this.dynBinds, name);
7649
+ return this.lookupDynamicLocated(name)?.value ?? null;
7650
+ }
7651
+ lookupBind(name) {
7652
+ return lookup(this.binds, name);
7653
+ }
7654
+ lookupFieldRaw(name) {
7655
+ return this.it[name] ?? null;
7656
+ }
7657
+ lookupMethod(name) {
7658
+ const fn = this.it[name];
7659
+ return fn instanceof Function ? fn.call(this.it) : null;
7660
+ }
7661
+ // The dispatched DOM event / drag info, read only by EventMemberVal's
7662
+ // `e.<member>` handler args. Null outside a live event transaction.
7663
+ lookupEvent() {
7664
+ return this.ctx?.event ?? null;
7665
+ }
7666
+ lookupDragInfo() {
7667
+ return this.ctx?.dragInfo ?? null;
7668
+ }
7669
+ getHandlerFor(name, key) {
7670
+ return this.comps.getHandlerFor(this.it, name, key);
7671
+ }
7672
+ lookupBestView(views, defaultViewName) {
7673
+ let n = this.views;
7674
+ while (n !== null) {
7675
+ const view = views[n[0]];
7676
+ if (view !== void 0) return view;
7677
+ n = n[1];
7678
+ }
7679
+ return views[defaultViewName];
7680
+ }
7681
+ };
7682
+ var NOT_FOUND = /* @__PURE__ */ Symbol("NOT_FOUND");
7683
+
7404
7684
  // src/components.js
7405
7685
  var COMPONENT = /* @__PURE__ */ Symbol.for("tutuca.component");
7406
7686
  var Components = class {
@@ -7439,12 +7719,14 @@ var ComponentStack = class _ComponentStack {
7439
7719
  this.byName = {};
7440
7720
  this.intentsByName = {};
7441
7721
  this.macros = {};
7722
+ this.paths = {};
7442
7723
  }
7443
7724
  enter() {
7444
7725
  return new _ComponentStack(this.comps, this);
7445
7726
  }
7446
7727
  registerComponents(comps, opts) {
7447
- const { aliases: aliases2 = {} } = opts ?? {};
7728
+ const { aliases: aliases2 = {}, paths } = opts ?? {};
7729
+ if (paths) this.registerPaths(paths);
7448
7730
  for (let i = 0; i < comps.length; i++) {
7449
7731
  const Comp = comps[i];
7450
7732
  Comp[COMPONENT].scope = this.enter();
@@ -7458,6 +7740,27 @@ var ComponentStack = class _ComponentStack {
7458
7740
  else console.warn("alias", alias, "to inexistent component", aliases2[alias]);
7459
7741
  }
7460
7742
  }
7743
+ // Register lowercase names as absolute paths from the app state root. A
7744
+ // descendant that declares one in its `lookup` reads and renders `*name` without
7745
+ // anything above it publishing one — which is what makes a session, a theme or a
7746
+ // host-owned value available in its natural registration scope, instead of forcing
7747
+ // an application root whose only job is to `provide` it. Register on a nested
7748
+ // scope to narrow a name; nearest registration wins.
7749
+ //
7750
+ // Uppercase names are ignored: a component TYPE is what `lookupComponent` already
7751
+ // answers, and a type has no path.
7752
+ registerPaths(paths) {
7753
+ for (const name in paths) {
7754
+ if (isTypeName(name)) {
7755
+ console.warn("registerPaths: a type name has no path", name);
7756
+ continue;
7757
+ }
7758
+ this.paths[name] = paths[name].toPath?.() ?? paths[name];
7759
+ }
7760
+ }
7761
+ lookupPath(name) {
7762
+ return this.paths[name] ?? this.parent?.lookupPath(name) ?? null;
7763
+ }
7461
7764
  registerMacros(macros) {
7462
7765
  for (const key in macros) {
7463
7766
  const lower = key.toLowerCase();
@@ -7489,17 +7792,16 @@ var ComponentStack = class _ComponentStack {
7489
7792
  lookupComponent(name) {
7490
7793
  return this.byName[name] ?? this.parent?.lookupComponent(name) ?? null;
7491
7794
  }
7492
- // The component in this scope chain that provides `name`, innermost first. A lookup
7493
- // names a value without naming its producer, so the render-target teleport
7494
- // (resolveDynProducer) recovers the producer here instead. Sound because
7495
- // PROVIDE_NAME_COLLISION keeps a provide name to one producer per chain; with two,
7496
- // this returns the innermost and the linter has already reported the ambiguity.
7497
- lookupProvider(name) {
7795
+ // Whether anything in this scope chain provides `name`. Existence only: a lookup
7796
+ // names what it WANTS and takes whoever is nearest above it at render time, so
7797
+ // there is no producer to identify — several components may publish one name and
7798
+ // the live render ancestry decides. Used by the linter to tell a lookup that can
7799
+ // be satisfied from one that never will be.
7800
+ hasProvider(name) {
7498
7801
  for (const compName in this.byName) {
7499
- const Comp = this.byName[compName];
7500
- if (Comp.provide?.[name] !== void 0) return Comp;
7802
+ if (this.byName[compName].provide?.[name] !== void 0) return true;
7501
7803
  }
7502
- return this.parent?.lookupProvider(name) ?? null;
7804
+ return this.parent?.hasProvider(name) ?? false;
7503
7805
  }
7504
7806
  lookupMacro(name) {
7505
7807
  return this.macros[name] ?? this.parent?.lookupMacro(name) ?? null;
@@ -7516,10 +7818,6 @@ var LookupInfo = class {
7516
7818
  }
7517
7819
  };
7518
7820
  var isString = (v) => typeof v === "string";
7519
- var isTypeName = (s) => {
7520
- const c = s.charCodeAt(0);
7521
- return c >= 65 && c <= 90;
7522
- };
7523
7821
  var _rawSpecKeys = "name view style commonStyle globalStyle receive intent alter views provide lookup fields methods statics";
7524
7822
  var KNOWN_SPEC_KEYS = new Set(_rawSpecKeys.split(" "));
7525
7823
  var _compId = 0;
@@ -9883,7 +10181,6 @@ var DYN_VAL_NOT_DEFINED = "DYN_VAL_NOT_DEFINED";
9883
10181
  var DYN_ALIAS_NOT_REFERENCED = "DYN_ALIAS_NOT_REFERENCED";
9884
10182
  var PROVIDE_NOT_ADDRESSABLE = "PROVIDE_NOT_ADDRESSABLE";
9885
10183
  var PROVIDE_TYPE_BAD_SHAPE = "PROVIDE_TYPE_BAD_SHAPE";
9886
- var PROVIDE_NAME_COLLISION = "PROVIDE_NAME_COLLISION";
9887
10184
  var LOOKUP_BAD_SHAPE = "LOOKUP_BAD_SHAPE";
9888
10185
  var LOOKUP_NO_PROVIDER = "LOOKUP_NO_PROVIDER";
9889
10186
  var RENDER_IT_OUTSIDE_OF_LOOP = "RENDER_IT_OUTSIDE_OF_LOOP";
@@ -10006,7 +10303,6 @@ function checkComponent(Comp, lx = new LintContext(), { wellKnownExtras = EMPTY_
10006
10303
  checkFieldMethodNameCollisions(lx, Comp);
10007
10304
  checkProvidesAreAddressable(lx, Comp);
10008
10305
  checkProvidedTypes(lx, Comp);
10009
- checkProvideNameCollisions(lx, Comp);
10010
10306
  checkLookupShapes(lx, Comp);
10011
10307
  checkLookupTypesResolve(lx, Comp);
10012
10308
  checkLookupsHaveProviders(lx, Comp);
@@ -10690,19 +10986,6 @@ function checkProvidedTypes(lx, Comp) {
10690
10986
  if (raw !== "self") lx.error(PROVIDE_TYPE_BAD_SHAPE, { name, value: raw });
10691
10987
  }
10692
10988
  }
10693
- function checkProvideNameCollisions(lx, Comp) {
10694
- const scope = Comp.scope;
10695
- if (!scope) return;
10696
- for (const name in Comp.provide) {
10697
- for (let s = scope; s; s = s.parent) {
10698
- for (const otherName in s.byName) {
10699
- const Other = s.byName[otherName];
10700
- if (Other !== Comp && Other.provide?.[name] !== void 0)
10701
- lx.error(PROVIDE_NAME_COLLISION, { name, other: Other.name });
10702
- }
10703
- }
10704
- }
10705
- }
10706
10989
  var KNOWN_LOOKUP_KEYS = /* @__PURE__ */ new Set(["name", "default"]);
10707
10990
  function checkLookupShapes(lx, Comp) {
10708
10991
  const raw = Comp._rawLookup;
@@ -10744,7 +11027,7 @@ function checkLookupsHaveProviders(lx, Comp) {
10744
11027
  if (!scope) return;
10745
11028
  for (const name in Comp.lookup) {
10746
11029
  if (isTypeName2(name)) continue;
10747
- if (scope.lookupProvider?.(name)) continue;
11030
+ if (scope.hasProvider?.(name) || scope.lookupPath?.(name)) continue;
10748
11031
  const info = { name, hasDefault: Comp.lookup[name].val != null };
10749
11032
  if (info.hasDefault) lx.hint(LOOKUP_NO_PROVIDER, info);
10750
11033
  else lx.error(LOOKUP_NO_PROVIDER, info);
@@ -10866,9 +11149,22 @@ var CHECK_TYPE_LIST = Array.isArray;
10866
11149
  var CHECK_TYPE_OBJECT = isPlainObject;
10867
11150
  var CHECK_TYPE_MAP = (v) => v instanceof Map;
10868
11151
  var CHECK_TYPE_SET = (v) => v instanceof Set;
11152
+ var COERCE_NONE = (_v) => null;
11153
+ var COERCE_BOOL = (v) => !!v;
11154
+ var COERCE_STRING = (v) => v?.toString?.() ?? "";
11155
+ var COERCE_INT = (v) => Number.isFinite(v) ? Math.trunc(v) : null;
11156
+ var COERCE_LIST = (v) => Array.isArray(v) ? [...v] : null;
11157
+ var COERCE_OBJECT = (v) => isPlainObject(v) ? { ...v } : null;
11158
+ var COERCE_MAP = (v) => {
11159
+ if (v instanceof Map) return new Map(v);
11160
+ if (Array.isArray(v) || isPlainObject(v))
11161
+ return new Map(Array.isArray(v) ? v : Object.entries(v));
11162
+ return null;
11163
+ };
11164
+ var COERCE_SET = (v) => v instanceof Set || Array.isArray(v) ? new Set(v) : null;
10869
11165
  var FieldBool = class extends Field {
10870
11166
  constructor(name, defaultValue = false) {
10871
- super("bool", name, CHECK_TYPE_BOOL, (v) => !!v, defaultValue);
11167
+ super("bool", name, CHECK_TYPE_BOOL, COERCE_BOOL, defaultValue);
10872
11168
  }
10873
11169
  };
10874
11170
  var FieldAny = class extends Field {
@@ -10878,23 +11174,17 @@ var FieldAny = class extends Field {
10878
11174
  };
10879
11175
  var FieldString = class extends Field {
10880
11176
  constructor(name, defaultValue = "") {
10881
- super("text", name, CHECK_TYPE_STRING, (v) => v?.toString?.() ?? "", defaultValue);
11177
+ super("text", name, CHECK_TYPE_STRING, COERCE_STRING, defaultValue);
10882
11178
  }
10883
11179
  };
10884
11180
  var FieldInt = class extends Field {
10885
11181
  constructor(name, defaultValue = 0) {
10886
- super(
10887
- "int",
10888
- name,
10889
- CHECK_TYPE_INT,
10890
- (v) => Number.isFinite(v) ? Math.trunc(v) : null,
10891
- defaultValue
10892
- );
11182
+ super("int", name, CHECK_TYPE_INT, COERCE_INT, defaultValue);
10893
11183
  }
10894
11184
  };
10895
11185
  var FieldFloat = class extends Field {
10896
11186
  constructor(name, defaultValue = 0) {
10897
- super("float", name, CHECK_TYPE_FLOAT, (_) => null, defaultValue);
11187
+ super("float", name, CHECK_TYPE_FLOAT, COERCE_NONE, defaultValue);
10898
11188
  }
10899
11189
  };
10900
11190
  var metaOf = (v) => v?.constructor?.[COMPONENT] ?? v?.constructor?.getMetaClass?.();
@@ -10907,45 +11197,22 @@ var FieldComp = class extends Field {
10907
11197
  };
10908
11198
  var FieldList = class extends Field {
10909
11199
  constructor(name, defaultValue = []) {
10910
- super("list", name, CHECK_TYPE_LIST, (v) => Array.isArray(v) ? [...v] : null, defaultValue);
11200
+ super("list", name, CHECK_TYPE_LIST, COERCE_LIST, defaultValue);
10911
11201
  }
10912
11202
  };
10913
11203
  var FieldObject = class extends Field {
10914
11204
  constructor(name, defaultValue = {}) {
10915
- super(
10916
- "object",
10917
- name,
10918
- CHECK_TYPE_OBJECT,
10919
- (v) => isPlainObject(v) ? { ...v } : null,
10920
- defaultValue
10921
- );
11205
+ super("object", name, CHECK_TYPE_OBJECT, COERCE_OBJECT, defaultValue);
10922
11206
  }
10923
11207
  };
10924
11208
  var FieldMap = class extends Field {
10925
11209
  constructor(name, defaultValue = /* @__PURE__ */ new Map()) {
10926
- super(
10927
- "map",
10928
- name,
10929
- CHECK_TYPE_MAP,
10930
- (v) => {
10931
- if (v instanceof Map) return new Map(v);
10932
- if (Array.isArray(v) || isPlainObject(v))
10933
- return new Map(Array.isArray(v) ? v : Object.entries(v));
10934
- return null;
10935
- },
10936
- defaultValue
10937
- );
11210
+ super("map", name, CHECK_TYPE_MAP, COERCE_MAP, defaultValue);
10938
11211
  }
10939
11212
  };
10940
11213
  var FieldSet = class extends Field {
10941
11214
  constructor(name, defaultValue = /* @__PURE__ */ new Set()) {
10942
- super(
10943
- "set",
10944
- name,
10945
- CHECK_TYPE_SET,
10946
- (v) => v instanceof Set || Array.isArray(v) ? new Set(v) : null,
10947
- defaultValue
10948
- );
11215
+ super("set", name, CHECK_TYPE_SET, COERCE_SET, defaultValue);
10949
11216
  }
10950
11217
  };
10951
11218
  function mkCompField(field, scope, args) {
@@ -11043,8 +11310,7 @@ function classFromData(name, { fields = {}, methods, statics }) {
11043
11310
  const value = fields[field];
11044
11311
  const type3 = typeof value;
11045
11312
  if (type3 === "string") b.addField(field, value, FieldString);
11046
- else if (type3 === "number")
11047
- b.addField(field, value, Number.isInteger(value) ? FieldInt : FieldFloat);
11313
+ else if (type3 === "number") b.addField(field, value, FieldFloat);
11048
11314
  else if (type3 === "boolean") b.addField(field, value, FieldBool);
11049
11315
  else if (Array.isArray(value)) b.addField(field, [...value], FieldList);
11050
11316
  else if (value instanceof Set) b.addField(field, new Set(value), FieldSet);
@@ -11121,160 +11387,6 @@ Component.fromSpec = (opts) => {
11121
11387
  };
11122
11388
  var component = (opts) => Component.fromSpec(opts);
11123
11389
 
11124
- // src/stack.js
11125
- var STOP = /* @__PURE__ */ Symbol("STOP");
11126
- var NEXT = /* @__PURE__ */ Symbol("NEXT");
11127
- var DEFAULT_ROUTE = ["dyn", "lex"];
11128
- function routeLookup(route, lex, dyn) {
11129
- for (let i = 0; i < route.length; i++) {
11130
- const leg = route[i];
11131
- if (leg === "dyn") {
11132
- const v = dyn();
11133
- if (v != null) return v;
11134
- } else if (leg === "lex") {
11135
- const v = lex();
11136
- if (v != null) return v;
11137
- } else {
11138
- console.warn("unknown lookup route leg", leg, '- expected "dyn" or "lex"');
11139
- }
11140
- }
11141
- return null;
11142
- }
11143
- function lookup(chain, name, dv = null) {
11144
- let n = chain;
11145
- while (n !== null) {
11146
- const r = n[0].lookup(name);
11147
- if (r === STOP) return dv;
11148
- if (r !== NEXT) return r;
11149
- n = n[1];
11150
- }
11151
- return dv;
11152
- }
11153
- var BindFrame = class {
11154
- constructor(it, binds, isFrame) {
11155
- this.it = it;
11156
- this.binds = binds;
11157
- this.isFrame = isFrame;
11158
- }
11159
- lookup(name) {
11160
- const v = this.binds[name];
11161
- return v === void 0 ? this.isFrame ? STOP : NEXT : v;
11162
- }
11163
- };
11164
- var ObjectFrame = class {
11165
- constructor(binds) {
11166
- this.binds = binds;
11167
- }
11168
- lookup(key) {
11169
- const v = this.binds[key];
11170
- return v === void 0 ? NEXT : v;
11171
- }
11172
- };
11173
- function computeViewsId(views) {
11174
- let s = "";
11175
- let n = views;
11176
- while (n !== null) {
11177
- s += n[0];
11178
- n = n[1];
11179
- }
11180
- return s === "main" ? "" : s;
11181
- }
11182
- var Stack = class _Stack {
11183
- constructor(comps, it, binds, dynBinds, views, viewsId, ctx = null) {
11184
- this.comps = comps;
11185
- this.it = it;
11186
- this.binds = binds;
11187
- this.dynBinds = dynBinds;
11188
- this.views = views;
11189
- this.viewsId = viewsId;
11190
- this.ctx = ctx;
11191
- }
11192
- // Evaluate every provide the entered component publishes and push them as one
11193
- // dynBinds frame, keyed by NAME. Published types go in the same frame: a type name
11194
- // starts A-Z and a value name does not, so the two namespaces cannot collide and
11195
- // nearest-ancestor-wins falls out of frame order for both. No-op with no provides.
11196
- _pushProvides() {
11197
- const comp = this.comps.getCompFor(this.it);
11198
- if (comp == null) return this;
11199
- const { provide, provideType } = comp;
11200
- const dynObj = {};
11201
- let has2 = false;
11202
- for (const k in provide) {
11203
- dynObj[k] = provide[k].val.eval(this);
11204
- has2 = true;
11205
- }
11206
- for (const k in provideType) {
11207
- dynObj[k] = provideType[k];
11208
- has2 = true;
11209
- }
11210
- if (!has2) return this;
11211
- const newDynBinds = [new ObjectFrame(dynObj), this.dynBinds];
11212
- const { comps, it, binds, views, viewsId, ctx } = this;
11213
- return new _Stack(comps, it, binds, newDynBinds, views, viewsId, ctx);
11214
- }
11215
- static root(comps, it, ctx) {
11216
- const binds = [new BindFrame(it, {}, true), null];
11217
- const dynBinds = [new ObjectFrame({}), null];
11218
- const views = ["main", null];
11219
- return new _Stack(comps, it, binds, dynBinds, views, "", ctx)._pushProvides();
11220
- }
11221
- enter(it, bindings = {}, isFrame = true) {
11222
- const { comps, binds, dynBinds, views, viewsId, ctx } = this;
11223
- const newBinds = [new BindFrame(it, bindings, isFrame), binds];
11224
- const stack = new _Stack(comps, it, newBinds, dynBinds, views, viewsId, ctx);
11225
- return isFrame ? stack._pushProvides() : stack;
11226
- }
11227
- pushViewName(name) {
11228
- const { comps, it, binds, dynBinds, views, ctx } = this;
11229
- const newViews = [name, views];
11230
- return new _Stack(comps, it, binds, dynBinds, newViews, computeViewsId(newViews), ctx);
11231
- }
11232
- // Published types are stable per scope and would only churn the render cache, so
11233
- // the cache key covers values alone.
11234
- _pushDynBindValuesToArray(arr, comp) {
11235
- for (const k in comp.provide) arr.push(this.lookupDynamic(k));
11236
- for (const k in comp.lookup) arr.push(this.lookupDynamic(k));
11237
- }
11238
- // `*name`: the nearest binding above (including this component's own provides,
11239
- // pushed on entering it), else this component's declared default, else null.
11240
- lookupDynamic(name) {
11241
- const v = lookup(this.dynBinds, name);
11242
- if (v != null) return v;
11243
- const comp = this.comps.getCompFor(this.it);
11244
- return comp?.lookup[name]?.val?.eval(this) ?? null;
11245
- }
11246
- lookupBind(name) {
11247
- return lookup(this.binds, name);
11248
- }
11249
- lookupFieldRaw(name) {
11250
- return this.it[name] ?? null;
11251
- }
11252
- lookupMethod(name) {
11253
- const fn = this.it[name];
11254
- return fn instanceof Function ? fn.call(this.it) : null;
11255
- }
11256
- // The dispatched DOM event / drag info, read only by EventMemberVal's
11257
- // `e.<member>` handler args. Null outside a live event transaction.
11258
- lookupEvent() {
11259
- return this.ctx?.event ?? null;
11260
- }
11261
- lookupDragInfo() {
11262
- return this.ctx?.dragInfo ?? null;
11263
- }
11264
- getHandlerFor(name, key) {
11265
- return this.comps.getHandlerFor(this.it, name, key);
11266
- }
11267
- lookupBestView(views, defaultViewName) {
11268
- let n = this.views;
11269
- while (n !== null) {
11270
- const view = views[n[0]];
11271
- if (view !== void 0) return view;
11272
- n = n[1];
11273
- }
11274
- return views[defaultViewName];
11275
- }
11276
- };
11277
-
11278
11390
  // src/transactor.js
11279
11391
  var State2 = class {
11280
11392
  constructor(val) {
@@ -11350,9 +11462,9 @@ var Transactor = class {
11350
11462
  // `.a[.selId]` render target reconstructed from a DOM event) against the root the
11351
11463
  // handler read, so pathKeys carries concrete keys instead of dropping the dynamic
11352
11464
  // step. No-op when nobody is observing.
11353
- _emitRecord(root, { kind, name, args, path, targetPath, handler, handlerName, matched, before, after, parent }) {
11465
+ _emitRecord(root, { kind, name, args, path: path2, targetPath, handler, handlerName, matched, before, after, parent }) {
11354
11466
  if (this._observers.length === 0) return;
11355
- const pinned = path.pinKeys(root);
11467
+ const pinned = path2.pinKeys(root);
11356
11468
  this._emit({
11357
11469
  kind,
11358
11470
  name,
@@ -11403,18 +11515,20 @@ var Transactor = class {
11403
11515
  // intent's answerPath is: a reply must reach the sender that asked even if a key
11404
11516
  // moved while the message was in flight. Null when nobody is waiting — a host
11405
11517
  // sendAtRoot or a view's own `@on.*` — and ctx.sendReply refuses on that.
11406
- pushSend(path, name, args = [], parent = null, origin = null) {
11407
- const t = new SendEvent(path, this, name, args, parent);
11408
- t.origin = origin === null ? null : origin.toTransactionPath().pinKeys(this.state.val);
11518
+ pushSend(path2, name, args = [], parent = null, origin = null, txnPath = null) {
11519
+ const t = new SendEvent(path2, this, name, args, parent);
11520
+ t.txnPath = txnPath;
11521
+ t.origin = origin;
11522
+ t.originPinned = origin === null ? null : origin.toTransactionPath().pinKeys(this.state.val);
11409
11523
  this.pushTransaction(t);
11410
11524
  return this._link(t, parent);
11411
11525
  }
11412
11526
  // Raise an intent: a job the sender did not address, walked along a route until
11413
11527
  // something answers. `opts.route` is a list of legs (see DEFAULT_ROUTE) and
11414
11528
  // `opts.livePath` opts out of pinning the answer's destination keys.
11415
- pushIntent(path, name, args = [], opts = {}, parent = null) {
11529
+ pushIntent(path2, name, args = [], opts = {}, parent = null) {
11416
11530
  const release = parent ? parent.completion.track() : null;
11417
- const walk = new IntentWalk(this, path, name, args, opts, parent, release);
11531
+ const walk = new IntentWalk(this, path2, name, args, opts, parent, release);
11418
11532
  walk.advance();
11419
11533
  return walk;
11420
11534
  }
@@ -11448,16 +11562,17 @@ var Transactor = class {
11448
11562
  transaction._completion?.releaseSelf();
11449
11563
  }
11450
11564
  }
11451
- transactInputNow(path, event, eventHandler, dragInfo) {
11452
- this.transact(new InputEvent(path, event, eventHandler, this, dragInfo));
11565
+ transactInputNow(path2, event, eventHandler, dragInfo) {
11566
+ this.transact(new InputEvent(path2, event, eventHandler, this, dragInfo));
11453
11567
  }
11454
11568
  };
11455
11569
  function nullHandler() {
11456
11570
  return this;
11457
11571
  }
11458
11572
  var Transaction = class {
11459
- constructor(path, transactor, parentTransaction = null) {
11460
- this.path = path;
11573
+ constructor(path2, transactor, parentTransaction = null) {
11574
+ this.path = path2;
11575
+ this.txnPath = null;
11461
11576
  this.transactor = transactor;
11462
11577
  this.parentTransaction = parentTransaction;
11463
11578
  this._completion = null;
@@ -11506,9 +11621,11 @@ var Transaction = class {
11506
11621
  getHandlerAndArgs(_root, _instance, _comps) {
11507
11622
  return null;
11508
11623
  }
11509
- // The path used to apply the mutation. Teleports dynamic-var renders so it lands on
11510
- // the data's real location (the dispatch `this.path` keeps intermediates).
11624
+ // The path used to apply the mutation: the ACTIVE frame of the dispatch path, so
11625
+ // an event inside a `<x render="*name">` subtree updates the value where it
11626
+ // really lives (the dispatch `this.path` keeps the visual callers, for bubbling).
11511
11627
  getTransactionPath() {
11628
+ if (this.txnPath !== null) return this.txnPath;
11512
11629
  return this.path.toTransactionPath().compact();
11513
11630
  }
11514
11631
  run(curRoot, comps) {
@@ -11526,15 +11643,16 @@ var Transaction = class {
11526
11643
  }
11527
11644
  };
11528
11645
  var InputEvent = class extends Transaction {
11529
- constructor(path, e, handler, transactor, dragInfo) {
11530
- super(path, transactor);
11646
+ constructor(path2, e, handler, transactor, dragInfo) {
11647
+ super(path2, transactor);
11531
11648
  this.e = e;
11532
11649
  this.handler = handler;
11533
11650
  this.dragInfo = dragInfo;
11534
11651
  this._dispatchPath = null;
11535
11652
  }
11536
- // Frame steps removed, DynStep + one step per crossed component kept: bubbling
11537
- // it visits every component (including intermediates of a dynamic-var render).
11653
+ // Frame-only steps removed, one step per crossed component kept — inside every
11654
+ // continuation frame independently, so bubbling it visits every component and
11655
+ // then returns to the caller that wrote the `*name`.
11538
11656
  get dispatchPath() {
11539
11657
  this._dispatchPath ??= this.path.compact();
11540
11658
  return this._dispatchPath;
@@ -11569,11 +11687,11 @@ var InputEvent = class extends Transaction {
11569
11687
  this.transactor.pushIntent(this.dispatchPath, name, args, rest, this);
11570
11688
  }
11571
11689
  getHandlerAndArgs(root, _instance, comps) {
11572
- const stack = this.path.toTransactionPath().buildStack(Stack.root(comps, root, this));
11690
+ const stack = this.path.buildStack(Stack.root(comps, root, this));
11573
11691
  const [handler, args] = this.handler.getHandlerAndArgs(stack, this);
11574
11692
  this._handlerArgs = [...args];
11575
- const path = this.dispatchPath;
11576
- args.push(new EventContext(path, this.transactor, this));
11693
+ const path2 = this.dispatchPath;
11694
+ args.push(new EventContext(path2, this.transactor, this));
11577
11695
  return [handler, args];
11578
11696
  }
11579
11697
  // The dispatched DOM event, read only through `e.<member>` handler args
@@ -11584,11 +11702,11 @@ var InputEvent = class extends Transaction {
11584
11702
  }
11585
11703
  };
11586
11704
  var NameArgsTransaction = class extends Transaction {
11587
- constructor(path, transactor, name, args, parentTransaction) {
11588
- super(path, transactor, parentTransaction);
11705
+ constructor(path2, transactor, name, args, parentTransaction) {
11706
+ super(path2, transactor, parentTransaction);
11589
11707
  this.name = name;
11590
11708
  this.args = args;
11591
- this.targetPath = path;
11709
+ this.targetPath = path2;
11592
11710
  }
11593
11711
  handlerProp = null;
11594
11712
  // NameArgs verbs map their handler bucket straight to the observed kind:
@@ -11645,8 +11763,8 @@ var SendEvent = class extends NameArgsTransaction {
11645
11763
  };
11646
11764
  var IntentEvent = class extends NameArgsTransaction {
11647
11765
  handlerProp = "intent";
11648
- constructor(path, transactor, walk) {
11649
- super(path, transactor, walk.name, walk.args, walk.parent);
11766
+ constructor(path2, transactor, walk) {
11767
+ super(path2, transactor, walk.name, walk.args, walk.parent);
11650
11768
  this.walk = walk;
11651
11769
  this.targetPath = walk.origin;
11652
11770
  }
@@ -11673,17 +11791,17 @@ var PASS = /* @__PURE__ */ Symbol.for("tutuca.intent.pass");
11673
11791
  var REFUSAL_RING_CAP = 200;
11674
11792
  var INTENT_DEPTH = 64;
11675
11793
  var IntentWalk = class {
11676
- constructor(transactor, path, name, args, opts, parent, release) {
11794
+ constructor(transactor, path2, name, args, opts, parent, release) {
11677
11795
  this.transactor = transactor;
11678
11796
  this.name = name;
11679
11797
  this.args = args;
11680
11798
  this.route = opts?.route ?? DEFAULT_ROUTE;
11681
11799
  this.parent = parent;
11682
11800
  this.release = release;
11683
- this.origin = path;
11684
- this.answerPath = opts?.livePath ? null : path.toTransactionPath().pinKeys(transactor.state.val);
11801
+ this.origin = path2;
11802
+ this.answerPath = opts?.livePath ? null : path2.toTransactionPath().pinKeys(transactor.state.val);
11685
11803
  this.legIndex = 0;
11686
- this.dynAt = path;
11804
+ this.dynAt = path2;
11687
11805
  this.hops = 0;
11688
11806
  this.ended = false;
11689
11807
  }
@@ -11695,7 +11813,7 @@ var IntentWalk = class {
11695
11813
  while (this.legIndex < this.route.length) {
11696
11814
  const leg = this.route[this.legIndex];
11697
11815
  if (leg === "dyn") {
11698
- if (this.dynAt.steps.length === 0) {
11816
+ if (!this.dynAt.canPop()) {
11699
11817
  this.legIndex++;
11700
11818
  continue;
11701
11819
  }
@@ -11792,8 +11910,8 @@ var IntentWalk = class {
11792
11910
  if (this.ended) return;
11793
11911
  this.ended = true;
11794
11912
  if (name === null) return this.release?.();
11795
- const path = this.answerPath ?? this.origin;
11796
- const t = new SendEvent(path, this.transactor, name, args, this.parent);
11913
+ const t = new SendEvent(this.origin, this.transactor, name, args, this.parent);
11914
+ t.txnPath = this.answerPath;
11797
11915
  t._isAnswer = true;
11798
11916
  this.transactor.pushTransaction(t);
11799
11917
  if (this.release) t.completion.whenSubtreeSettled().then(this.release);
@@ -11859,8 +11977,8 @@ var Completion = class {
11859
11977
  }
11860
11978
  };
11861
11979
  var Dispatcher = class {
11862
- constructor(path, transactor, parentTransaction, root = transactor.state.val) {
11863
- this.path = path;
11980
+ constructor(path2, transactor, parentTransaction, root = transactor.state.val) {
11981
+ this.path = path2;
11864
11982
  this.transactor = transactor;
11865
11983
  this.parent = parentTransaction;
11866
11984
  this.root = root;
@@ -11888,7 +12006,9 @@ var Dispatcher = class {
11888
12006
  // replayed; provides are pushed on every component frame either way, so a provide
11889
12007
  // that reads a loop binding is the one case this cannot reproduce faithfully.
11890
12008
  _stack() {
11891
- this._stackMemo ??= this.path.toTransactionPath().buildStack(Stack.root(this.transactor.comps, this.root, this.parent));
12009
+ this._stackMemo ??= this.path.buildStack(
12010
+ Stack.root(this.transactor.comps, this.root, this.parent)
12011
+ );
11892
12012
  return this._stackMemo;
11893
12013
  }
11894
12014
  // Resolve a name the way the renderer would. `opts.route` takes the same legs in
@@ -11902,14 +12022,19 @@ var Dispatcher = class {
11902
12022
  );
11903
12023
  }
11904
12024
  // The `lex` leg without a Stack: the scope of the component whose handler is
11905
- // running, which is the leaf of this ctx's path.
12025
+ // running, which is the leaf of this ctx's path. A type name resolves to the
12026
+ // component registered under it; a value name to a path registered under it
12027
+ // (see ComponentStack.registerPaths), read against the current root.
11906
12028
  _lookupLex(name) {
11907
12029
  let Comp = null;
11908
12030
  this.walkPath((c) => {
11909
12031
  Comp = c;
11910
12032
  return false;
11911
12033
  });
11912
- return Comp?.scope?.lookupComponent(name) ?? null;
12034
+ const scope = Comp?.scope;
12035
+ if (scope == null) return null;
12036
+ if (isTypeName(name)) return scope.lookupComponent(name) ?? null;
12037
+ return scope.lookupPath(name)?.lookup(this.root) ?? null;
11913
12038
  }
11914
12039
  // A component lookup is a value lookup constrained to a component. The `lex` leg
11915
12040
  // can only ever answer with one; the `dyn` leg reads a binding an ancestor
@@ -11931,8 +12056,8 @@ var Dispatcher = class {
11931
12056
  send(name, args) {
11932
12057
  return this.sendAtPath(this.path, name, args);
11933
12058
  }
11934
- sendAtPath(path, name, args) {
11935
- return this.transactor.pushSend(path, name, args, this.parent, this.path);
12059
+ sendAtPath(path2, name, args) {
12060
+ return this.transactor.pushSend(path2, name, args, this.parent, this.path);
11936
12061
  }
11937
12062
  // An intent is ROUTED: it names a job and walks until something answers. The verb
11938
12063
  // does not decide which scope answers — `opts.route` does, written here at the call
@@ -11940,8 +12065,8 @@ var Dispatcher = class {
11940
12065
  intent(name, args, opts) {
11941
12066
  return this.intentAtPath(this.path, name, args, opts);
11942
12067
  }
11943
- intentAtPath(path, name, args, opts) {
11944
- return this.transactor.pushIntent(path, name, args, opts, this.parent);
12068
+ intentAtPath(path2, name, args, opts) {
12069
+ return this.transactor.pushIntent(path2, name, args, opts, this.parent);
11945
12070
  }
11946
12071
  };
11947
12072
  var EventContext = class extends Dispatcher {
@@ -11970,7 +12095,14 @@ var EventContext = class extends Dispatcher {
11970
12095
  this.transactor.refuse("NO_SENDER", { name });
11971
12096
  return null;
11972
12097
  }
11973
- return this.sendAtPath(origin, name, args);
12098
+ return this.transactor.pushSend(
12099
+ origin,
12100
+ name,
12101
+ args,
12102
+ this.parent,
12103
+ this.path,
12104
+ this.parent.originPinned
12105
+ );
11974
12106
  }
11975
12107
  // End the walk answering nothing — "served, and no answer".
11976
12108
  stop() {
@@ -12002,13 +12134,13 @@ var PathChanges = class extends PathBuilder {
12002
12134
  }
12003
12135
  };
12004
12136
  function rootDispatcher(transactor) {
12005
- return new Dispatcher(new Path([]), transactor, null);
12137
+ return new Dispatcher(new DispatchPath(), transactor, null);
12006
12138
  }
12007
12139
 
12008
12140
  // tools/core/results.js
12009
12141
  var ModuleInfo = class {
12010
- constructor({ path = null, present = /* @__PURE__ */ new Set(), counts = {}, warnings = [] }) {
12011
- this.path = path;
12142
+ constructor({ path: path2 = null, present = /* @__PURE__ */ new Set(), counts = {}, warnings = [] }) {
12143
+ this.path = path2;
12012
12144
  this.present = present;
12013
12145
  this.counts = counts;
12014
12146
  this.warnings = warnings;
@@ -12118,8 +12250,8 @@ var DescribeResult = class {
12118
12250
  }
12119
12251
  };
12120
12252
  var ModuleTestReport = class {
12121
- constructor({ path = null, suites = [], counts = { pass: 0, fail: 0, skip: 0, total: 0 } }) {
12122
- this.path = path;
12253
+ constructor({ path: path2 = null, suites = [], counts = { pass: 0, fail: 0, skip: 0, total: 0 } }) {
12254
+ this.path = path2;
12123
12255
  this.suites = suites;
12124
12256
  this.counts = counts;
12125
12257
  }
@@ -12162,8 +12294,8 @@ var Test = class {
12162
12294
  }
12163
12295
  };
12164
12296
  var ModuleTests = class {
12165
- constructor({ path = null, suites = [] } = {}) {
12166
- this.path = path;
12297
+ constructor({ path: path2 = null, suites = [] } = {}) {
12298
+ this.path = path2;
12167
12299
  this.suites = suites;
12168
12300
  }
12169
12301
  };
@@ -12185,8 +12317,8 @@ function titleFromArg(arg) {
12185
12317
  if (typeof arg === "function") return arg.name || "(anonymous)";
12186
12318
  return String(arg);
12187
12319
  }
12188
- function makeCollector({ path = null, components = [] } = {}) {
12189
- const moduleTests = new ModuleTests({ path, suites: [] });
12320
+ function makeCollector({ path: path2 = null, components = [] } = {}) {
12321
+ const moduleTests = new ModuleTests({ path: path2, suites: [] });
12190
12322
  const stack = [];
12191
12323
  function describe(...args) {
12192
12324
  let head;
@@ -12287,7 +12419,7 @@ async function driveStack(stack, value, phase, opts = {}) {
12287
12419
  val
12288
12420
  );
12289
12421
  });
12290
- dispatchPhase(rootDispatcher(transactor), new Path([]), phase, value);
12422
+ dispatchPhase(rootDispatcher(transactor), new DispatchPath(), phase, value);
12291
12423
  await transactor.settle();
12292
12424
  return transactor.state.val;
12293
12425
  }
@@ -12297,7 +12429,7 @@ async function drive(cfg, value, phase, opts = {}) {
12297
12429
  async function runTests({
12298
12430
  getTests,
12299
12431
  components = [],
12300
- path = null,
12432
+ path: path2 = null,
12301
12433
  expect: expect2,
12302
12434
  name = null,
12303
12435
  grep = null,
@@ -12308,13 +12440,13 @@ async function runTests({
12308
12440
  const counts = { pass: 0, fail: 0, skip: 0, total: 0 };
12309
12441
  if (typeof getTests !== "function") {
12310
12442
  return new TestReport({
12311
- modules: [new ModuleTestReport({ path, suites: [], counts })]
12443
+ modules: [new ModuleTestReport({ path: path2, suites: [], counts })]
12312
12444
  });
12313
12445
  }
12314
12446
  if (typeof expect2 !== "function") {
12315
12447
  throw new Error("runTests: expect must be provided (e.g. chai's expect)");
12316
12448
  }
12317
- const { describe, test: test3, moduleTests } = makeCollector({ path, components });
12449
+ const { describe, test: test3, moduleTests } = makeCollector({ path: path2, components });
12318
12450
  let _stack = null;
12319
12451
  const getStack = () => _stack ??= buildStack({ components, macros, intentHandlers });
12320
12452
  const driveLocal = (value, phase, opts = {}) => driveStack(getStack(), value, phase, opts);
@@ -12377,7 +12509,7 @@ async function runTests({
12377
12509
  if (r !== null) suiteResults.push(r);
12378
12510
  }
12379
12511
  return new TestReport({
12380
- modules: [new ModuleTestReport({ path, suites: suiteResults, counts })]
12512
+ modules: [new ModuleTestReport({ path: path2, suites: suiteResults, counts })]
12381
12513
  });
12382
12514
  }
12383
12515
 
@@ -12546,15 +12678,13 @@ function lintIdToMessage(id, info) {
12546
12678
  case "DYN_ALIAS_NOT_REFERENCED":
12547
12679
  return `Lookup '${info.name}' is defined but never used — remove it or reference it as '*${info.name}' in a view`;
12548
12680
  case "PROVIDE_NOT_ADDRESSABLE":
12549
- 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`;
12681
+ return `Provide '${info.name}' value '${info.value}' must be a field ('.f') or seq-access ('.s[.k]') — a provide doubles as the path '<x render="*${info.name}">' resumes at, so this one is dropped and '*${info.name}' resolves to nothing`;
12550
12682
  case "LOOKUP_BAD_SHAPE":
12551
12683
  return `Lookup '${info.name}' has an invalid shape: ${info.problem}`;
12552
12684
  case "LOOKUP_NO_PROVIDER":
12553
- 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`;
12685
+ return info.hasDefault ? `Lookup '${info.name}' is provided by no component in scope and matches no registered path, so it always resolves to its default` : `Lookup '${info.name}' is provided by no component in scope and matches no registered path — add a 'provide' for it, register a path under that name, or give this lookup a default`;
12554
12686
  case "PROVIDE_TYPE_BAD_SHAPE":
12555
12687
  return `Provide '${info.name}' starts uppercase, so it publishes a component type — its value must be 'self', not '${info.value}'`;
12556
- case "PROVIDE_NAME_COLLISION":
12557
- return `Provide '${info.name}' is also provided by '${info.other}' in the same scope — one name, one provider, so a lookup can find it`;
12558
12688
  case "UNKNOWN_MACRO_ARG":
12559
12689
  return `Argument '${info.name}' is not declared in macro '${info.macroName}'`;
12560
12690
  case "UNKNOWN_DIRECTIVE":
@@ -12720,7 +12850,7 @@ var App = class {
12720
12850
  const { type: type3 } = e;
12721
12851
  const isDrag = type3 === "dragover" || type3 === "dragstart" || type3 === "dragend" || type3 === "drop";
12722
12852
  const { rootNode: root, maxEventNodeDepth: maxDepth, comps, transactor } = this;
12723
- const [path, handlers] = Path.fromNodeAndEventName(
12853
+ const [path2, handlers] = DispatchPath.fromNodeAndEventName(
12724
12854
  e.target,
12725
12855
  type3,
12726
12856
  root,
@@ -12728,9 +12858,9 @@ var App = class {
12728
12858
  comps,
12729
12859
  !isDrag
12730
12860
  );
12731
- if (isDrag) this._handleDragEvent(e, type3, path);
12732
- if (path !== null && handlers !== null)
12733
- for (const handler of handlers) transactor.transactInputNow(path, e, handler, this.dragInfo);
12861
+ if (isDrag) this._handleDragEvent(e, type3, path2);
12862
+ if (path2 !== null && handlers !== null)
12863
+ for (const handler of handlers) transactor.transactInputNow(path2, e, handler, this.dragInfo);
12734
12864
  }
12735
12865
  _handleTouchEvent(e) {
12736
12866
  const { type: type3 } = e;
@@ -12773,7 +12903,7 @@ var App = class {
12773
12903
  this._touch = null;
12774
12904
  }
12775
12905
  }
12776
- _handleDragEvent(e, type3, path) {
12906
+ _handleDragEvent(e, type3, path2) {
12777
12907
  if (type3 === "dragover") {
12778
12908
  const dropTarget = getClosestDropTarget(e.target, this.rootNode, Infinity);
12779
12909
  if (dropTarget !== null) {
@@ -12785,10 +12915,10 @@ var App = class {
12785
12915
  } else if (type3 === "dragstart") {
12786
12916
  e.target.dataset.dragging = 1;
12787
12917
  const rootValue = this.state.val;
12788
- const txnPath = path.compact().toTransactionPath();
12918
+ const txnPath = path2.compact().toTransactionPath();
12789
12919
  const value = txnPath.lookup(rootValue);
12790
12920
  const dragType = e.target.dataset.dragtype ?? "?";
12791
- const stack = path.toTransactionPath().buildStack(this.makeStack(rootValue));
12921
+ const stack = path2.buildStack(this.makeStack(rootValue));
12792
12922
  this.dragInfo = new DragInfo(stack, value, dragType, e.target);
12793
12923
  } else if (type3 === "drop") {
12794
12924
  e.preventDefault();
@@ -12863,7 +12993,7 @@ var App = class {
12863
12993
  this.rootNode.removeEventListener(name, this, listenerOpts(name));
12864
12994
  }
12865
12995
  sendAtRoot(name, args) {
12866
- this.transactor.pushSend(new Path([]), name, args);
12996
+ this.transactor.pushSend(new DispatchPath(), name, args);
12867
12997
  }
12868
12998
  registerComponents(comps, opts) {
12869
12999
  const scope = this.compStack.enter();
@@ -13003,7 +13133,20 @@ var WeakMapDomCache = class {
13003
13133
  };
13004
13134
 
13005
13135
  // src/renderer.js
13006
- var DATASET_ATTRS = ["nid", "cid", "eid", "vid", "si", "sk"];
13136
+ var DATASET_ATTRS = ["nid", "cid", "eid", "vid", "si", "sk", "rp"];
13137
+ function stampRenderBase(vdom, text) {
13138
+ if (vdom instanceof VNode)
13139
+ return new VNode(
13140
+ vdom.tag,
13141
+ { ...vdom.attrs, "data-rp": text },
13142
+ vdom.childs,
13143
+ vdom.key,
13144
+ vdom.namespace
13145
+ );
13146
+ if (vdom instanceof VFragment)
13147
+ return new VFragment(vdom.childs.map((c) => stampRenderBase(c, text)));
13148
+ return vdom;
13149
+ }
13007
13150
  var Renderer = class {
13008
13151
  constructor(comps) {
13009
13152
  this.comps = comps;
@@ -13040,17 +13183,17 @@ var Renderer = class {
13040
13183
  if (comp === null) return null;
13041
13184
  return this._rValComp(stack, val, comp, comp.getView(viewName).anode, "ROOT", viewName);
13042
13185
  }
13043
- renderIt(stack, node, key, viewName) {
13186
+ renderIt(stack, node, key, viewName, base = null) {
13044
13187
  const comp = this.comps.getCompFor(stack.it);
13045
- return comp ? this._rValComp(stack, stack.it, comp, node, key, viewName) : null;
13188
+ return comp ? this._rValComp(stack, stack.it, comp, node, key, viewName, base) : null;
13046
13189
  }
13047
13190
  // `node` is the parse node of the render site (`<x render>` / `render-it` /
13048
13191
  // `render-each`, or the view's root anode for the app root). It keys the
13049
13192
  // cache as a globally-unique object: node ids alone are unique only within a
13050
13193
  // single view, so the same value rendered by two components (e.g. through a
13051
13194
  // shared dynamic-var sequence) would otherwise collide in the cache.
13052
- _rValComp(stack, val, comp, node, key, viewName) {
13053
- const cacheKey = `${viewName ?? ""}${stack.viewsId ?? ""}${key}`;
13195
+ _rValComp(stack, val, comp, node, key, viewName, base = null) {
13196
+ const cacheKey = `${viewName ?? ""}${stack.viewsId ?? ""}${key}${stack.renderPath.addressKey}`;
13054
13197
  const cachePath = [node, val];
13055
13198
  stack._pushDynBindValuesToArray(cachePath, comp);
13056
13199
  const cachedNode = this.cache.get(cachePath, cacheKey);
@@ -13058,30 +13201,43 @@ var Renderer = class {
13058
13201
  const view = viewName ? comp.getView(viewName) : stack.lookupBestView(comp.views, "main");
13059
13202
  const body = this.renderView(view, stack);
13060
13203
  if (body == null) return null;
13204
+ const baseJson = base === null ? null : pathToJson(base);
13061
13205
  const meta = this._renderMetadata({
13062
13206
  $: "Comp",
13063
13207
  nid: node?.nodeId ?? null,
13064
13208
  cid: comp.id,
13065
- vid: view.name
13209
+ vid: view.name,
13210
+ ...baseJson === null ? null : { base: baseJson }
13066
13211
  });
13067
- const dom = new VFragment([meta, body]);
13212
+ const dom = new VFragment([
13213
+ meta,
13214
+ baseJson === null ? body : stampRenderBase(body, JSON.stringify(baseJson))
13215
+ ]);
13068
13216
  this.cache.set(cachePath, cacheKey, dom);
13069
13217
  return dom;
13070
13218
  }
13071
13219
  pushEachEntry(r, nid, attrName, key, dom) {
13072
13220
  r.push(this._renderMetadata({ $: "Each", nid, [attrName]: key }), dom);
13073
13221
  }
13074
- renderEachWhen(stack, iterInfo, view, nid) {
13222
+ renderEachWhen(stack, each2) {
13223
+ const { iterInfo, node: view, nodeId: nid } = each2;
13075
13224
  const { seq, filter, loopWith, enricher } = iterInfo.eval(stack);
13225
+ const seqPath = iterInfo.val instanceof DynVal ? stack.lookupDynamicLocated(iterInfo.val.name)?.path ?? null : null;
13076
13226
  const r = [];
13077
13227
  const it = stack.it;
13078
13228
  const renderOne = (key, value, attrName, binds) => {
13229
+ const itemBase = seqPath === null ? null : keyedPath(seqPath, key);
13230
+ const itemStep = itemBase === null ? each2.itemStep(key) : null;
13231
+ const itemPath = itemBase !== null ? stack.renderPath.pushFrame(itemBase) : itemStep !== null ? stack.renderPath.pushItem(itemStep) : stack.renderPath;
13079
13232
  const cachePath = enricher ? [view, it, value] : [view, value];
13080
- const cacheKey = `${stack.viewsId ?? ""}${nid}${key}`;
13233
+ const cacheKey = `${stack.viewsId ?? ""}${nid}${key}${itemPath.addressKey}`;
13081
13234
  const cachedNode = this.cache.get(cachePath, cacheKey);
13082
13235
  if (cachedNode) this.pushEachEntry(r, nid, attrName, key, cachedNode);
13083
13236
  else {
13084
- const dom = this.renderView(view, stack.enter(value, binds, false));
13237
+ const dom = this.renderView(
13238
+ view,
13239
+ stack.enter(value, binds, false, itemPath, itemBase !== null)
13240
+ );
13085
13241
  if (dom != null) this.pushEachEntry(r, nid, attrName, key, dom);
13086
13242
  this.cache.set(cachePath, cacheKey, dom);
13087
13243
  }
@@ -13337,7 +13493,6 @@ export {
13337
13493
  ModuleTests,
13338
13494
  PASS,
13339
13495
  PLACEHOLDERLESS_TEMPLATE_STRING,
13340
- PROVIDE_NAME_COLLISION,
13341
13496
  PROVIDE_NOT_ADDRESSABLE,
13342
13497
  PROVIDE_TYPE_BAD_SHAPE,
13343
13498
  ParseContext,
@@ -13378,6 +13533,7 @@ export {
13378
13533
  lintIdToMessage,
13379
13534
  macro,
13380
13535
  makeCollector,
13536
+ path,
13381
13537
  phaseOps,
13382
13538
  reportTestReportToConsole,
13383
13539
  resolveArgs,