tutuca 0.13.3 → 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.
@@ -1039,8 +1039,68 @@ var init_immer2 = __esm({
1039
1039
  });
1040
1040
 
1041
1041
  // src/path.js
1042
- function warnRawDynStep(op, step) {
1043
- console.warn(`Path.${op} reached a DynStep: call toTransactionPath() first`, step);
1042
+ function stepToJson(step) {
1043
+ if (step instanceof SeqStep) return { f: step.field, k: step.key };
1044
+ if (step instanceof FieldStep) return { f: step.field };
1045
+ if (step instanceof SeqAccessStep) return { f: step.seqField, a: step.keyField };
1046
+ return null;
1047
+ }
1048
+ function stepFromJson(j) {
1049
+ if (j == null || typeof j.f !== "string") return null;
1050
+ if (j.k !== void 0) return new SeqStep(j.f, j.k);
1051
+ if (j.a !== void 0) return new SeqAccessStep(j.f, j.a);
1052
+ return new FieldStep(j.f);
1053
+ }
1054
+ function pathToJson(path) {
1055
+ const out = [];
1056
+ for (const step of path.steps) {
1057
+ const j = stepToJson(step);
1058
+ if (j === null) return null;
1059
+ out.push(j);
1060
+ }
1061
+ return out;
1062
+ }
1063
+ function pathFromJson(j) {
1064
+ if (!Array.isArray(j)) return null;
1065
+ const steps = [];
1066
+ for (const item of j) {
1067
+ const step = stepFromJson(item);
1068
+ if (step === null) return null;
1069
+ steps.push(step);
1070
+ }
1071
+ return new Path(steps);
1072
+ }
1073
+ function walkItems(stack, items, renderPath, path) {
1074
+ let prev = stack.it;
1075
+ for (const step of items) {
1076
+ const next = step.lookup(prev, NONE);
1077
+ if (next === NONE) {
1078
+ console.warn("bad PathItem", { root: stack.it, step, path });
1079
+ return null;
1080
+ }
1081
+ renderPath = renderPath.pushItem(step);
1082
+ stack = step.enterFrame(stack, next, renderPath);
1083
+ prev = next;
1084
+ }
1085
+ return [stack, renderPath];
1086
+ }
1087
+ function keyedPath(path, key) {
1088
+ const steps = path.steps;
1089
+ const last = steps[steps.length - 1];
1090
+ if (last instanceof SeqStep || last instanceof FieldStep)
1091
+ return new Path(steps.slice(0, -1).concat(new SeqStep(last.field, key)));
1092
+ return null;
1093
+ }
1094
+ function renderPathText(path) {
1095
+ return JSON.stringify(pathToJson(path));
1096
+ }
1097
+ function parseRenderPath(text) {
1098
+ try {
1099
+ return pathFromJson(JSON.parse(text));
1100
+ } catch (err) {
1101
+ console.warn("bad render path", err, text);
1102
+ return null;
1103
+ }
1044
1104
  }
1045
1105
  function metaChain(n) {
1046
1106
  const out = [];
@@ -1061,15 +1121,18 @@ function findHandlers(comp, eventIds, vid, eventName) {
1061
1121
  }
1062
1122
  return null;
1063
1123
  }
1064
- function resolvePathStep(comp, nodeIds, vid) {
1065
- for (let i = 0; i < nodeIds.length; i++) {
1066
- const ctx = new StepCtx(comp, nodeIds, i, vid);
1067
- const step = ctx.resolveNode().toPathStep(ctx);
1068
- if (step !== null) return step;
1124
+ function resolvePathPart(comp, nodeRefs, vid) {
1125
+ for (let i = 0; i < nodeRefs.length; i++) {
1126
+ const ref = nodeRefs[i];
1127
+ if (ref.base != null) return { base: ref.base };
1128
+ if (ref.nid === void 0 || ref.nid === null) continue;
1129
+ const ctx = new StepCtx(comp, nodeRefs, i, vid);
1130
+ const step = ctx.resolveNode()?.toPathStep(ctx) ?? null;
1131
+ if (step !== null) return { step };
1069
1132
  }
1070
1133
  return null;
1071
1134
  }
1072
- var NONE, readKey, writeKey, writeSeqKey, Step, BindStep, ScopeBindStep, FieldStep, SeqStep, SeqAccessStep, EachBindStep, EachRenderItStep, DynStep, DynEachStep, Path, StepCtx, NO_EVENT_INFO, BUBBLING_EVENTS, PathBuilder;
1135
+ var NONE, readKey, writeKey, writeSeqKey, Step, BindStep, ScopeBindStep, FieldStep, SeqStep, SeqAccessStep, EachBindStep, EachRenderItStep, Path, EMPTY_PATH, DispatchPath, StepCtx, NO_EVENT_INFO, BUBBLING_EVENTS, PathBuilder;
1073
1136
  var init_path = __esm({
1074
1137
  "src/path.js"() {
1075
1138
  init_collection();
@@ -1100,8 +1163,11 @@ var init_path = __esm({
1100
1163
  }
1101
1164
  setDraftValue(_root, _v) {
1102
1165
  }
1103
- enterFrame(stack, next) {
1104
- return stack.enter(next, {}, true);
1166
+ // Re-enter this step while rebuilding a stack. `renderPath` is the dispatch
1167
+ // position AFTER this step: a rebuilt frame must carry the same render path
1168
+ // the renderer had there, or the provides it publishes would be located wrong.
1169
+ enterFrame(stack, next, renderPath) {
1170
+ return stack.enter(next, {}, true, renderPath);
1105
1171
  }
1106
1172
  toAbstractPathStep() {
1107
1173
  return this;
@@ -1126,8 +1192,8 @@ var init_path = __esm({
1126
1192
  lookup(v, _dval) {
1127
1193
  return v;
1128
1194
  }
1129
- enterFrame(stack, next) {
1130
- return stack.enter(next, { ...this.binds }, false);
1195
+ enterFrame(stack, next, renderPath) {
1196
+ return stack.enter(next, { ...this.binds }, false, renderPath);
1131
1197
  }
1132
1198
  withIndex(i) {
1133
1199
  return new _BindStep({ ...this.binds, key: i });
@@ -1144,9 +1210,9 @@ var init_path = __esm({
1144
1210
  super(binds);
1145
1211
  this.val = val;
1146
1212
  }
1147
- enterFrame(stack, next) {
1213
+ enterFrame(stack, next, renderPath) {
1148
1214
  const dyn = this.val.evalAsHandler(stack)?.call(stack.it) ?? {};
1149
- return stack.enter(next, { ...this.binds, ...dyn }, false);
1215
+ return stack.enter(next, { ...this.binds, ...dyn }, false, renderPath);
1150
1216
  }
1151
1217
  withIndex(i) {
1152
1218
  return new _ScopeBindStep(this.val, { ...this.binds, key: i });
@@ -1189,8 +1255,8 @@ var init_path = __esm({
1189
1255
  const seq = readKey(root, this.field, null);
1190
1256
  if (seq != null) writeSeqKey(seq, this.key, v);
1191
1257
  }
1192
- enterFrame(stack, next) {
1193
- return stack.enter(next, { key: this.key }, true);
1258
+ enterFrame(stack, next, renderPath) {
1259
+ return stack.enter(next, { key: this.key }, true, renderPath);
1194
1260
  }
1195
1261
  toKey() {
1196
1262
  return { field: this.field, key: this.key };
@@ -1236,57 +1302,21 @@ var init_path = __esm({
1236
1302
  }
1237
1303
  // Replay the renderer's per-item binds (key, value + any @enrich-with binds)
1238
1304
  // so a rebuilt stack matches the one @each rendered with.
1239
- enterFrame(stack, next) {
1240
- return stack.enter(next, this.iterInfo.enrichBinds(stack, this.key), false);
1305
+ enterFrame(stack, next, renderPath) {
1306
+ return stack.enter(next, this.iterInfo.enrichBinds(stack, this.key), false, renderPath);
1241
1307
  }
1242
1308
  toAbstractPathStep() {
1243
1309
  return null;
1244
1310
  }
1245
1311
  };
1246
1312
  EachRenderItStep = class extends SeqStep {
1247
- enterFrame(stack, next) {
1248
- return stack.enter(next, { key: this.key, value: next }, false).enter(next, {}, true);
1313
+ enterFrame(stack, next, renderPath) {
1314
+ return stack.enter(next, { key: this.key, value: next }, false, renderPath).enter(next, {}, true, renderPath);
1249
1315
  }
1250
1316
  toAbstractPathStep() {
1251
1317
  return new SeqStep(this.field, this.key);
1252
1318
  }
1253
1319
  };
1254
- DynStep = class extends Step {
1255
- constructor(producerCompId, producerSteps) {
1256
- super();
1257
- this.producerCompId = producerCompId;
1258
- this.producerSteps = producerSteps;
1259
- this.interiorCids = /* @__PURE__ */ new Set();
1260
- }
1261
- // Steps spliced into the transaction path in place of this marker.
1262
- teleportSteps() {
1263
- return this.producerSteps;
1264
- }
1265
- lookup(_v, dval = null) {
1266
- warnRawDynStep("lookup", this);
1267
- return dval;
1268
- }
1269
- enterFrame(stack, _next) {
1270
- warnRawDynStep("enterFrame", this);
1271
- return stack;
1272
- }
1273
- };
1274
- DynEachStep = class extends DynStep {
1275
- constructor(producerCompId, producerSteps, key) {
1276
- super(producerCompId, producerSteps);
1277
- this.key = key;
1278
- }
1279
- teleportSteps() {
1280
- const { producerSteps, key } = this;
1281
- if (producerSteps.length === 0) return producerSteps;
1282
- const last = producerSteps[producerSteps.length - 1];
1283
- if (!(last instanceof FieldStep)) {
1284
- console.warn("DynEachStep: seq-access dynamic cannot be iterated", this);
1285
- return producerSteps;
1286
- }
1287
- return producerSteps.slice(0, -1).concat(new SeqStep(last.field, key));
1288
- }
1289
- };
1290
1320
  Path = class _Path {
1291
1321
  constructor(steps = []) {
1292
1322
  this.steps = steps;
@@ -1297,40 +1327,13 @@ var init_path = __esm({
1297
1327
  popStep() {
1298
1328
  return new _Path(this.steps.slice(0, -1));
1299
1329
  }
1300
- // The dispatch path: frame-only steps removed, one step per crossed component
1301
- // (DynStep included). `popStep` over it bubbles through every component.
1330
+ // Frame-only steps removed, one step per crossed component: `popStep` over the
1331
+ // result bubbles through every component.
1302
1332
  compact() {
1303
1333
  const out = [];
1304
1334
  for (const step of this.steps) {
1305
1335
  const s = step.toAbstractPathStep();
1306
- if (s !== null) {
1307
- if (s !== step) s._originCid = step._originCid;
1308
- out.push(s);
1309
- }
1310
- }
1311
- return new _Path(out);
1312
- }
1313
- // The abstract path used to apply a transaction: every DynStep is teleported —
1314
- // the steps interior to its producer..consumer span are dropped and the
1315
- // producer's own path spliced in — so a mutation lands on the data's real
1316
- // location. A path with no DynStep is returned unchanged.
1317
- toTransactionPath() {
1318
- let hasDyn = false;
1319
- for (const step of this.steps)
1320
- if (step instanceof DynStep) {
1321
- hasDyn = true;
1322
- break;
1323
- }
1324
- if (!hasDyn) return this;
1325
- const out = [];
1326
- for (const step of this.steps) {
1327
- if (step instanceof DynStep) {
1328
- while (out.length > 0 && step.interiorCids.has(out[out.length - 1]._originCid)) out.pop();
1329
- for (const ts of step.teleportSteps()) {
1330
- ts._originCid = step.producerCompId;
1331
- out.push(ts);
1332
- }
1333
- } else out.push(step);
1336
+ if (s !== null) out.push(s);
1334
1337
  }
1335
1338
  return new _Path(out);
1336
1339
  }
@@ -1338,7 +1341,6 @@ var init_path = __esm({
1338
1341
  // key as it is *now* so a later lookup/setValue lands on the same item even if the
1339
1342
  // keyField changed meanwhile (e.g. the selected tab moved while an intent was in
1340
1343
  // flight). Returns a new Path with those steps replaced; `this` if nothing pinned.
1341
- // Must be called on a transaction path (no DynSteps — call toTransactionPath first).
1342
1344
  pinKeys(root) {
1343
1345
  let curVal = root;
1344
1346
  let out = null;
@@ -1361,8 +1363,8 @@ var init_path = __esm({
1361
1363
  }
1362
1364
  // The values entered along the path, root→leaf (root included): index 0 is `root`,
1363
1365
  // the last entry is the leaf this path resolves to. Stops early at the first
1364
- // unresolvable step. Call on a transaction path (no DynSteps). Used to walk the
1365
- // component instances on a dispatch path (filter via Components.getCompFor).
1366
+ // unresolvable step. Used to walk the component instances on a dispatch path
1367
+ // (filter via Components.getCompFor).
1366
1368
  resolveChain(root) {
1367
1369
  const out = [root];
1368
1370
  let curVal = root;
@@ -1376,7 +1378,7 @@ var init_path = __esm({
1376
1378
  // A flat `[{ field, key? }]` list of the addressing steps, skipping frame-only
1377
1379
  // steps (binds). Generic path introspection so tooling (e.g. the storybook
1378
1380
  // activity log) can identify which subtree a transaction touched without
1379
- // depending on Step internals. Call on a transaction path (no DynSteps).
1381
+ // depending on Step internals.
1380
1382
  toKeys() {
1381
1383
  const out = [];
1382
1384
  for (const step of this.steps) {
@@ -1397,62 +1399,133 @@ var init_path = __esm({
1397
1399
  });
1398
1400
  }
1399
1401
  buildStack(stack) {
1400
- let prev = stack.it;
1401
- for (const step of this.steps) {
1402
- const next = step.lookup(prev, NONE);
1403
- if (next === NONE) {
1404
- console.warn("bad PathItem", { root: stack.it, step, path: this });
1405
- return null;
1402
+ return walkItems(stack, this.steps, stack.renderPath ?? new DispatchPath(), this)?.[0] ?? null;
1403
+ }
1404
+ };
1405
+ EMPTY_PATH = new Path([]);
1406
+ DispatchPath = class _DispatchPath {
1407
+ constructor(frames = [{ base: EMPTY_PATH, items: [] }]) {
1408
+ this.frames = frames;
1409
+ }
1410
+ // Plain addressing steps in one frame based at the root: what a caller means
1411
+ // by "this position" when it has no continuation of its own.
1412
+ static ofSteps(steps) {
1413
+ return new _DispatchPath([{ base: EMPTY_PATH, items: steps.slice() }]);
1414
+ }
1415
+ get top() {
1416
+ return this.frames[this.frames.length - 1];
1417
+ }
1418
+ _withTopItems(items) {
1419
+ const frames = this.frames.slice();
1420
+ frames[frames.length - 1] = { base: this.top.base, items };
1421
+ return new _DispatchPath(frames);
1422
+ }
1423
+ concat(steps) {
1424
+ if (this.frames.length === 0) return _DispatchPath.ofSteps(steps);
1425
+ return this._withTopItems(this.top.items.concat(steps));
1426
+ }
1427
+ pushItem(step) {
1428
+ return this.concat([step]);
1429
+ }
1430
+ pushFrame(base) {
1431
+ return new _DispatchPath(this.frames.concat({ base, items: [] }));
1432
+ }
1433
+ // Whether bubbling has anywhere left to go: another step in this frame, or a
1434
+ // visual caller underneath it.
1435
+ canPop() {
1436
+ const n = this.frames.length;
1437
+ return n > 1 || n === 1 && this.frames[0].items.length > 0;
1438
+ }
1439
+ isRoot() {
1440
+ return this.toTransactionPath().steps.length === 0;
1441
+ }
1442
+ // One component closer to the root. At the top of a frame that is popping back
1443
+ // to the visual caller, not to the producer's own parent — the caller is where
1444
+ // the `*name` was written, and where an unhandled message should keep going.
1445
+ popStep() {
1446
+ const n = this.frames.length;
1447
+ if (n === 0) return this;
1448
+ const top = this.frames[n - 1];
1449
+ if (top.items.length > 0) return this._withTopItems(top.items.slice(0, -1));
1450
+ if (n > 1) return new _DispatchPath(this.frames.slice(0, -1));
1451
+ return this;
1452
+ }
1453
+ // Drop frame-only steps inside every frame independently; a frame's base is
1454
+ // already addressing-only.
1455
+ compact() {
1456
+ return new _DispatchPath(
1457
+ this.frames.map(({ base, items }) => ({ base, items: new Path(items).compact().steps }))
1458
+ );
1459
+ }
1460
+ // A stable string for the ADDRESS this path denotes, for the render cache. The
1461
+ // same immutable value can sit at two places in the tree, and a subtree rendered
1462
+ // at one of them bakes that address in — the provides it publishes are located
1463
+ // there. Frame-only steps address nothing, so they are compacted out: two sites
1464
+ // that differ only in binds do render the same subtree.
1465
+ get addressKey() {
1466
+ this._addressKey ??= renderPathText(this.toTransactionPath().compact());
1467
+ return this._addressKey;
1468
+ }
1469
+ // The active transaction address: the top frame's absolute base followed by
1470
+ // its ordinary descendant steps. This is where a mutation lands.
1471
+ toTransactionPath() {
1472
+ const top = this.top;
1473
+ return top === void 0 ? EMPTY_PATH : top.base.concat(top.items);
1474
+ }
1475
+ // Rebuild the render stack this path was dispatched from. A frame with a base
1476
+ // re-enters at that absolute value first — replaying the resume a `*name`
1477
+ // render performed — and then walks its ordinary items.
1478
+ buildStack(stack) {
1479
+ let renderPath = new _DispatchPath();
1480
+ for (let i = 0; i < this.frames.length; i++) {
1481
+ const { base, items } = this.frames[i];
1482
+ if (i > 0 || base.steps.length > 0) {
1483
+ const baseValue = base.lookup(stack.root, NONE);
1484
+ if (baseValue === NONE) {
1485
+ console.warn("bad frame base", { base, path: this });
1486
+ return null;
1487
+ }
1488
+ renderPath = renderPath.pushFrame(base);
1489
+ stack = stack.enter(baseValue, {}, true, renderPath);
1406
1490
  }
1407
- stack = step.enterFrame(stack, next);
1408
- prev = next;
1491
+ const walked = walkItems(stack, items, renderPath, this);
1492
+ if (walked === null) return null;
1493
+ [stack, renderPath] = walked;
1409
1494
  }
1410
1495
  return stack;
1411
1496
  }
1412
1497
  static fromNodeAndEventName(node, eventName, rootNode, maxDepth, comps, stopOnNoEvent = true) {
1413
- const pathSteps = [];
1414
- const pendingDyns = [];
1498
+ const parts = [];
1415
1499
  const bubbles = BUBBLING_EVENTS.has(eventName);
1416
1500
  let depth = 0;
1417
1501
  let eventIds = [];
1418
1502
  let handlers = null;
1419
- let nodeIds = [];
1503
+ let nodeRefs = [];
1420
1504
  let isLeafComponent = true;
1421
1505
  const crossComponent = (cidNum, vid) => {
1422
1506
  const comp = comps.getComponentForId(cidNum);
1423
- let pushStep = true;
1507
+ let pushPart = true;
1424
1508
  if (handlers === null && (isLeafComponent || bubbles)) {
1425
1509
  handlers = findHandlers(comp, eventIds, vid, eventName);
1426
1510
  if (handlers === null) {
1427
1511
  if (isLeafComponent && stopOnNoEvent && !bubbles) return false;
1428
1512
  } else if (!isLeafComponent) {
1429
- pathSteps.length = 0;
1430
- pendingDyns.length = 0;
1431
- pushStep = false;
1513
+ parts.length = 0;
1514
+ pushPart = false;
1432
1515
  }
1433
1516
  }
1434
1517
  isLeafComponent = false;
1435
- for (const dyn of pendingDyns) dyn.interiorCids.add(cidNum);
1436
- if (pushStep) {
1437
- const step = resolvePathStep(comp, nodeIds, vid);
1438
- if (step) {
1439
- step._originCid = cidNum;
1440
- pathSteps.push(step);
1441
- if (step instanceof DynStep) {
1442
- step.interiorCids.add(cidNum);
1443
- pendingDyns.push(step);
1444
- }
1445
- }
1518
+ if (pushPart) {
1519
+ const part = resolvePathPart(comp, nodeRefs, vid);
1520
+ if (part) parts.push(part);
1446
1521
  }
1447
- for (let i = pendingDyns.length - 1; i >= 0; i--)
1448
- if (pendingDyns[i].producerCompId === cidNum) pendingDyns.splice(i, 1);
1449
1522
  eventIds = [];
1450
- nodeIds = [];
1523
+ nodeRefs = [];
1451
1524
  return true;
1452
1525
  };
1453
1526
  while (node && node !== rootNode && depth < maxDepth) {
1454
1527
  if (node?.dataset) {
1455
- const { eid, cid, vid } = node.dataset;
1528
+ const { eid, cid, vid, rp } = node.dataset;
1456
1529
  if (eid !== void 0) eventIds.push(eid);
1457
1530
  const metas = metaChain(node.previousSibling);
1458
1531
  let sawComp = false;
@@ -1460,19 +1533,27 @@ var init_path = __esm({
1460
1533
  if (m.$ === "Comp") {
1461
1534
  sawComp = true;
1462
1535
  if (!crossComponent(m.cid, m.vid)) return NO_EVENT_INFO;
1463
- nodeIds.push({ nid: m.nid });
1536
+ nodeRefs.push({ nid: m.nid, base: pathFromJson(m.base) });
1464
1537
  } else {
1465
- nodeIds.push({ nid: m.nid, si: m.si, sk: m.sk });
1538
+ nodeRefs.push({ nid: m.nid, si: m.si, sk: m.sk });
1539
+ }
1540
+ }
1541
+ if (!sawComp && cid !== void 0) {
1542
+ if (!crossComponent(+cid, vid)) return NO_EVENT_INFO;
1543
+ if (rp !== void 0) {
1544
+ const base = parseRenderPath(rp);
1545
+ if (base !== null) nodeRefs.push({ base });
1466
1546
  }
1467
1547
  }
1468
- if (!sawComp && cid !== void 0 && !crossComponent(+cid, vid)) return NO_EVENT_INFO;
1469
1548
  }
1470
1549
  depth += 1;
1471
1550
  node = node.parentNode;
1472
1551
  }
1473
- if (pendingDyns.length > 0)
1474
- console.warn("event reconstruction: dynamic-var producer not found", pendingDyns);
1475
- return [new _Path(pathSteps.reverse()), handlers];
1552
+ parts.reverse();
1553
+ let path = new _DispatchPath();
1554
+ for (const part of parts)
1555
+ path = part.base !== void 0 ? path.pushFrame(part.base) : path.pushItem(part.step);
1556
+ return [path, handlers];
1476
1557
  }
1477
1558
  };
1478
1559
  StepCtx = class _StepCtx {
@@ -1514,6 +1595,9 @@ var init_path = __esm({
1514
1595
  constructor() {
1515
1596
  this.pathChanges = [];
1516
1597
  }
1598
+ toPath() {
1599
+ return new Path(this.pathChanges);
1600
+ }
1517
1601
  add(pathChange) {
1518
1602
  this.pathChanges.push(pathChange);
1519
1603
  return this;
@@ -2702,13 +2786,16 @@ var init_vdom = __esm({
2702
2786
  });
2703
2787
 
2704
2788
  // src/anode.js
2705
- function resolveDynProducer(comp, name) {
2706
- const own = comp?.provide?.[name];
2707
- const producerComp = own != null ? comp : comp?.scope?.lookupProvider(name) ?? null;
2708
- const producerProvide = own ?? producerComp?.provide?.[name];
2709
- if (producerComp == null || producerProvide == null) return null;
2710
- const pi = producerProvide.val?.toPathItem?.() ?? null;
2711
- return { producerCompId: producerComp.id, producerSteps: pi ? [pi] : [] };
2789
+ function renderTarget(val, stack) {
2790
+ if (val instanceof DynVal) {
2791
+ const loc = stack.lookupDynamicLocated(val.name);
2792
+ if (loc?.path == null) return [loc?.value ?? null, stack.renderPath, null];
2793
+ return [loc.value, stack.renderPath.pushFrame(loc.path), loc.path];
2794
+ }
2795
+ const step = val.toPathItem?.() ?? null;
2796
+ if (step === null) return [val.eval(stack), stack.renderPath, null];
2797
+ const path = stack.renderPath.pushItem(step);
2798
+ return [val.eval(stack), path, stack.pendingFrame ? path.toTransactionPath() : null];
2712
2799
  }
2713
2800
  function optimizeChilds(childs) {
2714
2801
  for (let i = 0; i < childs.length; i++) {
@@ -2816,11 +2903,6 @@ function makeWrapperNode(data, px) {
2816
2903
  }
2817
2904
  return node;
2818
2905
  }
2819
- function dynRenderStep(comp, name, key) {
2820
- const p = resolveDynProducer(comp, name);
2821
- if (!p) return null;
2822
- return key === void 0 ? new DynStep(p.producerCompId, p.producerSteps) : new DynEachStep(p.producerCompId, p.producerSteps, key);
2823
- }
2824
2906
  function parseRenderEach(px, value, as, attrs) {
2825
2907
  const seqVal = parseXOpVal("render-each", value, px, parseSequence);
2826
2908
  if (seqVal === null) return null;
@@ -3090,26 +3172,29 @@ var init_anode = __esm({
3090
3172
  };
3091
3173
  RenderNode = class extends RenderViewId {
3092
3174
  render(stack, rx) {
3093
- const newStack = stack.enter(this.val.eval(stack), {}, true);
3094
- return rx.renderIt(newStack, this, "", this.evalViewName(stack));
3175
+ const [value, renderPath, base] = renderTarget(this.val, stack);
3176
+ const newStack = stack.enter(value, {}, true, renderPath, false);
3177
+ return rx.renderIt(newStack, this, "", this.evalViewName(stack), base);
3095
3178
  }
3179
+ // A `*name` target contributes no step: the site recorded the absolute base it
3180
+ // resumed at, and event reconstruction turns that into a continuation frame.
3096
3181
  toPathStep(ctx) {
3097
- if (this.val instanceof DynVal) return dynRenderStep(ctx.comp, this.val.name);
3182
+ if (this.val instanceof DynVal) return null;
3098
3183
  return super.toPathStep(ctx);
3099
3184
  }
3100
3185
  };
3101
3186
  RenderItNode = class extends RenderViewId {
3102
3187
  render(stack, rx) {
3103
- const newStack = stack.enter(stack.it, {}, true);
3104
- return rx.renderIt(newStack, this, "", this.evalViewName(stack));
3188
+ const base = stack.pendingFrame ? stack.renderPath.toTransactionPath() : null;
3189
+ const newStack = stack.enter(stack.it, {}, true, stack.renderPath, false);
3190
+ return rx.renderIt(newStack, this, "", this.evalViewName(stack), base);
3105
3191
  }
3106
3192
  toPathStep(ctx) {
3107
3193
  const next = ctx.next();
3108
3194
  if (next === null) return null;
3109
3195
  const nextNode = next.resolveNode();
3110
3196
  if (nextNode instanceof EachNode && next.hasKey) {
3111
- if (nextNode.val instanceof DynVal)
3112
- return dynRenderStep(ctx.comp, nextNode.val.name, next.key);
3197
+ if (nextNode.val instanceof DynVal) return null;
3113
3198
  return new EachRenderItStep(nextNode.val.name, next.key);
3114
3199
  }
3115
3200
  return null;
@@ -3199,11 +3284,19 @@ var init_anode = __esm({
3199
3284
  this.iterInfo = new IterInfo(val, null, null, null);
3200
3285
  }
3201
3286
  render(stack, rx) {
3202
- return rx.renderEachWhen(stack, this.iterInfo, this.node, this.nodeId);
3287
+ return rx.renderEachWhen(stack, this);
3203
3288
  }
3204
3289
  toPathStep(ctx) {
3205
3290
  return ctx.hasKey ? new EachBindStep(this.iterInfo, ctx.key) : null;
3206
3291
  }
3292
+ // Where one item lives, for the render path. `@each` re-binds `it` to the item
3293
+ // whether or not the body is a component, so the position moves either way and
3294
+ // the step has to address it — `.rows` iterated at `key` IS `rows[key]`.
3295
+ // Null for a dynamic sequence: `*rows` carries its own absolute path and enters
3296
+ // a continuation frame instead (see Renderer.renderEachWhen).
3297
+ itemStep(key) {
3298
+ return this.val instanceof FieldVal ? new SeqStep(this.val.name, key) : null;
3299
+ }
3207
3300
  static register = true;
3208
3301
  };
3209
3302
  IterInfo = class {
@@ -3424,11 +3517,227 @@ var init_anode = __esm({
3424
3517
  }
3425
3518
  });
3426
3519
 
3520
+ // src/stack.js
3521
+ function routeLookup(route, lex, dyn) {
3522
+ for (let i = 0; i < route.length; i++) {
3523
+ const leg = route[i];
3524
+ if (leg === "dyn") {
3525
+ const v = dyn();
3526
+ if (v != null) return v;
3527
+ } else if (leg === "lex") {
3528
+ const v = lex();
3529
+ if (v != null) return v;
3530
+ } else {
3531
+ console.warn("unknown lookup route leg", leg, '- expected "dyn" or "lex"');
3532
+ }
3533
+ }
3534
+ return null;
3535
+ }
3536
+ function lookup(chain, name, dv = null) {
3537
+ let n = chain;
3538
+ while (n !== null) {
3539
+ const r = n[0].lookup(name);
3540
+ if (r === STOP) return dv;
3541
+ if (r !== NEXT) return r;
3542
+ n = n[1];
3543
+ }
3544
+ return dv;
3545
+ }
3546
+ function computeViewsId(views) {
3547
+ let s = "";
3548
+ let n = views;
3549
+ while (n !== null) {
3550
+ s += n[0];
3551
+ n = n[1];
3552
+ }
3553
+ return s === "main" ? "" : s;
3554
+ }
3555
+ var STOP, NEXT, DEFAULT_ROUTE, isTypeName, BindFrame, DynFrame, Stack, NOT_FOUND;
3556
+ var init_stack = __esm({
3557
+ "src/stack.js"() {
3558
+ init_path();
3559
+ STOP = /* @__PURE__ */ Symbol("STOP");
3560
+ NEXT = /* @__PURE__ */ Symbol("NEXT");
3561
+ DEFAULT_ROUTE = ["dyn", "lex"];
3562
+ isTypeName = (s) => {
3563
+ const c = s.charCodeAt(0);
3564
+ return c >= 65 && c <= 90;
3565
+ };
3566
+ BindFrame = class {
3567
+ constructor(it, binds, isFrame) {
3568
+ this.it = it;
3569
+ this.binds = binds;
3570
+ this.isFrame = isFrame;
3571
+ }
3572
+ lookup(name) {
3573
+ const v = this.binds[name];
3574
+ return v === void 0 ? this.isFrame ? STOP : NEXT : v;
3575
+ }
3576
+ };
3577
+ DynFrame = class {
3578
+ constructor(binds, types) {
3579
+ this.binds = binds;
3580
+ this.types = types;
3581
+ }
3582
+ lookup(name) {
3583
+ const v = (isTypeName(name) ? this.types : this.binds)[name];
3584
+ return v === void 0 ? NEXT : v;
3585
+ }
3586
+ };
3587
+ Stack = class _Stack {
3588
+ constructor(fields) {
3589
+ Object.assign(this, fields);
3590
+ }
3591
+ _with(patch) {
3592
+ return new _Stack({ ...this, ...patch });
3593
+ }
3594
+ // Evaluate every provide the entered component publishes and push them as one
3595
+ // dynBinds frame, keyed by NAME. A value is published together with the absolute
3596
+ // path it lives at: the same declaration is read as `*name` AND resumed at by
3597
+ // `<x render="*name">`, so a consumer needs both halves. Types go in the same
3598
+ // frame's other map. No-op with no provides.
3599
+ _pushProvides() {
3600
+ const comp = this.comps.getCompFor(this.it);
3601
+ if (comp == null) return this;
3602
+ const { provide, provideType } = comp;
3603
+ const binds = {};
3604
+ const types = {};
3605
+ let has2 = false;
3606
+ const base = this._publishBase();
3607
+ for (const k in provide) {
3608
+ const step = provide[k].val.toPathItem?.() ?? null;
3609
+ if (step === null) continue;
3610
+ const value = provide[k].val.eval(this);
3611
+ binds[k] = { value, path: base === null ? null : base.concat([step]) };
3612
+ has2 = true;
3613
+ }
3614
+ for (const k in provideType) {
3615
+ types[k] = provideType[k];
3616
+ has2 = true;
3617
+ }
3618
+ if (!has2) return this;
3619
+ return this._with({ dynBinds: [new DynFrame(binds, types), this.dynBinds] });
3620
+ }
3621
+ // The absolute address of the component being entered, or null when this
3622
+ // position cannot be written down as one. Frame-only steps carry bindings and
3623
+ // address nothing, so they are compacted away first; what is left is checked
3624
+ // against the value actually being rendered, because a scope CAN move the
3625
+ // render position without contributing an addressing step (a plain `@each`
3626
+ // body re-binds `it` to the item while its rebuild step is an identity).
3627
+ //
3628
+ // A null base still publishes the VALUE — `*name` reads it fine — but there is
3629
+ // nowhere to resume, so `<x render="*name">` renders nothing rather than
3630
+ // editing whatever happens to live at the address we guessed.
3631
+ _publishBase() {
3632
+ const base = this.renderPath.toTransactionPath().compact();
3633
+ return base.lookup(this.root, NOT_FOUND) === this.it ? base : null;
3634
+ }
3635
+ static root(comps, it, ctx = null) {
3636
+ return new _Stack({
3637
+ comps,
3638
+ root: it,
3639
+ it,
3640
+ binds: [new BindFrame(it, {}, true), null],
3641
+ dynBinds: [new DynFrame({}, {}), null],
3642
+ views: ["main", null],
3643
+ viewsId: "",
3644
+ renderPath: new DispatchPath(),
3645
+ pendingFrame: false,
3646
+ ctx
3647
+ })._pushProvides();
3648
+ }
3649
+ // `renderPath` defaults to this stack's own: an ordinary scope does not move.
3650
+ // `pendingFrame` clears on a component frame (which emits the base) and is
3651
+ // inherited by transparent scopes, which have to carry it to the next boundary.
3652
+ enter(it, bindings = {}, isFrame = true, renderPath = this.renderPath, pendingFrame = null) {
3653
+ const stack = this._with({
3654
+ it,
3655
+ binds: [new BindFrame(it, bindings, isFrame), this.binds],
3656
+ renderPath,
3657
+ pendingFrame: pendingFrame ?? (isFrame ? false : this.pendingFrame)
3658
+ });
3659
+ return isFrame ? stack._pushProvides() : stack;
3660
+ }
3661
+ pushViewName(name) {
3662
+ const views = [name, this.views];
3663
+ return this._with({ views, viewsId: computeViewsId(views) });
3664
+ }
3665
+ // Published types are stable per scope and would only churn the render cache, so
3666
+ // the cache key covers values alone.
3667
+ _pushDynBindValuesToArray(arr, comp) {
3668
+ for (const k in comp.provide) arr.push(this.lookupDynamic(k));
3669
+ for (const k in comp.lookup) arr.push(this.lookupDynamic(k));
3670
+ }
3671
+ // `*name`: the nearest binding above (including this component's own provides,
3672
+ // pushed on entering it), else a path registered in the component's lexical
3673
+ // scope, else this component's declared default, else null.
3674
+ //
3675
+ // One chain walk and no producer resolution: a lookup names what it WANTS, so the
3676
+ // frame it wants is keyed by that name. The default belongs to the CONSUMER's
3677
+ // declaration and is evaluated against the consumer's stack, which is why it is
3678
+ // consulted only after the whole chain has missed.
3679
+ lookupDynamicLocated(name) {
3680
+ if (isTypeName(name)) return null;
3681
+ const v = lookup(this.dynBinds, name);
3682
+ if (v != null) return v;
3683
+ const comp = this.comps.getCompFor(this.it);
3684
+ if (comp == null) return null;
3685
+ const path = comp.scope?.lookupPath?.(name) ?? null;
3686
+ if (path !== null) {
3687
+ const value2 = path.lookup(this.root, NOT_FOUND);
3688
+ if (value2 !== NOT_FOUND) return { value: value2, path };
3689
+ }
3690
+ const dval = comp.lookup[name]?.val ?? null;
3691
+ if (dval === null) return null;
3692
+ const step = dval.toPathItem?.() ?? null;
3693
+ const value = dval.eval(this);
3694
+ return step === null ? { value, path: null } : { value, path: this.renderPath.toTransactionPath().concat([step]) };
3695
+ }
3696
+ lookupDynamic(name) {
3697
+ if (isTypeName(name)) return lookup(this.dynBinds, name);
3698
+ return this.lookupDynamicLocated(name)?.value ?? null;
3699
+ }
3700
+ lookupBind(name) {
3701
+ return lookup(this.binds, name);
3702
+ }
3703
+ lookupFieldRaw(name) {
3704
+ return this.it[name] ?? null;
3705
+ }
3706
+ lookupMethod(name) {
3707
+ const fn = this.it[name];
3708
+ return fn instanceof Function ? fn.call(this.it) : null;
3709
+ }
3710
+ // The dispatched DOM event / drag info, read only by EventMemberVal's
3711
+ // `e.<member>` handler args. Null outside a live event transaction.
3712
+ lookupEvent() {
3713
+ return this.ctx?.event ?? null;
3714
+ }
3715
+ lookupDragInfo() {
3716
+ return this.ctx?.dragInfo ?? null;
3717
+ }
3718
+ getHandlerFor(name, key) {
3719
+ return this.comps.getHandlerFor(this.it, name, key);
3720
+ }
3721
+ lookupBestView(views, defaultViewName) {
3722
+ let n = this.views;
3723
+ while (n !== null) {
3724
+ const view = views[n[0]];
3725
+ if (view !== void 0) return view;
3726
+ n = n[1];
3727
+ }
3728
+ return views[defaultViewName];
3729
+ }
3730
+ };
3731
+ NOT_FOUND = /* @__PURE__ */ Symbol("NOT_FOUND");
3732
+ }
3733
+ });
3734
+
3427
3735
  // src/components.js
3428
- var COMPONENT, Components, ComponentStack, ProvideInfo, LookupInfo, isString, isTypeName, _rawSpecKeys, KNOWN_SPEC_KEYS, _compId, Component;
3736
+ var COMPONENT, Components, ComponentStack, ProvideInfo, LookupInfo, isString, _rawSpecKeys, KNOWN_SPEC_KEYS, _compId, Component;
3429
3737
  var init_components = __esm({
3430
3738
  "src/components.js"() {
3431
3739
  init_anode();
3740
+ init_stack();
3432
3741
  init_value();
3433
3742
  COMPONENT = /* @__PURE__ */ Symbol.for("tutuca.component");
3434
3743
  Components = class {
@@ -3467,12 +3776,14 @@ var init_components = __esm({
3467
3776
  this.byName = {};
3468
3777
  this.intentsByName = {};
3469
3778
  this.macros = {};
3779
+ this.paths = {};
3470
3780
  }
3471
3781
  enter() {
3472
3782
  return new _ComponentStack(this.comps, this);
3473
3783
  }
3474
3784
  registerComponents(comps, opts) {
3475
- const { aliases: aliases2 = {} } = opts ?? {};
3785
+ const { aliases: aliases2 = {}, paths } = opts ?? {};
3786
+ if (paths) this.registerPaths(paths);
3476
3787
  for (let i = 0; i < comps.length; i++) {
3477
3788
  const Comp = comps[i];
3478
3789
  Comp[COMPONENT].scope = this.enter();
@@ -3486,6 +3797,27 @@ var init_components = __esm({
3486
3797
  else console.warn("alias", alias, "to inexistent component", aliases2[alias]);
3487
3798
  }
3488
3799
  }
3800
+ // Register lowercase names as absolute paths from the app state root. A
3801
+ // descendant that declares one in its `lookup` reads and renders `*name` without
3802
+ // anything above it publishing one — which is what makes a session, a theme or a
3803
+ // host-owned value available in its natural registration scope, instead of forcing
3804
+ // an application root whose only job is to `provide` it. Register on a nested
3805
+ // scope to narrow a name; nearest registration wins.
3806
+ //
3807
+ // Uppercase names are ignored: a component TYPE is what `lookupComponent` already
3808
+ // answers, and a type has no path.
3809
+ registerPaths(paths) {
3810
+ for (const name in paths) {
3811
+ if (isTypeName(name)) {
3812
+ console.warn("registerPaths: a type name has no path", name);
3813
+ continue;
3814
+ }
3815
+ this.paths[name] = paths[name].toPath?.() ?? paths[name];
3816
+ }
3817
+ }
3818
+ lookupPath(name) {
3819
+ return this.paths[name] ?? this.parent?.lookupPath(name) ?? null;
3820
+ }
3489
3821
  registerMacros(macros) {
3490
3822
  for (const key in macros) {
3491
3823
  const lower = key.toLowerCase();
@@ -3517,17 +3849,16 @@ var init_components = __esm({
3517
3849
  lookupComponent(name) {
3518
3850
  return this.byName[name] ?? this.parent?.lookupComponent(name) ?? null;
3519
3851
  }
3520
- // The component in this scope chain that provides `name`, innermost first. A lookup
3521
- // names a value without naming its producer, so the render-target teleport
3522
- // (resolveDynProducer) recovers the producer here instead. Sound because
3523
- // PROVIDE_NAME_COLLISION keeps a provide name to one producer per chain; with two,
3524
- // this returns the innermost and the linter has already reported the ambiguity.
3525
- lookupProvider(name) {
3852
+ // Whether anything in this scope chain provides `name`. Existence only: a lookup
3853
+ // names what it WANTS and takes whoever is nearest above it at render time, so
3854
+ // there is no producer to identify several components may publish one name and
3855
+ // the live render ancestry decides. Used by the linter to tell a lookup that can
3856
+ // be satisfied from one that never will be.
3857
+ hasProvider(name) {
3526
3858
  for (const compName in this.byName) {
3527
- const Comp = this.byName[compName];
3528
- if (Comp.provide?.[name] !== void 0) return Comp;
3859
+ if (this.byName[compName].provide?.[name] !== void 0) return true;
3529
3860
  }
3530
- return this.parent?.lookupProvider(name) ?? null;
3861
+ return this.parent?.hasProvider(name) ?? false;
3531
3862
  }
3532
3863
  lookupMacro(name) {
3533
3864
  return this.macros[name] ?? this.parent?.lookupMacro(name) ?? null;
@@ -3544,10 +3875,6 @@ var init_components = __esm({
3544
3875
  }
3545
3876
  };
3546
3877
  isString = (v) => typeof v === "string";
3547
- isTypeName = (s) => {
3548
- const c = s.charCodeAt(0);
3549
- return c >= 65 && c <= 90;
3550
- };
3551
3878
  _rawSpecKeys = "name view style commonStyle globalStyle receive intent alter views provide lookup fields methods statics";
3552
3879
  KNOWN_SPEC_KEYS = new Set(_rawSpecKeys.split(" "));
3553
3880
  _compId = 0;
@@ -5958,7 +6285,6 @@ function checkComponent(Comp, lx = new LintContext(), { wellKnownExtras = EMPTY_
5958
6285
  checkFieldMethodNameCollisions(lx, Comp);
5959
6286
  checkProvidesAreAddressable(lx, Comp);
5960
6287
  checkProvidedTypes(lx, Comp);
5961
- checkProvideNameCollisions(lx, Comp);
5962
6288
  checkLookupShapes(lx, Comp);
5963
6289
  checkLookupTypesResolve(lx, Comp);
5964
6290
  checkLookupsHaveProviders(lx, Comp);
@@ -6533,19 +6859,6 @@ function checkProvidedTypes(lx, Comp) {
6533
6859
  if (raw !== "self") lx.error(PROVIDE_TYPE_BAD_SHAPE, { name, value: raw });
6534
6860
  }
6535
6861
  }
6536
- function checkProvideNameCollisions(lx, Comp) {
6537
- const scope = Comp.scope;
6538
- if (!scope) return;
6539
- for (const name in Comp.provide) {
6540
- for (let s = scope; s; s = s.parent) {
6541
- for (const otherName in s.byName) {
6542
- const Other = s.byName[otherName];
6543
- if (Other !== Comp && Other.provide?.[name] !== void 0)
6544
- lx.error(PROVIDE_NAME_COLLISION, { name, other: Other.name });
6545
- }
6546
- }
6547
- }
6548
- }
6549
6862
  function checkLookupShapes(lx, Comp) {
6550
6863
  const raw = Comp._rawLookup;
6551
6864
  if (!Array.isArray(raw)) {
@@ -6586,7 +6899,7 @@ function checkLookupsHaveProviders(lx, Comp) {
6586
6899
  if (!scope) return;
6587
6900
  for (const name in Comp.lookup) {
6588
6901
  if (isTypeName2(name)) continue;
6589
- if (scope.lookupProvider?.(name)) continue;
6902
+ if (scope.hasProvider?.(name) || scope.lookupPath?.(name)) continue;
6590
6903
  const info = { name, hasDefault: Comp.lookup[name].val != null };
6591
6904
  if (info.hasDefault) lx.hint(LOOKUP_NO_PROVIDER, info);
6592
6905
  else lx.error(LOOKUP_NO_PROVIDER, info);
@@ -6608,7 +6921,7 @@ function checkUnreferencedDynamics(lx, Comp, referencedDynamics) {
6608
6921
  }
6609
6922
  }
6610
6923
  }
6611
- 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;
6924
+ 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, 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;
6612
6925
  var init_lint_check = __esm({
6613
6926
  "tools/core/lint-check.js"() {
6614
6927
  init_anode();
@@ -6646,7 +6959,6 @@ var init_lint_check = __esm({
6646
6959
  DYN_ALIAS_NOT_REFERENCED = "DYN_ALIAS_NOT_REFERENCED";
6647
6960
  PROVIDE_NOT_ADDRESSABLE = "PROVIDE_NOT_ADDRESSABLE";
6648
6961
  PROVIDE_TYPE_BAD_SHAPE = "PROVIDE_TYPE_BAD_SHAPE";
6649
- PROVIDE_NAME_COLLISION = "PROVIDE_NAME_COLLISION";
6650
6962
  LOOKUP_BAD_SHAPE = "LOOKUP_BAD_SHAPE";
6651
6963
  LOOKUP_NO_PROVIDER = "LOOKUP_NO_PROVIDER";
6652
6964
  RENDER_IT_OUTSIDE_OF_LOOP = "RENDER_IT_OUTSIDE_OF_LOOP";
@@ -6974,7 +7286,7 @@ var init_lint_rules = __esm({
6974
7286
  code: LOOKUP_NO_PROVIDER,
6975
7287
  level: "error",
6976
7288
  group: "Dynamic bindings",
6977
- summary: "`lookup` name is provided by no component in scope."
7289
+ summary: "`lookup` name is neither provided in scope nor a registered path."
6978
7290
  },
6979
7291
  {
6980
7292
  code: PROVIDE_TYPE_BAD_SHAPE,
@@ -6982,12 +7294,6 @@ var init_lint_rules = __esm({
6982
7294
  group: "Dynamic bindings",
6983
7295
  summary: 'A PascalCase `provide` publishes a component type; its value must be `"self"`.'
6984
7296
  },
6985
- {
6986
- code: PROVIDE_NAME_COLLISION,
6987
- level: "error",
6988
- group: "Dynamic bindings",
6989
- summary: "Two components in one scope chain `provide` the same name."
6990
- },
6991
7297
  // Templates / events
6992
7298
  {
6993
7299
  code: RENDER_IT_OUTSIDE_OF_LOOP,
@@ -7276,15 +7582,13 @@ function lintIdToMessage(id, info) {
7276
7582
  case "DYN_ALIAS_NOT_REFERENCED":
7277
7583
  return `Lookup '${info.name}' is defined but never used — remove it or reference it as '*${info.name}' in a view`;
7278
7584
  case "PROVIDE_NOT_ADDRESSABLE":
7279
- 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`;
7585
+ 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`;
7280
7586
  case "LOOKUP_BAD_SHAPE":
7281
7587
  return `Lookup '${info.name}' has an invalid shape: ${info.problem}`;
7282
7588
  case "LOOKUP_NO_PROVIDER":
7283
- 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`;
7589
+ 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`;
7284
7590
  case "PROVIDE_TYPE_BAD_SHAPE":
7285
7591
  return `Provide '${info.name}' starts uppercase, so it publishes a component type — its value must be 'self', not '${info.value}'`;
7286
- case "PROVIDE_NAME_COLLISION":
7287
- return `Provide '${info.name}' is also provided by '${info.other}' in the same scope — one name, one provider, so a lookup can find it`;
7288
7592
  case "UNKNOWN_MACRO_ARG":
7289
7593
  return `Argument '${info.name}' is not declared in macro '${info.macroName}'`;
7290
7594
  case "UNKNOWN_DIRECTIVE":
@@ -12759,165 +13063,6 @@ var init_list = __esm({
12759
13063
  }
12760
13064
  });
12761
13065
 
12762
- // src/stack.js
12763
- function routeLookup(route, lex, dyn) {
12764
- for (let i = 0; i < route.length; i++) {
12765
- const leg = route[i];
12766
- if (leg === "dyn") {
12767
- const v = dyn();
12768
- if (v != null) return v;
12769
- } else if (leg === "lex") {
12770
- const v = lex();
12771
- if (v != null) return v;
12772
- } else {
12773
- console.warn("unknown lookup route leg", leg, '- expected "dyn" or "lex"');
12774
- }
12775
- }
12776
- return null;
12777
- }
12778
- function lookup(chain, name, dv = null) {
12779
- let n = chain;
12780
- while (n !== null) {
12781
- const r = n[0].lookup(name);
12782
- if (r === STOP) return dv;
12783
- if (r !== NEXT) return r;
12784
- n = n[1];
12785
- }
12786
- return dv;
12787
- }
12788
- function computeViewsId(views) {
12789
- let s = "";
12790
- let n = views;
12791
- while (n !== null) {
12792
- s += n[0];
12793
- n = n[1];
12794
- }
12795
- return s === "main" ? "" : s;
12796
- }
12797
- var STOP, NEXT, DEFAULT_ROUTE, BindFrame, ObjectFrame, Stack;
12798
- var init_stack = __esm({
12799
- "src/stack.js"() {
12800
- STOP = /* @__PURE__ */ Symbol("STOP");
12801
- NEXT = /* @__PURE__ */ Symbol("NEXT");
12802
- DEFAULT_ROUTE = ["dyn", "lex"];
12803
- BindFrame = class {
12804
- constructor(it, binds, isFrame) {
12805
- this.it = it;
12806
- this.binds = binds;
12807
- this.isFrame = isFrame;
12808
- }
12809
- lookup(name) {
12810
- const v = this.binds[name];
12811
- return v === void 0 ? this.isFrame ? STOP : NEXT : v;
12812
- }
12813
- };
12814
- ObjectFrame = class {
12815
- constructor(binds) {
12816
- this.binds = binds;
12817
- }
12818
- lookup(key) {
12819
- const v = this.binds[key];
12820
- return v === void 0 ? NEXT : v;
12821
- }
12822
- };
12823
- Stack = class _Stack {
12824
- constructor(comps, it, binds, dynBinds, views, viewsId, ctx = null) {
12825
- this.comps = comps;
12826
- this.it = it;
12827
- this.binds = binds;
12828
- this.dynBinds = dynBinds;
12829
- this.views = views;
12830
- this.viewsId = viewsId;
12831
- this.ctx = ctx;
12832
- }
12833
- // Evaluate every provide the entered component publishes and push them as one
12834
- // dynBinds frame, keyed by NAME. Published types go in the same frame: a type name
12835
- // starts A-Z and a value name does not, so the two namespaces cannot collide and
12836
- // nearest-ancestor-wins falls out of frame order for both. No-op with no provides.
12837
- _pushProvides() {
12838
- const comp = this.comps.getCompFor(this.it);
12839
- if (comp == null) return this;
12840
- const { provide, provideType } = comp;
12841
- const dynObj = {};
12842
- let has2 = false;
12843
- for (const k in provide) {
12844
- dynObj[k] = provide[k].val.eval(this);
12845
- has2 = true;
12846
- }
12847
- for (const k in provideType) {
12848
- dynObj[k] = provideType[k];
12849
- has2 = true;
12850
- }
12851
- if (!has2) return this;
12852
- const newDynBinds = [new ObjectFrame(dynObj), this.dynBinds];
12853
- const { comps, it, binds, views, viewsId, ctx } = this;
12854
- return new _Stack(comps, it, binds, newDynBinds, views, viewsId, ctx);
12855
- }
12856
- static root(comps, it, ctx) {
12857
- const binds = [new BindFrame(it, {}, true), null];
12858
- const dynBinds = [new ObjectFrame({}), null];
12859
- const views = ["main", null];
12860
- return new _Stack(comps, it, binds, dynBinds, views, "", ctx)._pushProvides();
12861
- }
12862
- enter(it, bindings = {}, isFrame = true) {
12863
- const { comps, binds, dynBinds, views, viewsId, ctx } = this;
12864
- const newBinds = [new BindFrame(it, bindings, isFrame), binds];
12865
- const stack = new _Stack(comps, it, newBinds, dynBinds, views, viewsId, ctx);
12866
- return isFrame ? stack._pushProvides() : stack;
12867
- }
12868
- pushViewName(name) {
12869
- const { comps, it, binds, dynBinds, views, ctx } = this;
12870
- const newViews = [name, views];
12871
- return new _Stack(comps, it, binds, dynBinds, newViews, computeViewsId(newViews), ctx);
12872
- }
12873
- // Published types are stable per scope and would only churn the render cache, so
12874
- // the cache key covers values alone.
12875
- _pushDynBindValuesToArray(arr, comp) {
12876
- for (const k in comp.provide) arr.push(this.lookupDynamic(k));
12877
- for (const k in comp.lookup) arr.push(this.lookupDynamic(k));
12878
- }
12879
- // `*name`: the nearest binding above (including this component's own provides,
12880
- // pushed on entering it), else this component's declared default, else null.
12881
- lookupDynamic(name) {
12882
- const v = lookup(this.dynBinds, name);
12883
- if (v != null) return v;
12884
- const comp = this.comps.getCompFor(this.it);
12885
- return comp?.lookup[name]?.val?.eval(this) ?? null;
12886
- }
12887
- lookupBind(name) {
12888
- return lookup(this.binds, name);
12889
- }
12890
- lookupFieldRaw(name) {
12891
- return this.it[name] ?? null;
12892
- }
12893
- lookupMethod(name) {
12894
- const fn = this.it[name];
12895
- return fn instanceof Function ? fn.call(this.it) : null;
12896
- }
12897
- // The dispatched DOM event / drag info, read only by EventMemberVal's
12898
- // `e.<member>` handler args. Null outside a live event transaction.
12899
- lookupEvent() {
12900
- return this.ctx?.event ?? null;
12901
- }
12902
- lookupDragInfo() {
12903
- return this.ctx?.dragInfo ?? null;
12904
- }
12905
- getHandlerFor(name, key) {
12906
- return this.comps.getHandlerFor(this.it, name, key);
12907
- }
12908
- lookupBestView(views, defaultViewName) {
12909
- let n = this.views;
12910
- while (n !== null) {
12911
- const view = views[n[0]];
12912
- if (view !== void 0) return view;
12913
- n = n[1];
12914
- }
12915
- return views[defaultViewName];
12916
- }
12917
- };
12918
- }
12919
- });
12920
-
12921
13066
  // src/oo.js
12922
13067
  function mkCompField(field, scope, args) {
12923
13068
  const Comp = scope?.lookupComponent(field.type) ?? null;
@@ -13203,7 +13348,7 @@ function warnNotIntent(verb) {
13203
13348
  console.warn(`ctx.${verb}() is only meaningful in an "intent" handler - ignored`);
13204
13349
  }
13205
13350
  function rootDispatcher(transactor) {
13206
- return new Dispatcher(new Path([]), transactor, null);
13351
+ return new Dispatcher(new DispatchPath(), transactor, null);
13207
13352
  }
13208
13353
  var State2, Transactor, Transaction, InputEvent, NameArgsTransaction, SendEvent, IntentEvent, PASS, REFUSAL_RING_CAP, INTENT_DEPTH, IntentWalk, Completion, Dispatcher, EventContext, PathChanges;
13209
13354
  var init_transactor = __esm({
@@ -13340,9 +13485,11 @@ var init_transactor = __esm({
13340
13485
  // intent's answerPath is: a reply must reach the sender that asked even if a key
13341
13486
  // moved while the message was in flight. Null when nobody is waiting — a host
13342
13487
  // sendAtRoot or a view's own `@on.*` — and ctx.sendReply refuses on that.
13343
- pushSend(path, name, args = [], parent = null, origin = null) {
13488
+ pushSend(path, name, args = [], parent = null, origin = null, txnPath = null) {
13344
13489
  const t = new SendEvent(path, this, name, args, parent);
13345
- t.origin = origin === null ? null : origin.toTransactionPath().pinKeys(this.state.val);
13490
+ t.txnPath = txnPath;
13491
+ t.origin = origin;
13492
+ t.originPinned = origin === null ? null : origin.toTransactionPath().pinKeys(this.state.val);
13346
13493
  this.pushTransaction(t);
13347
13494
  return this._link(t, parent);
13348
13495
  }
@@ -13392,6 +13539,7 @@ var init_transactor = __esm({
13392
13539
  Transaction = class {
13393
13540
  constructor(path, transactor, parentTransaction = null) {
13394
13541
  this.path = path;
13542
+ this.txnPath = null;
13395
13543
  this.transactor = transactor;
13396
13544
  this.parentTransaction = parentTransaction;
13397
13545
  this._completion = null;
@@ -13440,9 +13588,11 @@ var init_transactor = __esm({
13440
13588
  getHandlerAndArgs(_root, _instance, _comps) {
13441
13589
  return null;
13442
13590
  }
13443
- // The path used to apply the mutation. Teleports dynamic-var renders so it lands on
13444
- // the data's real location (the dispatch `this.path` keeps intermediates).
13591
+ // The path used to apply the mutation: the ACTIVE frame of the dispatch path, so
13592
+ // an event inside a `<x render="*name">` subtree updates the value where it
13593
+ // really lives (the dispatch `this.path` keeps the visual callers, for bubbling).
13445
13594
  getTransactionPath() {
13595
+ if (this.txnPath !== null) return this.txnPath;
13446
13596
  return this.path.toTransactionPath().compact();
13447
13597
  }
13448
13598
  run(curRoot, comps) {
@@ -13467,8 +13617,9 @@ var init_transactor = __esm({
13467
13617
  this.dragInfo = dragInfo;
13468
13618
  this._dispatchPath = null;
13469
13619
  }
13470
- // Frame steps removed, DynStep + one step per crossed component kept: bubbling
13471
- // it visits every component (including intermediates of a dynamic-var render).
13620
+ // Frame-only steps removed, one step per crossed component kept — inside every
13621
+ // continuation frame independently, so bubbling it visits every component and
13622
+ // then returns to the caller that wrote the `*name`.
13472
13623
  get dispatchPath() {
13473
13624
  this._dispatchPath ??= this.path.compact();
13474
13625
  return this._dispatchPath;
@@ -13503,7 +13654,7 @@ var init_transactor = __esm({
13503
13654
  this.transactor.pushIntent(this.dispatchPath, name, args, rest, this);
13504
13655
  }
13505
13656
  getHandlerAndArgs(root, _instance, comps) {
13506
- const stack = this.path.toTransactionPath().buildStack(Stack.root(comps, root, this));
13657
+ const stack = this.path.buildStack(Stack.root(comps, root, this));
13507
13658
  const [handler, args] = this.handler.getHandlerAndArgs(stack, this);
13508
13659
  this._handlerArgs = [...args];
13509
13660
  const path = this.dispatchPath;
@@ -13629,7 +13780,7 @@ var init_transactor = __esm({
13629
13780
  while (this.legIndex < this.route.length) {
13630
13781
  const leg = this.route[this.legIndex];
13631
13782
  if (leg === "dyn") {
13632
- if (this.dynAt.steps.length === 0) {
13783
+ if (!this.dynAt.canPop()) {
13633
13784
  this.legIndex++;
13634
13785
  continue;
13635
13786
  }
@@ -13726,8 +13877,8 @@ var init_transactor = __esm({
13726
13877
  if (this.ended) return;
13727
13878
  this.ended = true;
13728
13879
  if (name === null) return this.release?.();
13729
- const path = this.answerPath ?? this.origin;
13730
- const t = new SendEvent(path, this.transactor, name, args, this.parent);
13880
+ const t = new SendEvent(this.origin, this.transactor, name, args, this.parent);
13881
+ t.txnPath = this.answerPath;
13731
13882
  t._isAnswer = true;
13732
13883
  this.transactor.pushTransaction(t);
13733
13884
  if (this.release) t.completion.whenSubtreeSettled().then(this.release);
@@ -13822,7 +13973,9 @@ var init_transactor = __esm({
13822
13973
  // replayed; provides are pushed on every component frame either way, so a provide
13823
13974
  // that reads a loop binding is the one case this cannot reproduce faithfully.
13824
13975
  _stack() {
13825
- this._stackMemo ??= this.path.toTransactionPath().buildStack(Stack.root(this.transactor.comps, this.root, this.parent));
13976
+ this._stackMemo ??= this.path.buildStack(
13977
+ Stack.root(this.transactor.comps, this.root, this.parent)
13978
+ );
13826
13979
  return this._stackMemo;
13827
13980
  }
13828
13981
  // Resolve a name the way the renderer would. `opts.route` takes the same legs in
@@ -13836,14 +13989,19 @@ var init_transactor = __esm({
13836
13989
  );
13837
13990
  }
13838
13991
  // The `lex` leg without a Stack: the scope of the component whose handler is
13839
- // running, which is the leaf of this ctx's path.
13992
+ // running, which is the leaf of this ctx's path. A type name resolves to the
13993
+ // component registered under it; a value name to a path registered under it
13994
+ // (see ComponentStack.registerPaths), read against the current root.
13840
13995
  _lookupLex(name) {
13841
13996
  let Comp = null;
13842
13997
  this.walkPath((c) => {
13843
13998
  Comp = c;
13844
13999
  return false;
13845
14000
  });
13846
- return Comp?.scope?.lookupComponent(name) ?? null;
14001
+ const scope = Comp?.scope;
14002
+ if (scope == null) return null;
14003
+ if (isTypeName(name)) return scope.lookupComponent(name) ?? null;
14004
+ return scope.lookupPath(name)?.lookup(this.root) ?? null;
13847
14005
  }
13848
14006
  // A component lookup is a value lookup constrained to a component. The `lex` leg
13849
14007
  // can only ever answer with one; the `dyn` leg reads a binding an ancestor
@@ -13904,7 +14062,14 @@ var init_transactor = __esm({
13904
14062
  this.transactor.refuse("NO_SENDER", { name });
13905
14063
  return null;
13906
14064
  }
13907
- return this.sendAtPath(origin, name, args);
14065
+ return this.transactor.pushSend(
14066
+ origin,
14067
+ name,
14068
+ args,
14069
+ this.parent,
14070
+ this.path,
14071
+ this.parent.originPinned
14072
+ );
13908
14073
  }
13909
14074
  // End the walk answering nothing — "served, and no answer".
13910
14075
  stop() {
@@ -14015,7 +14180,7 @@ var init_app = __esm({
14015
14180
  const { type: type3 } = e;
14016
14181
  const isDrag = type3 === "dragover" || type3 === "dragstart" || type3 === "dragend" || type3 === "drop";
14017
14182
  const { rootNode: root, maxEventNodeDepth: maxDepth, comps, transactor } = this;
14018
- const [path, handlers] = Path.fromNodeAndEventName(
14183
+ const [path, handlers] = DispatchPath.fromNodeAndEventName(
14019
14184
  e.target,
14020
14185
  type3,
14021
14186
  root,
@@ -14083,7 +14248,7 @@ var init_app = __esm({
14083
14248
  const txnPath = path.compact().toTransactionPath();
14084
14249
  const value = txnPath.lookup(rootValue);
14085
14250
  const dragType = e.target.dataset.dragtype ?? "?";
14086
- const stack = path.toTransactionPath().buildStack(this.makeStack(rootValue));
14251
+ const stack = path.buildStack(this.makeStack(rootValue));
14087
14252
  this.dragInfo = new DragInfo(stack, value, dragType, e.target);
14088
14253
  } else if (type3 === "drop") {
14089
14254
  e.preventDefault();
@@ -14158,7 +14323,7 @@ var init_app = __esm({
14158
14323
  this.rootNode.removeEventListener(name, this, listenerOpts(name));
14159
14324
  }
14160
14325
  sendAtRoot(name, args) {
14161
- this.transactor.pushSend(new Path([]), name, args);
14326
+ this.transactor.pushSend(new DispatchPath(), name, args);
14162
14327
  }
14163
14328
  registerComponents(comps, opts) {
14164
14329
  const scope = this.compStack.enter();
@@ -14302,13 +14467,28 @@ var init_cache = __esm({
14302
14467
  });
14303
14468
 
14304
14469
  // src/renderer.js
14470
+ function stampRenderBase(vdom, text) {
14471
+ if (vdom instanceof VNode)
14472
+ return new VNode(
14473
+ vdom.tag,
14474
+ { ...vdom.attrs, "data-rp": text },
14475
+ vdom.childs,
14476
+ vdom.key,
14477
+ vdom.namespace
14478
+ );
14479
+ if (vdom instanceof VFragment)
14480
+ return new VFragment(vdom.childs.map((c) => stampRenderBase(c, text)));
14481
+ return vdom;
14482
+ }
14305
14483
  var DATASET_ATTRS, Renderer;
14306
14484
  var init_renderer = __esm({
14307
14485
  "src/renderer.js"() {
14308
14486
  init_cache();
14309
14487
  init_iteration();
14488
+ init_path();
14489
+ init_value();
14310
14490
  init_vdom();
14311
- DATASET_ATTRS = ["nid", "cid", "eid", "vid", "si", "sk"];
14491
+ DATASET_ATTRS = ["nid", "cid", "eid", "vid", "si", "sk", "rp"];
14312
14492
  Renderer = class {
14313
14493
  constructor(comps) {
14314
14494
  this.comps = comps;
@@ -14345,17 +14525,17 @@ var init_renderer = __esm({
14345
14525
  if (comp === null) return null;
14346
14526
  return this._rValComp(stack, val, comp, comp.getView(viewName).anode, "ROOT", viewName);
14347
14527
  }
14348
- renderIt(stack, node, key, viewName) {
14528
+ renderIt(stack, node, key, viewName, base = null) {
14349
14529
  const comp = this.comps.getCompFor(stack.it);
14350
- return comp ? this._rValComp(stack, stack.it, comp, node, key, viewName) : null;
14530
+ return comp ? this._rValComp(stack, stack.it, comp, node, key, viewName, base) : null;
14351
14531
  }
14352
14532
  // `node` is the parse node of the render site (`<x render>` / `render-it` /
14353
14533
  // `render-each`, or the view's root anode for the app root). It keys the
14354
14534
  // cache as a globally-unique object: node ids alone are unique only within a
14355
14535
  // single view, so the same value rendered by two components (e.g. through a
14356
14536
  // shared dynamic-var sequence) would otherwise collide in the cache.
14357
- _rValComp(stack, val, comp, node, key, viewName) {
14358
- const cacheKey = `${viewName ?? ""}${stack.viewsId ?? ""}${key}`;
14537
+ _rValComp(stack, val, comp, node, key, viewName, base = null) {
14538
+ const cacheKey = `${viewName ?? ""}${stack.viewsId ?? ""}${key}${stack.renderPath.addressKey}`;
14359
14539
  const cachePath = [node, val];
14360
14540
  stack._pushDynBindValuesToArray(cachePath, comp);
14361
14541
  const cachedNode = this.cache.get(cachePath, cacheKey);
@@ -14363,30 +14543,43 @@ var init_renderer = __esm({
14363
14543
  const view = viewName ? comp.getView(viewName) : stack.lookupBestView(comp.views, "main");
14364
14544
  const body = this.renderView(view, stack);
14365
14545
  if (body == null) return null;
14546
+ const baseJson = base === null ? null : pathToJson(base);
14366
14547
  const meta = this._renderMetadata({
14367
14548
  $: "Comp",
14368
14549
  nid: node?.nodeId ?? null,
14369
14550
  cid: comp.id,
14370
- vid: view.name
14551
+ vid: view.name,
14552
+ ...baseJson === null ? null : { base: baseJson }
14371
14553
  });
14372
- const dom = new VFragment([meta, body]);
14554
+ const dom = new VFragment([
14555
+ meta,
14556
+ baseJson === null ? body : stampRenderBase(body, JSON.stringify(baseJson))
14557
+ ]);
14373
14558
  this.cache.set(cachePath, cacheKey, dom);
14374
14559
  return dom;
14375
14560
  }
14376
14561
  pushEachEntry(r, nid, attrName, key, dom) {
14377
14562
  r.push(this._renderMetadata({ $: "Each", nid, [attrName]: key }), dom);
14378
14563
  }
14379
- renderEachWhen(stack, iterInfo, view, nid) {
14564
+ renderEachWhen(stack, each2) {
14565
+ const { iterInfo, node: view, nodeId: nid } = each2;
14380
14566
  const { seq, filter, loopWith, enricher } = iterInfo.eval(stack);
14567
+ const seqPath = iterInfo.val instanceof DynVal ? stack.lookupDynamicLocated(iterInfo.val.name)?.path ?? null : null;
14381
14568
  const r = [];
14382
14569
  const it = stack.it;
14383
14570
  const renderOne = (key, value, attrName, binds) => {
14571
+ const itemBase = seqPath === null ? null : keyedPath(seqPath, key);
14572
+ const itemStep = itemBase === null ? each2.itemStep(key) : null;
14573
+ const itemPath = itemBase !== null ? stack.renderPath.pushFrame(itemBase) : itemStep !== null ? stack.renderPath.pushItem(itemStep) : stack.renderPath;
14384
14574
  const cachePath = enricher ? [view, it, value] : [view, value];
14385
- const cacheKey = `${stack.viewsId ?? ""}${nid}${key}`;
14575
+ const cacheKey = `${stack.viewsId ?? ""}${nid}${key}${itemPath.addressKey}`;
14386
14576
  const cachedNode = this.cache.get(cachePath, cacheKey);
14387
14577
  if (cachedNode) this.pushEachEntry(r, nid, attrName, key, cachedNode);
14388
14578
  else {
14389
- const dom = this.renderView(view, stack.enter(value, binds, false));
14579
+ const dom = this.renderView(
14580
+ view,
14581
+ stack.enter(value, binds, false, itemPath, itemBase !== null)
14582
+ );
14390
14583
  if (dom != null) this.pushEachEntry(r, nid, attrName, key, dom);
14391
14584
  this.cache.set(cachePath, cacheKey, dom);
14392
14585
  }
@@ -14442,7 +14635,7 @@ function renderToHTMLNode(document2, components, macros, rootState, ParseContext
14442
14635
  const comps = new Components();
14443
14636
  const renderer = new Renderer(comps);
14444
14637
  const app = new App(container, comps, renderer, ParseContext2);
14445
- const scope = app.registerComponents(components);
14638
+ const scope = app.registerComponents(components, { paths: opts.paths });
14446
14639
  if (macros) scope.registerMacros(macros);
14447
14640
  if (opts.intentHandlers) scope.registerIntentHandlers(opts.intentHandlers);
14448
14641
  app.rootViewName = opts.view ?? null;
@@ -14468,7 +14661,7 @@ async function renderToHTMLDriven(document2, components, macros, rootState, Pars
14468
14661
  );
14469
14662
  try {
14470
14663
  if (phase) {
14471
- dispatchPhase(rootDispatcher(app.transactor), new Path([]), phase, app.state.val);
14664
+ dispatchPhase(rootDispatcher(app.transactor), new DispatchPath(), phase, app.state.val);
14472
14665
  await app.transactor.settle();
14473
14666
  }
14474
14667
  return serializeContainer(container);
@@ -14706,7 +14899,7 @@ async function driveStack(stack, value, phase, opts = {}) {
14706
14899
  val
14707
14900
  );
14708
14901
  });
14709
- dispatchPhase(rootDispatcher(transactor), new Path([]), phase, value);
14902
+ dispatchPhase(rootDispatcher(transactor), new DispatchPath(), phase, value);
14710
14903
  await transactor.settle();
14711
14904
  return transactor.state.val;
14712
14905
  }