tutuca 0.13.3 → 0.15.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;
@@ -4954,12 +4954,6 @@ var produce = immer.produce;
4954
4954
 
4955
4955
  // src/path.js
4956
4956
  var NONE = /* @__PURE__ */ Symbol("NONE");
4957
- var readKey = (value, key, dval = null) => {
4958
- if (value == null) return dval;
4959
- if (value instanceof Map) return value.has(key) ? value.get(key) : dval;
4960
- if (value instanceof Set) return value.has(key) ? key : dval;
4961
- return Object.hasOwn(value, key) ? value[key] : dval;
4962
- };
4963
4957
  var writeKey = (value, key, next) => {
4964
4958
  if (value instanceof Map) value.set(key, next);
4965
4959
  else if (value instanceof Set) {
@@ -4967,20 +4961,15 @@ var writeKey = (value, key, next) => {
4967
4961
  value.add(next);
4968
4962
  } else value[key] = next;
4969
4963
  };
4970
- var writeSeqKey = (value, key, next) => {
4971
- if (value instanceof Map || value instanceof Set || Array.isArray(value) || Object.hasOwn(value, key))
4972
- writeKey(value, key, next);
4973
- else if (typeof value?.set === "function") value.set(key, next);
4974
- else writeKey(value, key, next);
4975
- };
4964
+ var writeSeqKey = (value, key, next) => !(value instanceof Map || value instanceof Set || Array.isArray(value)) && !Object.hasOwn(value, key) && typeof value?.set === "function" ? value.set(key, next) : writeKey(value, key, next);
4976
4965
  var Step = class {
4977
- lookup(_v, dval = null) {
4978
- return dval;
4979
- }
4980
4966
  setDraftValue(_root, _v) {
4981
4967
  }
4982
- enterFrame(stack, next) {
4983
- return stack.enter(next, {}, true);
4968
+ // Re-enter this step while rebuilding a stack. `renderPath` is the dispatch
4969
+ // position AFTER this step: a rebuilt frame must carry the same render path
4970
+ // the renderer had there, or the provides it publishes would be located wrong.
4971
+ enterFrame(stack, next, renderPath) {
4972
+ return stack.enter(next, {}, true, renderPath);
4984
4973
  }
4985
4974
  toAbstractPathStep() {
4986
4975
  return this;
@@ -4997,41 +4986,29 @@ var Step = class {
4997
4986
  return null;
4998
4987
  }
4999
4988
  };
5000
- var BindStep = class _BindStep extends Step {
4989
+ var BindStep = class extends Step {
5001
4990
  constructor(binds) {
5002
4991
  super();
5003
4992
  this.binds = binds;
5004
4993
  }
5005
- lookup(v, _dval) {
4994
+ lookup(v) {
5006
4995
  return v;
5007
4996
  }
5008
- enterFrame(stack, next) {
5009
- return stack.enter(next, { ...this.binds }, false);
5010
- }
5011
- withIndex(i) {
5012
- return new _BindStep({ ...this.binds, key: i });
5013
- }
5014
- withKey(key) {
5015
- return new _BindStep({ ...this.binds, key });
4997
+ enterFrame(stack, next, renderPath) {
4998
+ return stack.enter(next, { ...this.binds }, false, renderPath);
5016
4999
  }
5017
5000
  toAbstractPathStep() {
5018
5001
  return null;
5019
5002
  }
5020
5003
  };
5021
- var ScopeBindStep = class _ScopeBindStep extends BindStep {
5004
+ var ScopeBindStep = class extends BindStep {
5022
5005
  constructor(val, binds = {}) {
5023
5006
  super(binds);
5024
5007
  this.val = val;
5025
5008
  }
5026
- enterFrame(stack, next) {
5009
+ enterFrame(stack, next, renderPath) {
5027
5010
  const dyn = this.val.evalAsHandler(stack)?.call(stack.it) ?? {};
5028
- return stack.enter(next, { ...this.binds, ...dyn }, false);
5029
- }
5030
- withIndex(i) {
5031
- return new _ScopeBindStep(this.val, { ...this.binds, key: i });
5032
- }
5033
- withKey(key) {
5034
- return new _ScopeBindStep(this.val, { ...this.binds, key });
5011
+ return stack.enter(next, { ...this.binds, ...dyn }, false, renderPath);
5035
5012
  }
5036
5013
  };
5037
5014
  var FieldStep = class extends Step {
@@ -5039,18 +5016,12 @@ var FieldStep = class extends Step {
5039
5016
  super();
5040
5017
  this.field = field;
5041
5018
  }
5042
- lookup(v, dval = null) {
5043
- return readKey(v, this.field, dval);
5019
+ lookup(v) {
5020
+ return seqGet(v, this.field, NONE);
5044
5021
  }
5045
5022
  setDraftValue(root, v) {
5046
5023
  writeKey(root, this.field, v);
5047
5024
  }
5048
- withIndex(i) {
5049
- return new SeqStep(this.field, i);
5050
- }
5051
- withKey(k) {
5052
- return new SeqStep(this.field, k);
5053
- }
5054
5025
  toKey() {
5055
5026
  return { field: this.field };
5056
5027
  }
@@ -5061,15 +5032,15 @@ var SeqStep = class extends Step {
5061
5032
  this.field = field;
5062
5033
  this.key = key;
5063
5034
  }
5064
- lookup(v, dval = null) {
5065
- return seqGet(readKey(v, this.field, null), this.key, dval);
5035
+ lookup(v) {
5036
+ return seqGet(seqGet(v, this.field, null), this.key, NONE);
5066
5037
  }
5067
5038
  setDraftValue(root, v) {
5068
- const seq = readKey(root, this.field, null);
5039
+ const seq = seqGet(root, this.field, null);
5069
5040
  if (seq != null) writeSeqKey(seq, this.key, v);
5070
5041
  }
5071
- enterFrame(stack, next) {
5072
- return stack.enter(next, { key: this.key }, true);
5042
+ enterFrame(stack, next, renderPath) {
5043
+ return stack.enter(next, { key: this.key }, true, renderPath);
5073
5044
  }
5074
5045
  toKey() {
5075
5046
  return { field: this.field, key: this.key };
@@ -5081,20 +5052,20 @@ var SeqAccessStep = class extends Step {
5081
5052
  this.seqField = seqField;
5082
5053
  this.keyField = keyField;
5083
5054
  }
5084
- lookup(v, dval = null) {
5085
- const seq = readKey(v, this.seqField, NONE);
5086
- const key = readKey(v, this.keyField, NONE);
5087
- return key !== NONE && seq !== NONE ? seqGet(seq, key, dval) : dval;
5055
+ lookup(v) {
5056
+ const seq = seqGet(v, this.seqField, NONE);
5057
+ const key = seqGet(v, this.keyField, NONE);
5058
+ return key !== NONE && seq !== NONE ? seqGet(seq, key, NONE) : NONE;
5088
5059
  }
5089
5060
  setDraftValue(root, v) {
5090
- const seq = readKey(root, this.seqField, NONE);
5091
- const key = readKey(root, this.keyField, NONE);
5061
+ const seq = seqGet(root, this.seqField, NONE);
5062
+ const key = seqGet(root, this.keyField, NONE);
5092
5063
  if (seq !== NONE && key !== NONE) writeSeqKey(seq, key, v);
5093
5064
  }
5094
5065
  // Resolve `keyField` against `v` now and freeze it as a literal-key `SeqStep`, so a
5095
5066
  // later lookup/setValue lands on this same item even if `keyField` changes meanwhile.
5096
5067
  pinKey(v) {
5097
- const key = readKey(v, this.keyField, NONE);
5068
+ const key = seqGet(v, this.keyField, NONE);
5098
5069
  return key === NONE ? this : new SeqStep(this.seqField, key);
5099
5070
  }
5100
5071
  // The key is a *field reference* resolved live, so it is unknown without a value;
@@ -5105,70 +5076,62 @@ var SeqAccessStep = class extends Step {
5105
5076
  }
5106
5077
  };
5107
5078
  var EachBindStep = class extends Step {
5108
- constructor(iterInfo, key) {
5079
+ constructor(eachNode, key) {
5109
5080
  super();
5110
- this.iterInfo = iterInfo;
5081
+ this.eachNode = eachNode;
5111
5082
  this.key = key;
5112
5083
  }
5113
- lookup(v, _dval) {
5084
+ lookup(v) {
5114
5085
  return v;
5115
5086
  }
5116
5087
  // Replay the renderer's per-item binds (key, value + any @enrich-with binds)
5117
5088
  // 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);
5089
+ enterFrame(stack, next, renderPath) {
5090
+ return stack.enter(next, this.eachNode.enrichBinds(stack, this.key), false, renderPath);
5120
5091
  }
5121
5092
  toAbstractPathStep() {
5122
5093
  return null;
5123
5094
  }
5124
5095
  };
5125
5096
  var EachRenderItStep = class extends SeqStep {
5126
- enterFrame(stack, next) {
5127
- return stack.enter(next, { key: this.key, value: next }, false).enter(next, {}, true);
5097
+ enterFrame(stack, next, renderPath) {
5098
+ return stack.enter(next, { key: this.key, value: next }, false, renderPath).enter(next, {}, true, renderPath);
5128
5099
  }
5129
5100
  toAbstractPathStep() {
5130
5101
  return new SeqStep(this.field, this.key);
5131
5102
  }
5132
5103
  };
5133
- function warnRawDynStep(op, step) {
5134
- console.warn(`Path.${op} reached a DynStep: call toTransactionPath() first`, step);
5104
+ function stepToJson(step) {
5105
+ if (step instanceof SeqStep) return { f: step.field, k: step.key };
5106
+ if (step instanceof FieldStep) return { f: step.field };
5107
+ if (step instanceof SeqAccessStep) return { f: step.seqField, a: step.keyField };
5108
+ return null;
5135
5109
  }
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;
5110
+ function stepFromJson(j) {
5111
+ if (j == null || typeof j.f !== "string") return null;
5112
+ if (j.k !== void 0) return new SeqStep(j.f, j.k);
5113
+ if (j.a !== void 0) return new SeqAccessStep(j.f, j.a);
5114
+ return new FieldStep(j.f);
5115
+ }
5116
+ function pathToJson(path2) {
5117
+ const out = [];
5118
+ for (const step of path2.steps) {
5119
+ const j = stepToJson(step);
5120
+ if (j === null) return null;
5121
+ out.push(j);
5160
5122
  }
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));
5123
+ return out;
5124
+ }
5125
+ function pathFromJson(j) {
5126
+ if (!Array.isArray(j)) return null;
5127
+ const steps = [];
5128
+ for (const item of j) {
5129
+ const step = stepFromJson(item);
5130
+ if (step === null) return null;
5131
+ steps.push(step);
5170
5132
  }
5171
- };
5133
+ return new Path(steps);
5134
+ }
5172
5135
  var Path = class _Path {
5173
5136
  constructor(steps = []) {
5174
5137
  this.steps = steps;
@@ -5176,43 +5139,13 @@ var Path = class _Path {
5176
5139
  concat(steps) {
5177
5140
  return new _Path(this.steps.concat(steps));
5178
5141
  }
5179
- popStep() {
5180
- return new _Path(this.steps.slice(0, -1));
5181
- }
5182
- // The dispatch path: frame-only steps removed, one step per crossed component
5183
- // (DynStep included). `popStep` over it bubbles through every component.
5142
+ // Frame-only steps removed, one step per crossed component: `popStep` over the
5143
+ // result bubbles through every component.
5184
5144
  compact() {
5185
5145
  const out = [];
5186
5146
  for (const step of this.steps) {
5187
5147
  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);
5148
+ if (s !== null) out.push(s);
5216
5149
  }
5217
5150
  return new _Path(out);
5218
5151
  }
@@ -5220,7 +5153,6 @@ var Path = class _Path {
5220
5153
  // key as it is *now* so a later lookup/setValue lands on the same item even if the
5221
5154
  // keyField changed meanwhile (e.g. the selected tab moved while an intent was in
5222
5155
  // 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
5156
  pinKeys(root) {
5225
5157
  let curVal = root;
5226
5158
  let out = null;
@@ -5228,7 +5160,7 @@ var Path = class _Path {
5228
5160
  const step = this.steps[i];
5229
5161
  const pinned = step.pinKey(curVal);
5230
5162
  if (pinned !== step) (out ??= this.steps.slice())[i] = pinned;
5231
- curVal = step.lookup(curVal, NONE);
5163
+ curVal = step.lookup(curVal);
5232
5164
  if (curVal === NONE) break;
5233
5165
  }
5234
5166
  return out ? new _Path(out) : this;
@@ -5236,20 +5168,20 @@ var Path = class _Path {
5236
5168
  lookup(v, dval = null) {
5237
5169
  let curVal = v;
5238
5170
  for (const step of this.steps) {
5239
- curVal = step.lookup(curVal, NONE);
5171
+ curVal = step.lookup(curVal);
5240
5172
  if (curVal === NONE) return dval;
5241
5173
  }
5242
5174
  return curVal;
5243
5175
  }
5244
5176
  // The values entered along the path, root→leaf (root included): index 0 is `root`,
5245
5177
  // 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).
5178
+ // unresolvable step. Used to walk the component instances on a dispatch path
5179
+ // (filter via Components.getCompFor).
5248
5180
  resolveChain(root) {
5249
5181
  const out = [root];
5250
5182
  let curVal = root;
5251
5183
  for (const step of this.steps) {
5252
- curVal = step.lookup(curVal, NONE);
5184
+ curVal = step.lookup(curVal);
5253
5185
  if (curVal === NONE) break;
5254
5186
  out.push(curVal);
5255
5187
  }
@@ -5258,7 +5190,7 @@ var Path = class _Path {
5258
5190
  // A flat `[{ field, key? }]` list of the addressing steps, skipping frame-only
5259
5191
  // steps (binds). Generic path introspection so tooling (e.g. the storybook
5260
5192
  // activity log) can identify which subtree a transaction touched without
5261
- // depending on Step internals. Call on a transaction path (no DynSteps).
5193
+ // depending on Step internals.
5262
5194
  toKeys() {
5263
5195
  const out = [];
5264
5196
  for (const step of this.steps) {
@@ -5272,69 +5204,146 @@ var Path = class _Path {
5272
5204
  return produce(root, (draft) => {
5273
5205
  let parent = draft;
5274
5206
  for (let i = 0; i < this.steps.length - 1; i++) {
5275
- parent = this.steps[i].lookup(parent, NONE);
5207
+ parent = this.steps[i].lookup(parent);
5276
5208
  if (parent === NONE) return;
5277
5209
  }
5278
5210
  this.steps.at(-1).setDraftValue(parent, v);
5279
5211
  });
5280
5212
  }
5213
+ };
5214
+ function walkItems(stack, items, renderPath, path2) {
5215
+ let prev = stack.it;
5216
+ for (const step of items) {
5217
+ const next = step.lookup(prev);
5218
+ if (next === NONE) {
5219
+ console.warn("bad PathItem", { root: stack.it, step, path: path2 });
5220
+ return null;
5221
+ }
5222
+ renderPath = renderPath.pushItem(step);
5223
+ stack = step.enterFrame(stack, next, renderPath);
5224
+ prev = next;
5225
+ }
5226
+ return [stack, renderPath];
5227
+ }
5228
+ var EMPTY_PATH = new Path([]);
5229
+ var DispatchPath = class _DispatchPath {
5230
+ constructor(frames = [{ base: EMPTY_PATH, items: [] }]) {
5231
+ this.frames = frames;
5232
+ }
5233
+ // Plain addressing steps in one frame based at the root: what a caller means
5234
+ // by "this position" when it has no continuation of its own.
5235
+ static ofSteps(steps) {
5236
+ return new _DispatchPath([{ base: EMPTY_PATH, items: steps.slice() }]);
5237
+ }
5238
+ get top() {
5239
+ return this.frames[this.frames.length - 1];
5240
+ }
5241
+ _withTopItems(items) {
5242
+ const frames = this.frames.slice();
5243
+ frames[frames.length - 1] = { base: this.top.base, items };
5244
+ return new _DispatchPath(frames);
5245
+ }
5246
+ concat(steps) {
5247
+ return this._withTopItems(this.top.items.concat(steps));
5248
+ }
5249
+ pushItem(step) {
5250
+ return this.concat([step]);
5251
+ }
5252
+ pushFrame(base) {
5253
+ return new _DispatchPath(this.frames.concat({ base, items: [] }));
5254
+ }
5255
+ // Whether bubbling has anywhere left to go: another step in this frame, or a
5256
+ // visual caller underneath it. (A path always has at least one frame.)
5257
+ canPop() {
5258
+ return this.frames.length > 1 || this.frames[0].items.length > 0;
5259
+ }
5260
+ // One component closer to the root. At the top of a frame that is popping back
5261
+ // to the visual caller, not to the producer's own parent — the caller is where
5262
+ // the `*name` was written, and where an unhandled message should keep going.
5263
+ popStep() {
5264
+ const { top } = this;
5265
+ if (top.items.length > 0) return this._withTopItems(top.items.slice(0, -1));
5266
+ if (this.frames.length > 1) return new _DispatchPath(this.frames.slice(0, -1));
5267
+ return this;
5268
+ }
5269
+ // Drop frame-only steps inside every frame independently; a frame's base is
5270
+ // already addressing-only.
5271
+ compact() {
5272
+ return new _DispatchPath(
5273
+ this.frames.map(({ base, items }) => ({ base, items: new Path(items).compact().steps }))
5274
+ );
5275
+ }
5276
+ // A stable string for the ADDRESS this path denotes, for the render cache. The
5277
+ // same immutable value can sit at two places in the tree, and a subtree rendered
5278
+ // at one of them bakes that address in — the provides it publishes are located
5279
+ // there. Frame-only steps address nothing, so they are compacted out: two sites
5280
+ // that differ only in binds do render the same subtree.
5281
+ get addressKey() {
5282
+ this._addressKey ??= renderPathText(this.toTransactionPath().compact());
5283
+ return this._addressKey;
5284
+ }
5285
+ // The active transaction address: the top frame's absolute base followed by
5286
+ // its ordinary descendant steps. This is where a mutation lands.
5287
+ toTransactionPath() {
5288
+ const { base, items } = this.top;
5289
+ return base.concat(items);
5290
+ }
5291
+ // Rebuild the render stack this path was dispatched from. A frame with a base
5292
+ // re-enters at that absolute value first — replaying the resume a `*name`
5293
+ // render performed — and then walks its ordinary items.
5281
5294
  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;
5295
+ let renderPath = new _DispatchPath();
5296
+ for (let i = 0; i < this.frames.length; i++) {
5297
+ const { base, items } = this.frames[i];
5298
+ if (i > 0 || base.steps.length > 0) {
5299
+ const baseValue = base.lookup(stack.root, NONE);
5300
+ if (baseValue === NONE) {
5301
+ console.warn("bad frame base", { base, path: this });
5302
+ return null;
5303
+ }
5304
+ renderPath = renderPath.pushFrame(base);
5305
+ stack = stack.enter(baseValue, {}, true, renderPath);
5288
5306
  }
5289
- stack = step.enterFrame(stack, next);
5290
- prev = next;
5307
+ const walked = walkItems(stack, items, renderPath, this);
5308
+ if (walked === null) return null;
5309
+ [stack, renderPath] = walked;
5291
5310
  }
5292
5311
  return stack;
5293
5312
  }
5294
- static fromNodeAndEventName(node, eventName, rootNode, maxDepth, comps, stopOnNoEvent = true) {
5295
- const pathSteps = [];
5296
- const pendingDyns = [];
5313
+ // Reconstruct the dispatch position of a DOM event from the `data-*` stamps and
5314
+ // `§…§` meta comments the renderer left on the way down. `stopOnNoEvent` is off for
5315
+ // drag events, whose path is needed even where no handler is registered.
5316
+ static fromNodeAndEventName(node, eventName, rootNode, comps, stopOnNoEvent = true) {
5317
+ const parts = [];
5297
5318
  const bubbles = BUBBLING_EVENTS.has(eventName);
5298
- let depth = 0;
5299
5319
  let eventIds = [];
5300
5320
  let handlers = null;
5301
- let nodeIds = [];
5321
+ let nodeRefs = [];
5302
5322
  let isLeafComponent = true;
5303
5323
  const crossComponent = (cidNum, vid) => {
5304
5324
  const comp = comps.getComponentForId(cidNum);
5305
- let pushStep = true;
5325
+ let pushPart = true;
5306
5326
  if (handlers === null && (isLeafComponent || bubbles)) {
5307
5327
  handlers = findHandlers(comp, eventIds, vid, eventName);
5308
5328
  if (handlers === null) {
5309
5329
  if (isLeafComponent && stopOnNoEvent && !bubbles) return false;
5310
5330
  } else if (!isLeafComponent) {
5311
- pathSteps.length = 0;
5312
- pendingDyns.length = 0;
5313
- pushStep = false;
5331
+ parts.length = 0;
5332
+ pushPart = false;
5314
5333
  }
5315
5334
  }
5316
5335
  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
- }
5336
+ if (pushPart) {
5337
+ const part = resolvePathPart(comp, nodeRefs, vid);
5338
+ if (part) parts.push(part);
5328
5339
  }
5329
- for (let i = pendingDyns.length - 1; i >= 0; i--)
5330
- if (pendingDyns[i].producerCompId === cidNum) pendingDyns.splice(i, 1);
5331
5340
  eventIds = [];
5332
- nodeIds = [];
5341
+ nodeRefs = [];
5333
5342
  return true;
5334
5343
  };
5335
- while (node && node !== rootNode && depth < maxDepth) {
5344
+ while (node && node !== rootNode) {
5336
5345
  if (node?.dataset) {
5337
- const { eid, cid, vid } = node.dataset;
5346
+ const { eid, cid, vid, rp } = node.dataset;
5338
5347
  if (eid !== void 0) eventIds.push(eid);
5339
5348
  const metas = metaChain(node.previousSibling);
5340
5349
  let sawComp = false;
@@ -5342,21 +5351,46 @@ var Path = class _Path {
5342
5351
  if (m.$ === "Comp") {
5343
5352
  sawComp = true;
5344
5353
  if (!crossComponent(m.cid, m.vid)) return NO_EVENT_INFO;
5345
- nodeIds.push({ nid: m.nid });
5354
+ nodeRefs.push({ nid: m.nid, base: pathFromJson(m.base) });
5346
5355
  } else {
5347
- nodeIds.push({ nid: m.nid, si: m.si, sk: m.sk });
5356
+ nodeRefs.push({ nid: m.nid, si: m.si, sk: m.sk });
5357
+ }
5358
+ }
5359
+ if (!sawComp && cid !== void 0) {
5360
+ if (!crossComponent(+cid, vid)) return NO_EVENT_INFO;
5361
+ if (rp !== void 0) {
5362
+ const base = parseRenderPath(rp);
5363
+ if (base !== null) nodeRefs.push({ base });
5348
5364
  }
5349
5365
  }
5350
- if (!sawComp && cid !== void 0 && !crossComponent(+cid, vid)) return NO_EVENT_INFO;
5351
5366
  }
5352
- depth += 1;
5353
5367
  node = node.parentNode;
5354
5368
  }
5355
- if (pendingDyns.length > 0)
5356
- console.warn("event reconstruction: dynamic-var producer not found", pendingDyns);
5357
- return [new _Path(pathSteps.reverse()), handlers];
5369
+ parts.reverse();
5370
+ let path2 = new _DispatchPath();
5371
+ for (const part of parts)
5372
+ path2 = part.base !== void 0 ? path2.pushFrame(part.base) : path2.pushItem(part.step);
5373
+ return [path2, handlers];
5358
5374
  }
5359
5375
  };
5376
+ function keyedPath(path2, key) {
5377
+ const steps = path2.steps;
5378
+ const last = steps[steps.length - 1];
5379
+ if (last instanceof SeqStep || last instanceof FieldStep)
5380
+ return new Path(steps.slice(0, -1).concat(new SeqStep(last.field, key)));
5381
+ return null;
5382
+ }
5383
+ function renderPathText(path2) {
5384
+ return JSON.stringify(pathToJson(path2));
5385
+ }
5386
+ function parseRenderPath(text) {
5387
+ try {
5388
+ return pathFromJson(JSON.parse(text));
5389
+ } catch (err) {
5390
+ console.warn("bad render path", err, text);
5391
+ return null;
5392
+ }
5393
+ }
5360
5394
  function metaChain(n) {
5361
5395
  const out = [];
5362
5396
  while (n?.nodeType === 8 && n.textContent[0] === "§") {
@@ -5401,28 +5435,28 @@ var StepCtx = class _StepCtx {
5401
5435
  resolveNode() {
5402
5436
  return this.comp.getNodeForId(+this.meta.nid, this.vid);
5403
5437
  }
5404
- applyKey(pi) {
5405
- if (pi === null) return null;
5406
- const m = this.meta;
5407
- if (m.si !== void 0) return pi.withIndex(+m.si);
5408
- if (m.sk !== void 0) return pi.withKey(m.sk);
5409
- return pi;
5410
- }
5411
5438
  };
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;
5439
+ function resolvePathPart(comp, nodeRefs, vid) {
5440
+ for (let i = 0; i < nodeRefs.length; i++) {
5441
+ const ref = nodeRefs[i];
5442
+ if (ref.base != null) return { base: ref.base };
5443
+ if (ref.nid === void 0 || ref.nid === null) continue;
5444
+ const ctx = new StepCtx(comp, nodeRefs, i, vid);
5445
+ const step = ctx.resolveNode()?.toPathStep(ctx) ?? null;
5446
+ if (step !== null) return { step };
5417
5447
  }
5418
5448
  return null;
5419
5449
  }
5420
5450
  var NO_EVENT_INFO = [null, null];
5421
5451
  var BUBBLING_EVENTS = /* @__PURE__ */ new Set(["drop"]);
5452
+ var path = () => new PathBuilder();
5422
5453
  var PathBuilder = class {
5423
5454
  constructor() {
5424
5455
  this.pathChanges = [];
5425
5456
  }
5457
+ toPath() {
5458
+ return new Path(this.pathChanges);
5459
+ }
5426
5460
  add(pathChange) {
5427
5461
  this.pathChanges.push(pathChange);
5428
5462
  return this;
@@ -5438,10 +5472,8 @@ var PathBuilder = class {
5438
5472
  }
5439
5473
  };
5440
5474
 
5441
- // src/util/env.js
5442
- var isMac = (globalThis.navigator?.userAgent ?? "").toLowerCase().includes("mac");
5443
-
5444
5475
  // src/value.js
5476
+ var isMac = (globalThis.navigator?.userAgent ?? "").toLowerCase().includes("mac");
5445
5477
  var VALID_VAL_ID_RE = /^[a-zA-Z][a-zA-Z0-9_]*\??$/;
5446
5478
  var isValidValId = (name) => VALID_VAL_ID_RE.test(name);
5447
5479
  var VALID_FLOAT_RE = /^-?[0-9]+(\.[0-9]+)?$/;
@@ -5623,22 +5655,10 @@ function _parsePredicate(s, tokens, px) {
5623
5655
  }
5624
5656
  return new PredicateVal(pred, args);
5625
5657
  }
5626
- function kindOf(val) {
5627
- if (val === null) return 0;
5628
- if (val instanceof ConstVal) return val.kind;
5629
- if (val instanceof StrTplVal) return val.kind;
5630
- if (val instanceof SeqAccessVal) return K_SEQ;
5631
- if (val instanceof FieldVal) return K_FIELD;
5632
- if (val instanceof MethodVal) return K_METHOD;
5633
- if (val instanceof BindVal) return K_BIND;
5634
- if (val instanceof DynVal) return K_DYN;
5635
- if (val instanceof NameVal) return K_NAME;
5636
- if (val instanceof EventMemberVal) return K_EVENT;
5637
- return 0;
5638
- }
5658
+ var kindOf = (val) => val?.kind ?? 0;
5639
5659
  var BaseVal = class {
5640
- render(_stack, _rx) {
5641
- }
5660
+ // No kind: never accepted by a group (PredicateVal, which only parseBool builds).
5661
+ kind = 0;
5642
5662
  eval(_stack) {
5643
5663
  }
5644
5664
  toPathItem() {
@@ -5658,9 +5678,6 @@ var ConstVal = class extends BaseVal {
5658
5678
  this.val = val;
5659
5679
  this.kind = kind;
5660
5680
  }
5661
- render(_stack, _rx) {
5662
- return this.val;
5663
- }
5664
5681
  eval(_stack) {
5665
5682
  return this.val;
5666
5683
  }
@@ -5686,9 +5703,7 @@ var PredicateVal = class extends BaseVal {
5686
5703
  return `${this.pred.name} ${this.args.map(String).join(" ")}`;
5687
5704
  }
5688
5705
  };
5689
- var VarVal = class extends BaseVal {
5690
- };
5691
- var StrTplVal = class _StrTplVal extends VarVal {
5706
+ var StrTplVal = class _StrTplVal extends BaseVal {
5692
5707
  constructor(vals) {
5693
5708
  super();
5694
5709
  this.vals = vals;
@@ -5701,9 +5716,6 @@ var StrTplVal = class _StrTplVal extends VarVal {
5701
5716
  for (const v of this.vals) if (!(v instanceof ConstVal) || v.fromMacroVar) return false;
5702
5717
  return true;
5703
5718
  }
5704
- render(stack, _rx) {
5705
- return this.eval(stack);
5706
- }
5707
5719
  eval(stack) {
5708
5720
  const strs = new Array(this.vals.length);
5709
5721
  for (let i = 0; i < this.vals.length; i++) strs[i] = this.vals[i]?.eval(stack, "");
@@ -5740,7 +5752,8 @@ var StrTplVal = class _StrTplVal extends VarVal {
5740
5752
  return new _StrTplVal(lo === 0 && hi === vals.length ? vals : vals.slice(lo, hi));
5741
5753
  }
5742
5754
  };
5743
- var NameVal = class extends VarVal {
5755
+ var NameVal = class extends BaseVal {
5756
+ kind = K_NAME;
5744
5757
  constructor(name) {
5745
5758
  super();
5746
5759
  this.name = name;
@@ -5790,6 +5803,7 @@ var EVENT_CONVENIENCES = {
5790
5803
  dragKey: nullSafe((info) => info.lookupBind("key"))
5791
5804
  };
5792
5805
  var EventMemberVal = class extends BaseVal {
5806
+ kind = K_EVENT;
5793
5807
  constructor(members) {
5794
5808
  super();
5795
5809
  this.members = members;
@@ -5812,24 +5826,21 @@ var EventMemberVal = class extends BaseVal {
5812
5826
  return `e.${this.members.join(".")}`;
5813
5827
  }
5814
5828
  };
5815
- var RenderVal = class extends BaseVal {
5816
- render(stack, _rx) {
5817
- return this.eval(stack);
5818
- }
5819
- };
5820
- var RenderNameVal = class extends RenderVal {
5829
+ var SigilNameVal = class extends BaseVal {
5821
5830
  constructor(name) {
5822
5831
  super();
5823
5832
  this.name = name;
5824
5833
  }
5834
+ toString() {
5835
+ return this.sigil + this.name;
5836
+ }
5825
5837
  };
5826
- var BindVal = class extends RenderNameVal {
5838
+ var BindVal = class extends SigilNameVal {
5839
+ kind = K_BIND;
5840
+ sigil = "@";
5827
5841
  eval(stack) {
5828
5842
  return stack.lookupBind(this.name);
5829
5843
  }
5830
- toString() {
5831
- return `@${this.name}`;
5832
- }
5833
5844
  };
5834
5845
  var BindMemberVal = class extends BindVal {
5835
5846
  constructor(name, member) {
@@ -5844,37 +5855,35 @@ var BindMemberVal = class extends BindVal {
5844
5855
  return `@${this.name}.${this.member}`;
5845
5856
  }
5846
5857
  };
5847
- var DynVal = class extends RenderNameVal {
5858
+ var DynVal = class extends SigilNameVal {
5859
+ kind = K_DYN;
5860
+ sigil = "*";
5848
5861
  eval(stack) {
5849
5862
  return stack.lookupDynamic(this.name);
5850
5863
  }
5851
- toString() {
5852
- return `*${this.name}`;
5853
- }
5854
5864
  };
5855
- var FieldVal = class extends RenderNameVal {
5865
+ var FieldVal = class extends SigilNameVal {
5866
+ kind = K_FIELD;
5867
+ sigil = ".";
5856
5868
  eval(stack) {
5857
5869
  return stack.lookupFieldRaw(this.name);
5858
5870
  }
5859
5871
  toPathItem() {
5860
5872
  return new FieldStep(this.name);
5861
5873
  }
5862
- toString() {
5863
- return `.${this.name}`;
5864
- }
5865
5874
  };
5866
- var MethodVal = class extends RenderNameVal {
5875
+ var MethodVal = class extends SigilNameVal {
5876
+ kind = K_METHOD;
5877
+ sigil = "$";
5867
5878
  eval(stack) {
5868
5879
  return stack.lookupMethod(this.name);
5869
5880
  }
5870
5881
  evalAsHandler(stack) {
5871
5882
  return stack.lookupFieldRaw(this.name);
5872
5883
  }
5873
- toString() {
5874
- return `$${this.name}`;
5875
- }
5876
5884
  };
5877
- var SeqAccessVal = class extends RenderVal {
5885
+ var SeqAccessVal = class extends BaseVal {
5886
+ kind = K_SEQ;
5878
5887
  constructor(seqVal, keyVal) {
5879
5888
  super();
5880
5889
  this.seqVal = seqVal;
@@ -5897,9 +5906,6 @@ var Attributes = class {
5897
5906
  constructor(items) {
5898
5907
  this.items = items;
5899
5908
  }
5900
- static parse(attributes, px, parseAll = false) {
5901
- return new AttrParser(px).parse(attributes, parseAll);
5902
- }
5903
5909
  isConstant() {
5904
5910
  return false;
5905
5911
  }
@@ -5917,10 +5923,16 @@ function parseDirectiveValue(px, directiveName, source, parser) {
5917
5923
  }
5918
5924
  return val;
5919
5925
  }
5926
+ var ITER_DIRECTIVES = {
5927
+ when: "whenVal",
5928
+ "loop-with": "loopWithVal",
5929
+ "enrich-with": "enrichWithVal"
5930
+ };
5931
+ var parseIterDirective = (px, name, s) => parseDirectiveValue(px, name, s, parseAlterHandler);
5920
5932
  function parseIterationDirectives(attributes, px) {
5921
5933
  const parseNamed = (name) => {
5922
5934
  const attr = attributes.getNamedItem(`@${name}`);
5923
- return attr ? parseDirectiveValue(px, name, attr.value, parseAlterHandler) : null;
5935
+ return attr ? parseIterDirective(px, name, attr.value) : null;
5924
5936
  };
5925
5937
  return { whenVal: parseNamed("when"), loopWithVal: parseNamed("loop-with") };
5926
5938
  }
@@ -5961,11 +5973,22 @@ var AttrParser = class {
5961
5973
  this.px.onParseIssue("bad-value", info);
5962
5974
  }
5963
5975
  }
5964
- parseThen(s) {
5965
- if (this.ifAttr) this.ifAttr.thenVal = parseText(s, this.px) ?? NOT_SET_VAL;
5976
+ // `@then` / `@else` fill the branches of the `@if.<attr>` on the same element.
5977
+ parseBranch(slot, name, s) {
5978
+ if (this.ifAttr === null) return this._orphan(name, s, "if");
5979
+ this.ifAttr[slot] = parseText(s, this.px) ?? NOT_SET_VAL;
5966
5980
  }
5967
- parseElse(value) {
5968
- if (this.ifAttr) this.ifAttr.elseVal = parseText(value, this.px) ?? NOT_SET_VAL;
5981
+ // `@when` / `@loop-with` / `@enrich-with` amend the `@each` on the same element. A
5982
+ // loop-less `@enrich-with` is a scope of its own; the other two need the loop.
5983
+ parseIter(name, s) {
5984
+ const val = parseIterDirective(this.px, name, s);
5985
+ if (this.eachAttr !== null) this.eachAttr[ITER_DIRECTIVES[name]] = val;
5986
+ else if (name === "enrich-with") this.pushWrapper("scope", s, val);
5987
+ else this._orphan(name, s, "each");
5988
+ }
5989
+ // A directive that only means something next to another one, written alone.
5990
+ _orphan(name, value, needs) {
5991
+ this.px.onParseIssue("orphan-directive", { name, value, needs });
5969
5992
  }
5970
5993
  parseEvent(directiveName, value) {
5971
5994
  const [eventName, ...modifiers] = directiveName.slice(3).split("+");
@@ -5979,77 +6002,51 @@ var AttrParser = class {
5979
6002
  this.events.add(eventName, handler, modifiers);
5980
6003
  }
5981
6004
  }
5982
- _parseDirectiveValue(directiveName, s, parserFn) {
5983
- return parseDirectiveValue(this.px, directiveName, s, parserFn);
5984
- }
5985
6005
  parseDirective(s, directiveName) {
5986
6006
  switch (directiveName) {
5987
6007
  case "dangerouslysetinnerhtml":
5988
6008
  this.attrs ??= [];
5989
- this.attrs.push(new RawHtmlAttr(this._parseDirectiveValue(directiveName, s, parseText)));
6009
+ this.attrs.push(new RawHtmlAttr(parseDirectiveValue(this.px, directiveName, s, parseText)));
5990
6010
  this.hasDynamic = true;
5991
6011
  return;
5992
6012
  case "push-view":
5993
- this.pushWrapper("push-view", s, this._parseDirectiveValue(directiveName, s, parseText));
6013
+ this.pushWrapper("push-view", s, parseDirectiveValue(this.px, directiveName, s, parseText));
5994
6014
  return;
5995
6015
  case "text":
5996
- this.textChild = this._parseDirectiveValue(directiveName, s, parseText);
6016
+ this.textChild = parseDirectiveValue(this.px, directiveName, s, parseText);
5997
6017
  return;
5998
6018
  case "show":
5999
- this.pushWrapper("show", s, this._parseDirectiveValue(directiveName, s, parseBool));
6019
+ this.pushWrapper("show", s, parseDirectiveValue(this.px, directiveName, s, parseBool));
6000
6020
  return;
6001
6021
  case "hide":
6002
- this.pushWrapper("hide", s, this._parseDirectiveValue(directiveName, s, parseBool));
6022
+ this.pushWrapper("hide", s, parseDirectiveValue(this.px, directiveName, s, parseBool));
6003
6023
  return;
6004
6024
  case "each": {
6005
- const val = this._parseDirectiveValue(directiveName, s, parseSequence);
6025
+ const val = parseDirectiveValue(this.px, directiveName, s, parseSequence);
6006
6026
  this.eachAttr = this.pushWrapper("each", s, val);
6007
6027
  return;
6008
6028
  }
6009
- case "enrich-with":
6010
- if (this.eachAttr !== null)
6011
- this.eachAttr.enrichWithVal = this._parseDirectiveValue(
6012
- directiveName,
6013
- s,
6014
- parseAlterHandler
6015
- );
6016
- else
6017
- this.pushWrapper(
6018
- "scope",
6019
- s,
6020
- this._parseDirectiveValue(directiveName, s, parseAlterHandler)
6021
- );
6022
- return;
6023
6029
  case "when":
6024
- this._parseWhen(s);
6025
- return;
6026
6030
  case "loop-with":
6027
- this._parseLoopWith(s);
6031
+ case "enrich-with":
6032
+ this.parseIter(directiveName, s);
6028
6033
  return;
6029
6034
  case "then":
6030
- this.parseThen(s);
6035
+ this.parseBranch("thenVal", directiveName, s);
6031
6036
  return;
6032
6037
  case "else":
6033
- this.parseElse(s);
6038
+ this.parseBranch("elseVal", directiveName, s);
6034
6039
  return;
6035
6040
  }
6036
6041
  if (directiveName.startsWith("on.")) this.parseEvent(directiveName, s);
6037
6042
  else if (directiveName.startsWith("if.")) this.parseIf(directiveName, s);
6038
- else if (directiveName.startsWith("then.")) this.parseThen(s);
6039
- else if (directiveName.startsWith("else.")) this.parseElse(s);
6043
+ else if (directiveName.startsWith("then.")) this.parseBranch("thenVal", directiveName, s);
6044
+ else if (directiveName.startsWith("else.")) this.parseBranch("elseVal", directiveName, s);
6040
6045
  else {
6041
6046
  const info = { name: directiveName, value: s };
6042
6047
  this.px.onParseIssue("unknown-directive", info);
6043
6048
  }
6044
6049
  }
6045
- _parseWhen(s) {
6046
- if (this.eachAttr !== null)
6047
- this.eachAttr.whenVal = this._parseDirectiveValue("when", s, parseAlterHandler);
6048
- }
6049
- _parseLoopWith(s) {
6050
- if (this.eachAttr !== null)
6051
- this.eachAttr.loopWithVal = this._parseDirectiveValue("loop-with", s, parseAlterHandler);
6052
- }
6053
6050
  parse(attributes, parseAll = false) {
6054
6051
  for (const { name, value } of attributes) {
6055
6052
  const charCode = name.charCodeAt(0);
@@ -6402,19 +6399,21 @@ var VNode = class _VNode extends VBase {
6402
6399
  const createOpts = attrs.is != null ? { is: attrs.is } : void 0;
6403
6400
  const node = ns === null ? doc.createElement(tag, createOpts) : doc.createElementNS(ns, tag, createOpts);
6404
6401
  const cOpts = childOpts(this, ns, opts);
6405
- if ("value" in attrs || "checked" in attrs) {
6406
- const { value, checked, ...rest } = attrs;
6407
- applyProperties(node, rest);
6408
- appendChildNodes(node, this.childs, cOpts);
6409
- if (value !== void 0) applyValueLast(node, value);
6410
- if (checked !== void 0) setProp(node, "checked", checked, false);
6411
- } else {
6412
- applyProperties(node, attrs);
6413
- appendChildNodes(node, this.childs, cOpts);
6414
- }
6402
+ applyAttrs(node, attrs, () => appendChildNodes(node, this.childs, cOpts));
6415
6403
  return node;
6416
6404
  }
6417
6405
  };
6406
+ function applyAttrs(node, attrs, placeChildren) {
6407
+ const hasValue = "value" in attrs;
6408
+ const hasChecked = "checked" in attrs;
6409
+ if (hasValue || hasChecked) {
6410
+ const { value: _v, checked: _c, ...rest } = attrs;
6411
+ applyProperties(node, rest);
6412
+ } else applyProperties(node, attrs);
6413
+ placeChildren();
6414
+ if (hasValue) applyValueLast(node, attrs.value);
6415
+ if (hasChecked) setProp(node, "checked", attrs.checked, isNamespaced(node));
6416
+ }
6418
6417
  function diffProps(a, b) {
6419
6418
  if (a === b) return null;
6420
6419
  let diff = null;
@@ -6445,22 +6444,16 @@ function morphNode(domNode, source, target, opts) {
6445
6444
  }
6446
6445
  if (type3 === 1 && source.isSameKind(target)) {
6447
6446
  const propsDiff = diffProps(source.attrs, target.attrs);
6448
- const hasValue = propsDiff != null && "value" in propsDiff;
6449
- const hasChecked = propsDiff != null && "checked" in propsDiff;
6450
- if (propsDiff) {
6451
- if (hasValue || hasChecked) {
6452
- const { value: _v, checked: _c, ...rest } = propsDiff;
6453
- applyProperties(domNode, rest);
6454
- } else applyProperties(domNode, propsDiff);
6455
- }
6456
- if (!target.attrs.dangerouslySetInnerHTML) {
6447
+ const placeChildren = () => {
6448
+ if (target.attrs.dangerouslySetInnerHTML) return;
6457
6449
  const ns = effectiveNs(target, opts);
6458
6450
  morphChildren(domNode, source.childs, target.childs, childOpts(target, ns, opts));
6451
+ };
6452
+ if (propsDiff) applyAttrs(domNode, propsDiff, placeChildren);
6453
+ else placeChildren();
6454
+ if (!(propsDiff && "value" in propsDiff) && source.tag === "SELECT") {
6455
+ if (target.attrs.value !== void 0) applyValueLast(domNode, target.attrs.value);
6459
6456
  }
6460
- if (hasValue) applyValueLast(domNode, propsDiff.value);
6461
- else if (source.tag === "SELECT" && target.attrs.value !== void 0)
6462
- applyValueLast(domNode, target.attrs.value);
6463
- if (hasChecked) setProp(domNode, "checked", propsDiff.checked, false);
6464
6457
  return domNode;
6465
6458
  }
6466
6459
  if (type3 === 11) {
@@ -6579,20 +6572,26 @@ function h(tagName, properties, children, namespace) {
6579
6572
  }
6580
6573
 
6581
6574
  // src/anode.js
6582
- function resolveDynProducer(comp, name) {
6583
- const own = comp?.provide?.[name];
6584
- const producerComp = own != null ? comp : comp?.scope?.lookupProvider(name) ?? null;
6585
- const producerProvide = own ?? producerComp?.provide?.[name];
6586
- if (producerComp == null || producerProvide == null) return null;
6587
- const pi = producerProvide.val?.toPathItem?.() ?? null;
6588
- return { producerCompId: producerComp.id, producerSteps: pi ? [pi] : [] };
6575
+ function renderTarget(val, stack) {
6576
+ if (val instanceof DynVal) {
6577
+ const loc = stack.lookupDynamicLocated(val.name);
6578
+ if (loc?.path == null) return [loc?.value ?? null, stack.renderPath, null];
6579
+ return [loc.value, stack.renderPath.pushFrame(loc.path), loc.path];
6580
+ }
6581
+ const step = val.toPathItem?.() ?? null;
6582
+ if (step === null) return [val.eval(stack), stack.renderPath, null];
6583
+ const path2 = stack.renderPath.pushItem(step);
6584
+ return [val.eval(stack), path2, stack.pendingFrame ? path2.toTransactionPath() : null];
6589
6585
  }
6590
6586
  var BaseNode = class {
6591
6587
  render(_stack, _rx) {
6592
6588
  return null;
6593
6589
  }
6594
- setDataAttr(key, val) {
6595
- console.warn("setDataAttr not implemented for", this, { key, val });
6590
+ // Stamp a `data-*` attribute on the element(s) this node renders. A no-op for
6591
+ // nodes that produce no element of their own (text, `<x render*>`): a view whose
6592
+ // root is one of those records its component boundary in the `§Comp§` meta
6593
+ // comment instead (see Renderer._rValComp).
6594
+ setDataAttr(_key, _val) {
6596
6595
  }
6597
6596
  isConstant() {
6598
6597
  return false;
@@ -6631,21 +6630,12 @@ var TextNode = class extends BaseNode {
6631
6630
  isConstant() {
6632
6631
  return true;
6633
6632
  }
6634
- setDataAttr(_key, _val) {
6635
- }
6636
6633
  };
6637
6634
  var CommentNode = class extends TextNode {
6638
6635
  render(_stack, rx) {
6639
6636
  return rx.renderComment(this.val);
6640
6637
  }
6641
6638
  };
6642
- function optimizeChilds(childs) {
6643
- for (let i = 0; i < childs.length; i++) {
6644
- const child = childs[i];
6645
- if (child.isConstant()) childs[i] = new RenderOnceNode(child);
6646
- else child.optimize();
6647
- }
6648
- }
6649
6639
  function optimizeNode(node) {
6650
6640
  if (node.isConstant()) return new RenderOnceNode(node);
6651
6641
  node.optimize();
@@ -6660,7 +6650,8 @@ var ChildsNode = class extends BaseNode {
6660
6650
  return this.childs.every((v) => v.isConstant());
6661
6651
  }
6662
6652
  optimize() {
6663
- optimizeChilds(this.childs);
6653
+ const { childs } = this;
6654
+ for (let i = 0; i < childs.length; i++) childs[i] = optimizeNode(childs[i]);
6664
6655
  }
6665
6656
  };
6666
6657
  var DomNode = class extends ChildsNode {
@@ -6672,8 +6663,7 @@ var DomNode = class extends ChildsNode {
6672
6663
  }
6673
6664
  render(stack, rx) {
6674
6665
  const childNodes = new Array(this.childs.length);
6675
- for (let i = 0; i < childNodes.length; i++)
6676
- childNodes[i] = this.childs[i]?.render?.(stack, rx) ?? null;
6666
+ for (let i = 0; i < childNodes.length; i++) childNodes[i] = this.childs[i].render(stack, rx);
6677
6667
  return rx.renderTag(this.tagName, this.attrs.eval(stack), childNodes, this.namespace);
6678
6668
  }
6679
6669
  setDataAttr(key, val) {
@@ -6685,7 +6675,7 @@ var DomNode = class extends ChildsNode {
6685
6675
  };
6686
6676
  var FragmentNode = class extends ChildsNode {
6687
6677
  render(stack, rx) {
6688
- return rx.renderFragment(this.childs.map((c) => c?.render(stack, rx)));
6678
+ return rx.renderFragment(this.childs.map((c) => c.render(stack, rx)));
6689
6679
  }
6690
6680
  setDataAttr(key, val) {
6691
6681
  for (const child of this.childs) child.setDataAttr(key, val);
@@ -6699,8 +6689,10 @@ var ANode = class _ANode extends BaseNode {
6699
6689
  this.nodeId = nodeId;
6700
6690
  this.val = val;
6701
6691
  }
6702
- toPathStep(ctx) {
6703
- return ctx.applyKey(this.val?.toPathItem?.() ?? null);
6692
+ // The addressing step this node contributes to an event's dispatch path, given
6693
+ // the `StepCtx` of the meta that named it; null when it addresses nothing.
6694
+ toPathStep(_ctx) {
6695
+ return this.val?.toPathItem?.() ?? null;
6704
6696
  }
6705
6697
  static parse(html2, px) {
6706
6698
  const nodes = px.parseHTML(html2);
@@ -6716,8 +6708,8 @@ var ANode = class _ANode extends BaseNode {
6716
6708
  return maybeFragment(trimmed);
6717
6709
  }
6718
6710
  static fromDOM(node, px) {
6719
- if (node instanceof px.Text) return new TextNode(node.textContent);
6720
- else if (node instanceof px.Comment) return new CommentNode(node.textContent);
6711
+ if (node.nodeType === 3) return new TextNode(node.textContent);
6712
+ if (node.nodeType === 8) return new CommentNode(node.textContent);
6721
6713
  const { childNodes, attributes: attrs, tagName: tag } = node;
6722
6714
  const childs = [];
6723
6715
  for (let i = 0; i < childNodes.length; i++) {
@@ -6735,11 +6727,11 @@ var ANode = class _ANode extends BaseNode {
6735
6727
  const slotName = attrs.getNamedItem("name")?.value ?? "_";
6736
6728
  return px.frame.macroSlots[slotName] ?? maybeFragment(childs);
6737
6729
  }
6738
- const [nAttrs, wrappers] = Attributes.parse(attrs, px, true);
6730
+ const [nAttrs, wrappers] = new AttrParser(px).parse(attrs, true);
6739
6731
  px.onAttributes(nAttrs, wrappers, null, true, tag);
6740
6732
  return wrap(px.newMacroNode(macroName, nAttrs.toMacroVars(), childs), px, wrappers);
6741
6733
  } else if (VALID_NODE_RE.test(tag)) {
6742
- const [nAttrs, wrappers, textChild] = Attributes.parse(attrs, px);
6734
+ const [nAttrs, wrappers, textChild] = new AttrParser(px).parse(attrs);
6743
6735
  px.onAttributes(nAttrs, wrappers, textChild, false, tag);
6744
6736
  if (textChild) childs.unshift(new RenderTextNode(null, textChild));
6745
6737
  const domChilds = tag !== "PRE" ? condenseChildsWhites(childs) : childs;
@@ -6901,39 +6893,32 @@ var RenderViewId = class extends ANode {
6901
6893
  evalViewName(stack) {
6902
6894
  return this.viewVal ? this.viewVal.eval(stack) : null;
6903
6895
  }
6904
- // A `<x render*>` produces no DOM element of its own to carry `data-cid`;
6905
- // when it is a view's root the component boundary is recorded in the `Comp`
6906
- // meta comment instead (see Renderer._rValComp), so this is a no-op.
6907
- setDataAttr(_key, _val) {
6908
- }
6909
6896
  };
6910
- function dynRenderStep(comp, name, key) {
6911
- const p = resolveDynProducer(comp, name);
6912
- if (!p) return null;
6913
- return key === void 0 ? new DynStep(p.producerCompId, p.producerSteps) : new DynEachStep(p.producerCompId, p.producerSteps, key);
6914
- }
6915
6897
  var RenderNode = class extends RenderViewId {
6916
6898
  render(stack, rx) {
6917
- const newStack = stack.enter(this.val.eval(stack), {}, true);
6918
- return rx.renderIt(newStack, this, "", this.evalViewName(stack));
6899
+ const [value, renderPath, base] = renderTarget(this.val, stack);
6900
+ const newStack = stack.enter(value, {}, true, renderPath, false);
6901
+ return rx.renderIt(newStack, this, this.evalViewName(stack), base);
6919
6902
  }
6903
+ // A `*name` target contributes no step: the site recorded the absolute base it
6904
+ // resumed at, and event reconstruction turns that into a continuation frame.
6920
6905
  toPathStep(ctx) {
6921
- if (this.val instanceof DynVal) return dynRenderStep(ctx.comp, this.val.name);
6906
+ if (this.val instanceof DynVal) return null;
6922
6907
  return super.toPathStep(ctx);
6923
6908
  }
6924
6909
  };
6925
6910
  var RenderItNode = class extends RenderViewId {
6926
6911
  render(stack, rx) {
6927
- const newStack = stack.enter(stack.it, {}, true);
6928
- return rx.renderIt(newStack, this, "", this.evalViewName(stack));
6912
+ const base = stack.pendingFrame ? stack.renderPath.toTransactionPath() : null;
6913
+ const newStack = stack.enter(stack.it, {}, true, stack.renderPath, false);
6914
+ return rx.renderIt(newStack, this, this.evalViewName(stack), base);
6929
6915
  }
6930
6916
  toPathStep(ctx) {
6931
6917
  const next = ctx.next();
6932
6918
  if (next === null) return null;
6933
6919
  const nextNode = next.resolveNode();
6934
6920
  if (nextNode instanceof EachNode && next.hasKey) {
6935
- if (nextNode.val instanceof DynVal)
6936
- return dynRenderStep(ctx.comp, nextNode.val.name, next.key);
6921
+ if (nextNode.val instanceof DynVal) return null;
6937
6922
  return new EachRenderItStep(nextNode.val.name, next.key);
6938
6923
  }
6939
6924
  return null;
@@ -6955,9 +6940,6 @@ var RenderTextNode = class extends ANode {
6955
6940
  render(stack, _rx) {
6956
6941
  return this.val.eval(stack);
6957
6942
  }
6958
- // Renders to a text node, which can't carry `data-cid`.
6959
- setDataAttr(_key, _val) {
6960
- }
6961
6943
  };
6962
6944
  var RenderOnceNode = class extends BaseNode {
6963
6945
  constructor(node) {
@@ -7032,36 +7014,46 @@ var ScopeNode = class extends WrapperNode {
7032
7014
  var EachNode = class extends WrapperNode {
7033
7015
  constructor(nodeId, val) {
7034
7016
  super(nodeId, val);
7035
- this.iterInfo = new IterInfo(val, null, null, null);
7017
+ this.iterInfo = new IterInfo();
7036
7018
  }
7037
7019
  render(stack, rx) {
7038
- return rx.renderEachWhen(stack, this.iterInfo, this.node, this.nodeId);
7020
+ return rx.renderEachWhen(stack, this);
7039
7021
  }
7040
- toPathStep(ctx) {
7041
- return ctx.hasKey ? new EachBindStep(this.iterInfo, ctx.key) : null;
7042
- }
7043
- static register = true;
7044
- };
7045
- var IterInfo = class {
7046
- constructor(val, whenVal, loopWithVal, enrichWithVal) {
7047
- this.val = val;
7048
- this.whenVal = whenVal;
7049
- this.loopWithVal = loopWithVal;
7050
- this.enrichWithVal = enrichWithVal;
7051
- }
7052
- eval(stack) {
7053
- const seq = this.val.eval(stack) ?? [];
7054
- const filter = this.whenVal?.evalAsHandler(stack) ?? filterAlwaysTrue;
7055
- const loopWith = this.loopWithVal?.evalAsHandler(stack) ?? nullLoopWith;
7056
- const enricher = this.enrichWithVal?.evalAsHandler(stack) ?? null;
7057
- return { seq, filter, loopWith, enricher };
7022
+ // The sequence and the three loop handlers, resolved against `stack`.
7023
+ evalIter(stack) {
7024
+ const { whenVal, loopWithVal, enrichWithVal } = this.iterInfo;
7025
+ return {
7026
+ seq: this.val.eval(stack) ?? [],
7027
+ filter: whenVal?.evalAsHandler(stack) ?? filterAlwaysTrue,
7028
+ loopWith: loopWithVal?.evalAsHandler(stack) ?? nullLoopWith,
7029
+ enricher: enrichWithVal?.evalAsHandler(stack) ?? null
7030
+ };
7058
7031
  }
7059
7032
  // Rebuild the per-item binds for `key` (see iteration.js bindsForKey).
7060
7033
  enrichBinds(stack, key) {
7061
- const { seq, filter, loopWith, enricher } = this.eval(stack);
7034
+ const { seq, filter, loopWith, enricher } = this.evalIter(stack);
7062
7035
  const ctx = makeLoopCtx(stack, filter);
7063
7036
  return bindsForKey({ seq, it: stack.it, loopWith, enricher, ctx }, key);
7064
7037
  }
7038
+ toPathStep(ctx) {
7039
+ return ctx.hasKey ? new EachBindStep(this, ctx.key) : null;
7040
+ }
7041
+ // Where one item lives, for the render path. `@each` re-binds `it` to the item
7042
+ // whether or not the body is a component, so the position moves either way and
7043
+ // the step has to address it — `.rows` iterated at `key` IS `rows[key]`.
7044
+ // Null for a dynamic sequence: `*rows` carries its own absolute path and enters
7045
+ // a continuation frame instead (see Renderer.renderEachWhen).
7046
+ itemStep(key) {
7047
+ return this.val instanceof FieldVal ? new SeqStep(this.val.name, key) : null;
7048
+ }
7049
+ static register = true;
7050
+ };
7051
+ var IterInfo = class {
7052
+ constructor() {
7053
+ this.whenVal = null;
7054
+ this.loopWithVal = null;
7055
+ this.enrichWithVal = null;
7056
+ }
7065
7057
  };
7066
7058
  function xOp(consumed = [], { wrappable = false, wrapper = null, ignoresChildren = false } = {}) {
7067
7059
  return { consumed: new Set(consumed), wrappable, wrapper, ignoresChildren };
@@ -7088,26 +7080,31 @@ var WRAPPER_NODES = {
7088
7080
  scope: ScopeNode,
7089
7081
  "push-view": PushViewNameNode
7090
7082
  };
7091
- var ParseContext = class _ParseContext {
7092
- constructor(document2, Text, Comment, nodes, events2, macroNodes, frame, parent) {
7093
- this.nodes = nodes ?? [];
7094
- this.events = events2 ?? [];
7095
- this.macroNodes = macroNodes ?? [];
7096
- this.parent = parent ?? null;
7097
- this.frame = frame ?? {};
7098
- this.document = document2 ?? globalThis.document;
7099
- this.Text = Text ?? globalThis.Text;
7100
- this.Comment = Comment ?? globalThis.Comment;
7101
- this.cacheConstNodes = true;
7083
+ var ParseContext = class {
7084
+ constructor(document2 = globalThis.document) {
7085
+ this.document = document2;
7086
+ this.nodes = [];
7087
+ this.events = [];
7088
+ this.macroNodes = [];
7089
+ this.parent = null;
7090
+ this.frame = {};
7102
7091
  this.currentTag = null;
7103
7092
  }
7104
7093
  isInsideMacro(name) {
7105
7094
  return this.frame.macroName === name || this.parent?.isInsideMacro(name);
7106
7095
  }
7096
+ // A macro body parses in a child context that shares every accumulator with
7097
+ // its parent (nodes, events, macroNodes, and whatever a subclass collects) and
7098
+ // differs only in its frame. Cloned rather than constructed so a subclass
7099
+ // keeps collecting inside macro bodies without re-implementing this — the
7100
+ // lint and class-set contexts used to lose (or had to copy) exactly that.
7107
7101
  enterMacro(macroName, macroVars, macroSlots) {
7108
- const { document: document2, Text, Comment, nodes, events: events2, macroNodes } = this;
7109
- const frame = { macroName, macroVars, macroSlots };
7110
- return new _ParseContext(document2, Text, Comment, nodes, events2, macroNodes, frame, this);
7102
+ const child = Object.create(Object.getPrototypeOf(this));
7103
+ return Object.assign(child, this, {
7104
+ frame: { macroName, macroVars, macroSlots },
7105
+ parent: this,
7106
+ currentTag: null
7107
+ });
7111
7108
  }
7112
7109
  parseHTML(html2) {
7113
7110
  const t = this.document.createElement("template");
@@ -7172,10 +7169,10 @@ var isBlockDomNode = (n) => {
7172
7169
  return node instanceof DomNode && HTML_BLOCK_TAGS.has(node.tagName);
7173
7170
  };
7174
7171
  var isEmptyText = (c) => c instanceof TextNode && c.val === "";
7175
- var isIgnorableXChild = (c) => c instanceof CommentNode || (c.isWhiteSpace?.() ?? false);
7172
+ var isIgnorableXChild = (c) => c instanceof CommentNode || c.isWhiteSpace();
7176
7173
  var hasMeaningfulChilds = (childs) => childs.some((c) => !isIgnorableXChild(c));
7177
7174
  function trimEdgeWhite(node) {
7178
- if (!node.isWhiteSpace?.()) return false;
7175
+ if (!node.isWhiteSpace()) return false;
7179
7176
  node.condenseWhiteSpace();
7180
7177
  return true;
7181
7178
  }
@@ -7186,7 +7183,7 @@ function condenseChildsWhites(childs) {
7186
7183
  if (last > 0 && trimEdgeWhite(childs[last])) emptied = true;
7187
7184
  for (let i = 1; i < last; i++) {
7188
7185
  const cur = childs[i];
7189
- if (!(cur.isWhiteSpace?.() && cur.hasNewLine())) continue;
7186
+ if (!(cur.isWhiteSpace() && cur.hasNewLine())) continue;
7190
7187
  const bothBlock = isBlockDomNode(childs[i - 1]) && isBlockDomNode(childs[i + 1]);
7191
7188
  cur.condenseWhiteSpace(bothBlock ? "" : " ");
7192
7189
  if (bothBlock) emptied = true;
@@ -7194,12 +7191,12 @@ function condenseChildsWhites(childs) {
7194
7191
  return emptied ? childs.filter((c) => !isEmptyText(c)) : childs;
7195
7192
  }
7196
7193
  var View = class {
7197
- constructor(name, rawView = "No View Defined", style = "", anode = null, ctx = null) {
7194
+ constructor(name, rawView = "No View Defined", style = "") {
7198
7195
  this.name = name;
7199
- this.anode = anode;
7200
- this.style = style;
7201
- this.ctx = ctx;
7202
7196
  this.rawView = rawView;
7197
+ this.style = style;
7198
+ this.anode = null;
7199
+ this.ctx = null;
7203
7200
  }
7204
7201
  compile(ctx, scope, cid) {
7205
7202
  this.ctx = ctx;
@@ -7207,7 +7204,7 @@ var View = class {
7207
7204
  this.anode.setDataAttr("data-cid", cid);
7208
7205
  this.anode.setDataAttr("data-vid", this.name);
7209
7206
  this.ctx.compile(scope);
7210
- if (ctx.cacheConstNodes) this.anode = optimizeNode(this.anode);
7207
+ this.anode = optimizeNode(this.anode);
7211
7208
  }
7212
7209
  render(stack, rx) {
7213
7210
  if (this.anode === null) {
@@ -7232,7 +7229,7 @@ var NodeEvents = class {
7232
7229
  getHandlersFor(eventName) {
7233
7230
  let r = null;
7234
7231
  for (const handler of this.handlers)
7235
- if (handler.handlesEventName(eventName)) {
7232
+ if (handler.name === eventName) {
7236
7233
  r ??= [];
7237
7234
  r.push(handler);
7238
7235
  }
@@ -7246,9 +7243,6 @@ var NodeEvent = class {
7246
7243
  this.modifierWrapper = compileModifiers(name, modifiers);
7247
7244
  this.modifiers = modifiers;
7248
7245
  }
7249
- handlesEventName(name) {
7250
- return this.name === name;
7251
- }
7252
7246
  getHandlerAndArgs(stack, event) {
7253
7247
  const r = this.handlerCall.getHandlerAndArgs(stack, event);
7254
7248
  r[0] = this.modifierWrapper(r[0], event);
@@ -7300,92 +7294,209 @@ function compileModifiers(eventName, names) {
7300
7294
  };
7301
7295
  }
7302
7296
 
7303
- // src/util/parsectx.js
7304
- var ParseCtxClassSetCollector = class _ParseCtxClassSetCollector extends ParseContext {
7305
- constructor(...args) {
7306
- super(...args);
7307
- this.classes = /* @__PURE__ */ new Set();
7308
- }
7309
- _addClasses(s) {
7310
- for (const v of s.split(/\s+/)) {
7311
- this.classes.add(v);
7312
- }
7297
+ // src/stack.js
7298
+ var STOP = /* @__PURE__ */ Symbol("STOP");
7299
+ var NEXT = /* @__PURE__ */ Symbol("NEXT");
7300
+ var DEFAULT_ROUTE = ["dyn", "lex"];
7301
+ var isTypeName = (s) => {
7302
+ const c = s.charCodeAt(0);
7303
+ return c >= 65 && c <= 90;
7304
+ };
7305
+ function lookup(chain, name, dv = null) {
7306
+ let n = chain;
7307
+ while (n !== null) {
7308
+ const r = n[0].lookup(name);
7309
+ if (r === STOP) return dv;
7310
+ if (r !== NEXT) return r;
7311
+ n = n[1];
7313
7312
  }
7314
- enterMacro(macroName, macroVars, macroSlots) {
7315
- const { document: document2, Text, Comment, nodes, events: events2, macroNodes } = this;
7316
- const frame = { macroName, macroVars, macroSlots };
7317
- const v = new _ParseCtxClassSetCollector(
7318
- document2,
7319
- Text,
7320
- Comment,
7321
- nodes,
7322
- events2,
7323
- macroNodes,
7324
- frame,
7325
- this
7326
- );
7327
- v.classes = this.classes;
7328
- return v;
7313
+ return dv;
7314
+ }
7315
+ var BindFrame = class {
7316
+ constructor(it, binds, isFrame) {
7317
+ this.it = it;
7318
+ this.binds = binds;
7319
+ this.isFrame = isFrame;
7329
7320
  }
7330
- onAttributes(attrs, _wrapperAttrs, _textChild, _isMacroCall, _tag) {
7331
- if (Array.isArray(attrs.items)) {
7332
- for (const attr of attrs.items) {
7333
- if (attr.name !== "class") {
7334
- continue;
7335
- }
7336
- const { val, thenVal, elseVal } = attr;
7337
- if (thenVal !== void 0) {
7338
- this._maybeAddVal(thenVal);
7339
- this._maybeAddVal(elseVal);
7340
- } else {
7341
- this._maybeAddVal(val);
7342
- }
7343
- }
7344
- } else {
7345
- const attr = attrs.items.class;
7346
- if (attr) {
7347
- this._addClasses(attr);
7348
- }
7349
- }
7321
+ lookup(name) {
7322
+ const v = this.binds[name];
7323
+ return v === void 0 ? this.isFrame ? STOP : NEXT : v;
7350
7324
  }
7351
- _maybeAddVal(value) {
7352
- if (!this._maybeAddStrTpl(value) && typeof value?.val === "string") {
7353
- this._addClasses(value.val);
7354
- }
7325
+ };
7326
+ var DynFrame = class {
7327
+ constructor(binds, types) {
7328
+ this.binds = binds;
7329
+ this.types = types;
7355
7330
  }
7356
- _maybeAddStrTpl(value) {
7357
- if (value?.vals !== void 0) {
7358
- for (const val of value.vals) {
7359
- if (val instanceof ConstVal && val.val !== "") {
7360
- this._addClasses(val.val);
7361
- }
7362
- }
7363
- return true;
7364
- }
7365
- return false;
7331
+ lookup(name) {
7332
+ const v = (isTypeName(name) ? this.types : this.binds)[name];
7333
+ return v === void 0 ? NEXT : v;
7366
7334
  }
7367
7335
  };
7368
- function collectAppClassesInSet(app) {
7369
- const classes = /* @__PURE__ */ new Set();
7370
- for (const Comp of app.comps.byId.values()) {
7371
- for (const key in Comp.views) {
7372
- const view = Comp.views[key];
7373
- for (const name of view.ctx.classes) {
7374
- classes.add(name);
7375
- }
7376
- }
7336
+ function computeViewsId(views) {
7337
+ let s = "";
7338
+ let n = views;
7339
+ while (n !== null) {
7340
+ s += n[0];
7341
+ n = n[1];
7377
7342
  }
7378
- return classes;
7343
+ return s === "main" ? "" : s;
7379
7344
  }
7380
-
7381
- // src/components.js
7382
- var COMPONENT = /* @__PURE__ */ Symbol.for("tutuca.component");
7383
- var Components = class {
7345
+ var Stack = class _Stack {
7346
+ constructor(fields) {
7347
+ Object.assign(this, fields);
7348
+ }
7349
+ _with(patch) {
7350
+ return new _Stack({ ...this, ...patch });
7351
+ }
7352
+ // Evaluate every provide the entered component publishes and push them as one
7353
+ // dynBinds frame, keyed by NAME. A value is published together with the absolute
7354
+ // path it lives at: the same declaration is read as `*name` AND resumed at by
7355
+ // `<x render="*name">`, so a consumer needs both halves. Types go in the same
7356
+ // frame's other map. No-op with no provides.
7357
+ _pushProvides() {
7358
+ const comp = this.comps.getCompFor(this.it);
7359
+ if (comp == null) return this;
7360
+ const { provide, provideType } = comp;
7361
+ const binds = {};
7362
+ const types = {};
7363
+ let has2 = false;
7364
+ const base = this._publishBase();
7365
+ for (const k in provide) {
7366
+ const step = provide[k].toPathItem?.() ?? null;
7367
+ if (step === null) continue;
7368
+ const value = provide[k].eval(this);
7369
+ binds[k] = { value, path: base === null ? null : base.concat([step]) };
7370
+ has2 = true;
7371
+ }
7372
+ for (const k in provideType) {
7373
+ types[k] = provideType[k];
7374
+ has2 = true;
7375
+ }
7376
+ if (!has2) return this;
7377
+ return this._with({ dynBinds: [new DynFrame(binds, types), this.dynBinds] });
7378
+ }
7379
+ // The absolute address of the component being entered, or null when this
7380
+ // position cannot be written down as one. Frame-only steps carry bindings and
7381
+ // address nothing, so they are compacted away first; what is left is checked
7382
+ // against the value actually being rendered, because a scope CAN move the
7383
+ // render position without contributing an addressing step (a plain `@each`
7384
+ // body re-binds `it` to the item while its rebuild step is an identity).
7385
+ //
7386
+ // A null base still publishes the VALUE — `*name` reads it fine — but there is
7387
+ // nowhere to resume, so `<x render="*name">` renders nothing rather than
7388
+ // editing whatever happens to live at the address we guessed.
7389
+ _publishBase() {
7390
+ const base = this.renderPath.toTransactionPath().compact();
7391
+ return base.lookup(this.root, NOT_FOUND) === this.it ? base : null;
7392
+ }
7393
+ static root(comps, it, ctx = null) {
7394
+ return new _Stack({
7395
+ comps,
7396
+ root: it,
7397
+ it,
7398
+ binds: [new BindFrame(it, {}, true), null],
7399
+ dynBinds: [new DynFrame({}, {}), null],
7400
+ views: ["main", null],
7401
+ viewsId: "",
7402
+ renderPath: new DispatchPath(),
7403
+ pendingFrame: false,
7404
+ ctx
7405
+ })._pushProvides();
7406
+ }
7407
+ // `renderPath` defaults to this stack's own: an ordinary scope does not move.
7408
+ // `pendingFrame` clears on a component frame (which emits the base) and is
7409
+ // inherited by transparent scopes, which have to carry it to the next boundary.
7410
+ enter(it, bindings = {}, isFrame = true, renderPath = this.renderPath, pendingFrame = null) {
7411
+ const stack = this._with({
7412
+ it,
7413
+ binds: [new BindFrame(it, bindings, isFrame), this.binds],
7414
+ renderPath,
7415
+ pendingFrame: pendingFrame ?? (isFrame ? false : this.pendingFrame)
7416
+ });
7417
+ return isFrame ? stack._pushProvides() : stack;
7418
+ }
7419
+ pushViewName(name) {
7420
+ const views = [name, this.views];
7421
+ return this._with({ views, viewsId: computeViewsId(views) });
7422
+ }
7423
+ // Published types are stable per scope and would only churn the render cache, so
7424
+ // the cache key covers values alone.
7425
+ _pushDynBindValuesToArray(arr, comp) {
7426
+ for (const k in comp.provide) arr.push(this.lookupDynamic(k));
7427
+ for (const k in comp.lookup) arr.push(this.lookupDynamic(k));
7428
+ }
7429
+ // `*name`: the nearest binding above (including this component's own provides,
7430
+ // pushed on entering it), else a path registered in the component's lexical
7431
+ // scope, else this component's declared default, else null.
7432
+ //
7433
+ // One chain walk and no producer resolution: a lookup names what it WANTS, so the
7434
+ // frame it wants is keyed by that name. The default belongs to the CONSUMER's
7435
+ // declaration and is evaluated against the consumer's stack, which is why it is
7436
+ // consulted only after the whole chain has missed.
7437
+ lookupDynamicLocated(name) {
7438
+ if (isTypeName(name)) return null;
7439
+ const v = lookup(this.dynBinds, name);
7440
+ if (v != null) return v;
7441
+ const comp = this.comps.getCompFor(this.it);
7442
+ if (comp == null) return null;
7443
+ const path2 = comp.scope?.lookupPath?.(name) ?? null;
7444
+ if (path2 !== null) {
7445
+ const value2 = path2.lookup(this.root, NOT_FOUND);
7446
+ if (value2 !== NOT_FOUND) return { value: value2, path: path2 };
7447
+ }
7448
+ const dval = comp.lookup[name] ?? null;
7449
+ if (dval === null) return null;
7450
+ const step = dval.toPathItem?.() ?? null;
7451
+ const value = dval.eval(this);
7452
+ return step === null ? { value, path: null } : { value, path: this.renderPath.toTransactionPath().concat([step]) };
7453
+ }
7454
+ lookupDynamic(name) {
7455
+ if (isTypeName(name)) return lookup(this.dynBinds, name);
7456
+ return this.lookupDynamicLocated(name)?.value ?? null;
7457
+ }
7458
+ lookupBind(name) {
7459
+ return lookup(this.binds, name);
7460
+ }
7461
+ lookupFieldRaw(name) {
7462
+ return this.it[name] ?? null;
7463
+ }
7464
+ lookupMethod(name) {
7465
+ const fn = this.it[name];
7466
+ return fn instanceof Function ? fn.call(this.it) : null;
7467
+ }
7468
+ // The dispatched DOM event / drag info, read only by EventMemberVal's
7469
+ // `e.<member>` handler args. Null outside a live event transaction (`ctx` is
7470
+ // then a send/intent transaction, which carries no `e`).
7471
+ lookupEvent() {
7472
+ return this.ctx?.e ?? null;
7473
+ }
7474
+ lookupDragInfo() {
7475
+ return this.ctx?.dragInfo ?? null;
7476
+ }
7477
+ getHandlerFor(name, key) {
7478
+ return this.comps.getHandlerFor(this.it, name, key);
7479
+ }
7480
+ lookupBestView(views, defaultViewName) {
7481
+ let n = this.views;
7482
+ while (n !== null) {
7483
+ const view = views[n[0]];
7484
+ if (view !== void 0) return view;
7485
+ n = n[1];
7486
+ }
7487
+ return views[defaultViewName];
7488
+ }
7489
+ };
7490
+ var NOT_FOUND = /* @__PURE__ */ Symbol("NOT_FOUND");
7491
+
7492
+ // src/components.js
7493
+ var COMPONENT = /* @__PURE__ */ Symbol.for("tutuca.component");
7494
+ var Components = class {
7384
7495
  constructor() {
7385
7496
  this.byId = /* @__PURE__ */ new Map();
7386
7497
  }
7387
7498
  registerComponent(Comp) {
7388
- this.byId.set(Comp[COMPONENT].id, Comp);
7499
+ this.byId.set(Comp.id, Comp);
7389
7500
  }
7390
7501
  getComponentForId(id) {
7391
7502
  return this.byId.get(id) ?? null;
@@ -7405,7 +7516,7 @@ var Components = class {
7405
7516
  }
7406
7517
  compileStyles() {
7407
7518
  const styles2 = [];
7408
- for (const Comp of this.byId.values()) styles2.push(Comp[COMPONENT].compileStyle());
7519
+ for (const Comp of this.byId.values()) styles2.push(Comp.compileStyle());
7409
7520
  return styles2.join("\n");
7410
7521
  }
7411
7522
  };
@@ -7416,15 +7527,17 @@ var ComponentStack = class _ComponentStack {
7416
7527
  this.byName = {};
7417
7528
  this.intentsByName = {};
7418
7529
  this.macros = {};
7530
+ this.paths = {};
7419
7531
  }
7420
7532
  enter() {
7421
7533
  return new _ComponentStack(this.comps, this);
7422
7534
  }
7423
7535
  registerComponents(comps, opts) {
7424
- const { aliases: aliases2 = {} } = opts ?? {};
7536
+ const { aliases: aliases2 = {}, paths } = opts ?? {};
7537
+ if (paths) this.registerPaths(paths);
7425
7538
  for (let i = 0; i < comps.length; i++) {
7426
7539
  const Comp = comps[i];
7427
- Comp[COMPONENT].scope = this.enter();
7540
+ Comp.scope = this.enter();
7428
7541
  this.comps.registerComponent(Comp);
7429
7542
  this.byName[Comp.name] = Comp;
7430
7543
  }
@@ -7435,6 +7548,27 @@ var ComponentStack = class _ComponentStack {
7435
7548
  else console.warn("alias", alias, "to inexistent component", aliases2[alias]);
7436
7549
  }
7437
7550
  }
7551
+ // Register lowercase names as absolute paths from the app state root. A
7552
+ // descendant that declares one in its `lookup` reads and renders `*name` without
7553
+ // anything above it publishing one — which is what makes a session, a theme or a
7554
+ // host-owned value available in its natural registration scope, instead of forcing
7555
+ // an application root whose only job is to `provide` it. Register on a nested
7556
+ // scope to narrow a name; nearest registration wins.
7557
+ //
7558
+ // Uppercase names are ignored: a component TYPE is what `lookupComponent` already
7559
+ // answers, and a type has no path.
7560
+ registerPaths(paths) {
7561
+ for (const name in paths) {
7562
+ if (isTypeName(name)) {
7563
+ console.warn("registerPaths: a type name has no path", name);
7564
+ continue;
7565
+ }
7566
+ this.paths[name] = paths[name].toPath();
7567
+ }
7568
+ }
7569
+ lookupPath(name) {
7570
+ return this.paths[name] ?? this.parent?.lookupPath(name) ?? null;
7571
+ }
7438
7572
  registerMacros(macros) {
7439
7573
  for (const key in macros) {
7440
7574
  const lower = key.toLowerCase();
@@ -7466,97 +7600,82 @@ var ComponentStack = class _ComponentStack {
7466
7600
  lookupComponent(name) {
7467
7601
  return this.byName[name] ?? this.parent?.lookupComponent(name) ?? null;
7468
7602
  }
7469
- // The component in this scope chain that provides `name`, innermost first. A lookup
7470
- // names a value without naming its producer, so the render-target teleport
7471
- // (resolveDynProducer) recovers the producer here instead. Sound because
7472
- // PROVIDE_NAME_COLLISION keeps a provide name to one producer per chain; with two,
7473
- // this returns the innermost and the linter has already reported the ambiguity.
7474
- lookupProvider(name) {
7603
+ // Whether anything in this scope chain provides `name`. Existence only: a lookup
7604
+ // names what it WANTS and takes whoever is nearest above it at render time, so
7605
+ // there is no producer to identify — several components may publish one name and
7606
+ // the live render ancestry decides. Used by the linter to tell a lookup that can
7607
+ // be satisfied from one that never will be.
7608
+ hasProvider(name) {
7475
7609
  for (const compName in this.byName) {
7476
- const Comp = this.byName[compName];
7477
- if (Comp.provide?.[name] !== void 0) return Comp;
7610
+ if (this.byName[compName].provide?.[name] !== void 0) return true;
7478
7611
  }
7479
- return this.parent?.lookupProvider(name) ?? null;
7612
+ return this.parent?.hasProvider(name) ?? false;
7480
7613
  }
7481
7614
  lookupMacro(name) {
7482
7615
  return this.macros[name] ?? this.parent?.lookupMacro(name) ?? null;
7483
7616
  }
7484
7617
  };
7485
- var ProvideInfo = class {
7486
- constructor(val) {
7487
- this.val = val;
7488
- }
7489
- };
7490
- var LookupInfo = class {
7491
- constructor(val) {
7492
- this.val = val;
7493
- }
7494
- };
7495
7618
  var isString = (v) => typeof v === "string";
7496
- var isTypeName = (s) => {
7497
- const c = s.charCodeAt(0);
7498
- return c >= 65 && c <= 90;
7499
- };
7500
7619
  var _rawSpecKeys = "name view style commonStyle globalStyle receive intent alter views provide lookup fields methods statics";
7501
7620
  var KNOWN_SPEC_KEYS = new Set(_rawSpecKeys.split(" "));
7502
7621
  var _compId = 0;
7503
- var Component = class {
7504
- constructor(Class, o) {
7505
- this.id = _compId++;
7506
- this.name = o.name ?? "UnkComp";
7507
- this.Class = Class;
7508
- this.views = { main: new View("main", o.view, o.style) };
7509
- this.commonStyle = o.commonStyle ?? "";
7510
- this.globalStyle = o.globalStyle ?? "";
7511
- this.receive = o.receive ?? {};
7512
- this.intent = o.intent ?? {};
7513
- this.alter = o.alter ?? {};
7514
- for (const name in o.views ?? {}) {
7515
- const v = o.views[name];
7516
- const { view, style } = isString(v) ? { view: v } : v;
7517
- this.views[name] = new View(name, view, style);
7518
- }
7519
- this._rawProvide = o.provide ?? {};
7520
- this._rawLookup = o.lookup ?? [];
7521
- this.provide = {};
7522
- this.provideType = {};
7523
- this.lookup = {};
7524
- this.scope = null;
7525
- this.spec = o;
7526
- this.extra = {};
7527
- for (const key of Object.keys(o)) if (!KNOWN_SPEC_KEYS.has(key)) this.extra[key] = o[key];
7528
- }
7622
+ function initComponent(Class, o) {
7623
+ Class[COMPONENT] = Class;
7624
+ Class.id = _compId++;
7625
+ Class.views = { main: new View("main", o.view, o.style) };
7626
+ Class.commonStyle = o.commonStyle ?? "";
7627
+ Class.globalStyle = o.globalStyle ?? "";
7628
+ Class.receive = o.receive ?? {};
7629
+ Class.intent = o.intent ?? {};
7630
+ Class.alter = o.alter ?? {};
7631
+ for (const name in o.views ?? {}) {
7632
+ const v = o.views[name];
7633
+ const { view, style } = isString(v) ? { view: v } : v;
7634
+ Class.views[name] = new View(name, view, style);
7635
+ }
7636
+ Class._rawProvide = o.provide ?? {};
7637
+ Class._rawLookup = o.lookup ?? [];
7638
+ Class.provide = {};
7639
+ Class.provideType = {};
7640
+ Class.lookup = {};
7641
+ Class.scope = null;
7642
+ Class.spec = o;
7643
+ Class.extra = {};
7644
+ for (const key of Object.keys(o)) if (!KNOWN_SPEC_KEYS.has(key)) Class.extra[key] = o[key];
7645
+ return Object.assign(Class, COMPONENT_METHODS);
7646
+ }
7647
+ var COMPONENT_METHODS = {
7529
7648
  compile(ParseContext2) {
7530
7649
  for (const name in this.views)
7531
7650
  this.views[name].compile(new ParseContext2(), this.scope, this.id);
7532
7651
  const ctx = this.views.main.ctx;
7533
7652
  for (const key in this._rawProvide) {
7534
7653
  if (isTypeName(key)) {
7535
- if (this._rawProvide[key] === "self") this.provideType[key] = this.Class;
7654
+ if (this._rawProvide[key] === "self") this.provideType[key] = this;
7536
7655
  continue;
7537
7656
  }
7538
7657
  const val = parseProvide(this._rawProvide[key], ctx);
7539
- if (val) this.provide[key] = new ProvideInfo(val);
7658
+ if (val) this.provide[key] = val;
7540
7659
  }
7541
7660
  for (const entry of this._rawLookup) {
7542
7661
  const name = isString(entry) ? entry : isString(entry?.name) ? entry.name : null;
7543
7662
  if (name === null) continue;
7544
7663
  const defStr = isString(entry?.default) ? entry.default : null;
7545
- this.lookup[name] = new LookupInfo(defStr === null ? null : parseField(defStr, ctx));
7664
+ this.lookup[name] = defStr === null ? null : parseField(defStr, ctx);
7546
7665
  }
7547
7666
  for (const key in this.lookup)
7548
7667
  if (this.provide[key] !== void 0)
7549
7668
  console.warn("name declared in both provide and lookup", this.name, key);
7550
- }
7669
+ },
7551
7670
  getView(name) {
7552
7671
  return this.views[name] ?? this.views.main;
7553
- }
7554
- getEventForId(id, name = "main") {
7555
- return this.getView(name).ctx.getEventForId(id);
7556
- }
7557
- getNodeForId(id, name = "main") {
7558
- return this.getView(name).ctx.getNodeForId(id);
7559
- }
7672
+ },
7673
+ getEventForId(id, viewName) {
7674
+ return this.getView(viewName).ctx.getEventForId(id);
7675
+ },
7676
+ getNodeForId(id, viewName) {
7677
+ return this.getView(viewName).ctx.getNodeForId(id);
7678
+ },
7560
7679
  compileStyle() {
7561
7680
  const { id, commonStyle, globalStyle, views } = this;
7562
7681
  const styles2 = commonStyle ? [`[data-cid="${id}"]{${commonStyle}}`] : [];
@@ -7569,6 +7688,68 @@ var Component = class {
7569
7688
  }
7570
7689
  };
7571
7690
 
7691
+ // src/util/parsectx.js
7692
+ var ParseCtxClassSetCollector = class extends ParseContext {
7693
+ constructor(...args) {
7694
+ super(...args);
7695
+ this.classes = /* @__PURE__ */ new Set();
7696
+ }
7697
+ _addClasses(s) {
7698
+ for (const v of s.split(/\s+/)) {
7699
+ this.classes.add(v);
7700
+ }
7701
+ }
7702
+ onAttributes(attrs, _wrapperAttrs, _textChild, _isMacroCall, _tag) {
7703
+ if (Array.isArray(attrs.items)) {
7704
+ for (const attr of attrs.items) {
7705
+ if (attr.name !== "class") {
7706
+ continue;
7707
+ }
7708
+ const { val, thenVal, elseVal } = attr;
7709
+ if (thenVal !== void 0) {
7710
+ this._maybeAddVal(thenVal);
7711
+ this._maybeAddVal(elseVal);
7712
+ } else {
7713
+ this._maybeAddVal(val);
7714
+ }
7715
+ }
7716
+ } else {
7717
+ const attr = attrs.items.class;
7718
+ if (attr) {
7719
+ this._addClasses(attr);
7720
+ }
7721
+ }
7722
+ }
7723
+ _maybeAddVal(value) {
7724
+ if (!this._maybeAddStrTpl(value) && typeof value?.val === "string") {
7725
+ this._addClasses(value.val);
7726
+ }
7727
+ }
7728
+ _maybeAddStrTpl(value) {
7729
+ if (value?.vals !== void 0) {
7730
+ for (const val of value.vals) {
7731
+ if (val instanceof ConstVal && val.val !== "") {
7732
+ this._addClasses(val.val);
7733
+ }
7734
+ }
7735
+ return true;
7736
+ }
7737
+ return false;
7738
+ }
7739
+ };
7740
+ function collectAppClassesInSet(app) {
7741
+ const classes = /* @__PURE__ */ new Set();
7742
+ for (const Comp of app.comps.byId.values()) {
7743
+ for (const key in Comp.views) {
7744
+ const view = Comp.views[key];
7745
+ for (const name of view.ctx.classes) {
7746
+ classes.add(name);
7747
+ }
7748
+ }
7749
+ }
7750
+ return classes;
7751
+ }
7752
+
7572
7753
  // tools/core/html-tokenizer.js
7573
7754
  var CharCodes = {
7574
7755
  Tab: 9,
@@ -9860,7 +10041,6 @@ var DYN_VAL_NOT_DEFINED = "DYN_VAL_NOT_DEFINED";
9860
10041
  var DYN_ALIAS_NOT_REFERENCED = "DYN_ALIAS_NOT_REFERENCED";
9861
10042
  var PROVIDE_NOT_ADDRESSABLE = "PROVIDE_NOT_ADDRESSABLE";
9862
10043
  var PROVIDE_TYPE_BAD_SHAPE = "PROVIDE_TYPE_BAD_SHAPE";
9863
- var PROVIDE_NAME_COLLISION = "PROVIDE_NAME_COLLISION";
9864
10044
  var LOOKUP_BAD_SHAPE = "LOOKUP_BAD_SHAPE";
9865
10045
  var LOOKUP_NO_PROVIDER = "LOOKUP_NO_PROVIDER";
9866
10046
  var RENDER_IT_OUTSIDE_OF_LOOP = "RENDER_IT_OUTSIDE_OF_LOOP";
@@ -9877,6 +10057,7 @@ var IF_NO_BRANCH_SET = "IF_NO_BRANCH_SET";
9877
10057
  var UNKNOWN_COMPONENT_NAME = "UNKNOWN_COMPONENT_NAME";
9878
10058
  var UNKNOWN_MACRO_ARG = "UNKNOWN_MACRO_ARG";
9879
10059
  var UNKNOWN_DIRECTIVE = "UNKNOWN_DIRECTIVE";
10060
+ var ORPHAN_DIRECTIVE = "ORPHAN_DIRECTIVE";
9880
10061
  var UNKNOWN_X_OP = "UNKNOWN_X_OP";
9881
10062
  var UNKNOWN_X_ATTR = "UNKNOWN_X_ATTR";
9882
10063
  var X_OP_IGNORES_CHILDREN = "X_OP_IGNORES_CHILDREN";
@@ -9911,6 +10092,7 @@ var LEVEL_ERROR2 = "error";
9911
10092
  var LEVEL_HINT = "hint";
9912
10093
  var PARSE_ISSUES = {
9913
10094
  "unknown-directive": { id: UNKNOWN_DIRECTIVE, candidates: KNOWN_DIRECTIVE_NAMES },
10095
+ "orphan-directive": { id: ORPHAN_DIRECTIVE },
9914
10096
  "unknown-x-op": { id: UNKNOWN_X_OP, candidates: X_KNOWN_OP_NAMES, atPrefix: X_KNOWN_OP_NAMES },
9915
10097
  "unknown-x-attr": {
9916
10098
  id: UNKNOWN_X_ATTR,
@@ -9983,7 +10165,6 @@ function checkComponent(Comp, lx = new LintContext(), { wellKnownExtras = EMPTY_
9983
10165
  checkFieldMethodNameCollisions(lx, Comp);
9984
10166
  checkProvidesAreAddressable(lx, Comp);
9985
10167
  checkProvidedTypes(lx, Comp);
9986
- checkProvideNameCollisions(lx, Comp);
9987
10168
  checkLookupShapes(lx, Comp);
9988
10169
  checkLookupTypesResolve(lx, Comp);
9989
10170
  checkLookupsHaveProviders(lx, Comp);
@@ -10667,19 +10848,6 @@ function checkProvidedTypes(lx, Comp) {
10667
10848
  if (raw !== "self") lx.error(PROVIDE_TYPE_BAD_SHAPE, { name, value: raw });
10668
10849
  }
10669
10850
  }
10670
- function checkProvideNameCollisions(lx, Comp) {
10671
- const scope = Comp.scope;
10672
- if (!scope) return;
10673
- for (const name in Comp.provide) {
10674
- for (let s = scope; s; s = s.parent) {
10675
- for (const otherName in s.byName) {
10676
- const Other = s.byName[otherName];
10677
- if (Other !== Comp && Other.provide?.[name] !== void 0)
10678
- lx.error(PROVIDE_NAME_COLLISION, { name, other: Other.name });
10679
- }
10680
- }
10681
- }
10682
- }
10683
10851
  var KNOWN_LOOKUP_KEYS = /* @__PURE__ */ new Set(["name", "default"]);
10684
10852
  function checkLookupShapes(lx, Comp) {
10685
10853
  const raw = Comp._rawLookup;
@@ -10721,8 +10889,8 @@ function checkLookupsHaveProviders(lx, Comp) {
10721
10889
  if (!scope) return;
10722
10890
  for (const name in Comp.lookup) {
10723
10891
  if (isTypeName2(name)) continue;
10724
- if (scope.lookupProvider?.(name)) continue;
10725
- const info = { name, hasDefault: Comp.lookup[name].val != null };
10892
+ if (scope.hasProvider?.(name) || scope.lookupPath?.(name)) continue;
10893
+ const info = { name, hasDefault: Comp.lookup[name] != null };
10726
10894
  if (info.hasDefault) lx.hint(LOOKUP_NO_PROVIDER, info);
10727
10895
  else lx.error(LOOKUP_NO_PROVIDER, info);
10728
10896
  }
@@ -10770,13 +10938,14 @@ var LintContext = class {
10770
10938
  this.reports.push({ id, info, level, context: { ...this.frame }, suggestion });
10771
10939
  }
10772
10940
  };
10773
- var LintParseContext = class extends ParseContext {
10774
- constructor(document2, Text, Comment) {
10775
- super(document2, Text, Comment);
10941
+ var LintParseContext = class extends ParseCtxClassSetCollector {
10942
+ constructor(document2) {
10943
+ super(document2);
10776
10944
  this.attrs = [];
10777
10945
  this.parseIssues = [];
10778
10946
  }
10779
10947
  onAttributes(attrs, wrapperAttrs, textChild, isMacroCall = false, tag = null) {
10948
+ super.onAttributes(attrs, wrapperAttrs, textChild, isMacroCall, tag);
10780
10949
  this.attrs.push({ attrs, wrapperAttrs, textChild, isMacroCall, tag });
10781
10950
  }
10782
10951
  onParseIssue(kind, info) {
@@ -10813,14 +10982,36 @@ function dispatchPhase(dispatcher, targetPath, phase, self) {
10813
10982
 
10814
10983
  // src/oo.js
10815
10984
  var BAD_VALUE2 = /* @__PURE__ */ Symbol("BadValue");
10816
- var nullCoercer = (v) => v;
10985
+ var COERCE_NONE = (_v) => null;
10986
+ var COERCE_MAP = (v) => {
10987
+ if (v instanceof Map) return new Map(v);
10988
+ if (Array.isArray(v) || isPlainObject(v))
10989
+ return new Map(Array.isArray(v) ? v : Object.entries(v));
10990
+ return null;
10991
+ };
10992
+ var FIELD_TYPES = {
10993
+ any: [(_v) => true, COERCE_NONE, () => null],
10994
+ text: [(v) => typeof v === "string", (v) => v?.toString?.() ?? "", () => ""],
10995
+ int: [Number.isInteger, (v) => Number.isFinite(v) ? Math.trunc(v) : null, () => 0],
10996
+ float: [Number.isFinite, COERCE_NONE, () => 0],
10997
+ bool: [(v) => typeof v === "boolean", (v) => !!v, () => false],
10998
+ list: [Array.isArray, (v) => Array.isArray(v) ? [...v] : null, () => []],
10999
+ object: [isPlainObject, (v) => isPlainObject(v) ? { ...v } : null, () => ({})],
11000
+ map: [(v) => v instanceof Map, COERCE_MAP, () => /* @__PURE__ */ new Map()],
11001
+ set: [
11002
+ (v) => v instanceof Set,
11003
+ (v) => v instanceof Set || Array.isArray(v) ? new Set(v) : null,
11004
+ () => /* @__PURE__ */ new Set()
11005
+ ]
11006
+ };
10817
11007
  var Field = class {
10818
- constructor(type3, name, typeCheck, coercer, defaultValue = null) {
11008
+ // `type` names an entry of FIELD_TYPES; `defaultValue` falls back to the type's own.
11009
+ constructor(type3, name, defaultValue, [typeCheck, coercer, makeDefault] = FIELD_TYPES[type3]) {
10819
11010
  this.type = type3;
10820
11011
  this.name = name;
10821
11012
  this.typeCheck = typeCheck;
10822
11013
  this.coercer = coercer;
10823
- this.defaultValue = defaultValue;
11014
+ this.defaultValue = defaultValue === void 0 ? makeDefault() : defaultValue;
10824
11015
  }
10825
11016
  isValid(v) {
10826
11017
  return this.typeCheck(v);
@@ -10834,81 +11025,14 @@ var Field = class {
10834
11025
  return this.coerceOr(v, this.defaultValue);
10835
11026
  }
10836
11027
  };
10837
- var CHECK_TYPE_ANY = (_v) => true;
10838
- var CHECK_TYPE_INT = Number.isInteger;
10839
- var CHECK_TYPE_FLOAT = Number.isFinite;
10840
- var CHECK_TYPE_BOOL = (v) => typeof v === "boolean";
10841
- var CHECK_TYPE_STRING = (v) => typeof v === "string";
10842
- var CHECK_TYPE_LIST = Array.isArray;
10843
- var CHECK_TYPE_OBJECT = isPlainObject;
10844
- var CHECK_TYPE_MAP = (v) => v instanceof Map;
10845
- var CHECK_TYPE_SET = (v) => v instanceof Set;
10846
- var COERCE_NONE = (_v) => null;
10847
- var COERCE_BOOL = (v) => !!v;
10848
- var COERCE_STRING = (v) => v?.toString?.() ?? "";
10849
- var COERCE_INT = (v) => Number.isFinite(v) ? Math.trunc(v) : null;
10850
- var COERCE_LIST = (v) => Array.isArray(v) ? [...v] : null;
10851
- var COERCE_OBJECT = (v) => isPlainObject(v) ? { ...v } : null;
10852
- var COERCE_MAP = (v) => {
10853
- if (v instanceof Map) return new Map(v);
10854
- if (Array.isArray(v) || isPlainObject(v))
10855
- return new Map(Array.isArray(v) ? v : Object.entries(v));
10856
- return null;
10857
- };
10858
- var COERCE_SET = (v) => v instanceof Set || Array.isArray(v) ? new Set(v) : null;
10859
- var FieldBool = class extends Field {
10860
- constructor(name, defaultValue = false) {
10861
- super("bool", name, CHECK_TYPE_BOOL, COERCE_BOOL, defaultValue);
10862
- }
10863
- };
10864
- var FieldAny = class extends Field {
10865
- constructor(name, defaultValue = null) {
10866
- super("any", name, CHECK_TYPE_ANY, nullCoercer, defaultValue);
10867
- }
10868
- };
10869
- var FieldString = class extends Field {
10870
- constructor(name, defaultValue = "") {
10871
- super("text", name, CHECK_TYPE_STRING, COERCE_STRING, defaultValue);
10872
- }
10873
- };
10874
- var FieldInt = class extends Field {
10875
- constructor(name, defaultValue = 0) {
10876
- super("int", name, CHECK_TYPE_INT, COERCE_INT, defaultValue);
10877
- }
10878
- };
10879
- var FieldFloat = class extends Field {
10880
- constructor(name, defaultValue = 0) {
10881
- super("float", name, CHECK_TYPE_FLOAT, COERCE_NONE, defaultValue);
10882
- }
10883
- };
10884
- var metaOf = (v) => v?.constructor?.[COMPONENT] ?? v?.constructor?.getMetaClass?.();
11028
+ var metaOf = (v) => v?.constructor?.getMetaClass?.();
10885
11029
  var getTypeName = (v) => metaOf(v)?.name ?? null;
10886
11030
  var FieldComp = class extends Field {
10887
11031
  constructor(type3, name, args) {
10888
- super(type3, name, (v) => getTypeName(v) === type3, nullCoercer, null);
11032
+ super(type3, name, null, [(v) => getTypeName(v) === type3, COERCE_NONE, () => null]);
10889
11033
  this.args = args;
10890
11034
  }
10891
11035
  };
10892
- var FieldList = class extends Field {
10893
- constructor(name, defaultValue = []) {
10894
- super("list", name, CHECK_TYPE_LIST, COERCE_LIST, defaultValue);
10895
- }
10896
- };
10897
- var FieldObject = class extends Field {
10898
- constructor(name, defaultValue = {}) {
10899
- super("object", name, CHECK_TYPE_OBJECT, COERCE_OBJECT, defaultValue);
10900
- }
10901
- };
10902
- var FieldMap = class extends Field {
10903
- constructor(name, defaultValue = /* @__PURE__ */ new Map()) {
10904
- super("map", name, CHECK_TYPE_MAP, COERCE_MAP, defaultValue);
10905
- }
10906
- };
10907
- var FieldSet = class extends Field {
10908
- constructor(name, defaultValue = /* @__PURE__ */ new Set()) {
10909
- super("set", name, CHECK_TYPE_SET, COERCE_SET, defaultValue);
10910
- }
10911
- };
10912
11036
  function mkCompField(field, scope, args) {
10913
11037
  const Comp = scope?.lookupComponent(field.type) ?? null;
10914
11038
  if (Comp === null)
@@ -10917,112 +11041,66 @@ function mkCompField(field, scope, args) {
10917
11041
  );
10918
11042
  return Comp?.make({ ...field.args, ...args }, { scope }) ?? null;
10919
11043
  }
10920
- var ClassBuilder = class {
10921
- constructor(name) {
10922
- this.name = name;
10923
- this.fields = {};
10924
- this.compFields = /* @__PURE__ */ new Set();
10925
- this._methods = {};
10926
- this._statics = {};
10927
- }
10928
- build() {
10929
- const { name, fields, compFields, _methods } = this;
10930
- const defaults = Object.fromEntries(
10931
- Object.entries(fields).map(([fieldName, field]) => [fieldName, field.defaultValue])
10932
- );
10933
- const Class = {
10934
- [name]: class {
10935
- constructor(values = {}) {
10936
- Object.assign(this, defaults, values);
10937
- }
11044
+ function fieldFromSpec(name, value) {
11045
+ const type3 = typeof value;
11046
+ if (type3 === "string") return new Field("text", name, value);
11047
+ if (type3 === "number") return new Field("float", name, value);
11048
+ if (type3 === "boolean") return new Field("bool", name, value);
11049
+ if (Array.isArray(value)) return new Field("list", name, [...value]);
11050
+ if (value instanceof Set) return new Field("set", name, new Set(value));
11051
+ if (value instanceof Map) return new Field("map", name, new Map(value));
11052
+ if (value?.type && Object.hasOwn(value, "defaultValue")) {
11053
+ const t = value.type in FIELD_TYPES ? value.type : "any";
11054
+ const probe = new Field(t, name);
11055
+ return new Field(t, name, probe.coerceOr(value.defaultValue, probe.defaultValue));
11056
+ }
11057
+ if (value?.component && value?.args !== void 0)
11058
+ return new FieldComp(value.component, name, value.args);
11059
+ if (isPlainObject(value)) return new Field("object", name, { ...value });
11060
+ return new Field("any", name, value);
11061
+ }
11062
+ function classFromData(name, { fields: spec = {}, methods = {}, statics = {} }) {
11063
+ const fields = {};
11064
+ for (const key in spec) fields[key] = fieldFromSpec(key, spec[key]);
11065
+ const defaults = Object.fromEntries(
11066
+ Object.entries(fields).map(([key, field]) => [key, field.defaultValue])
11067
+ );
11068
+ const Class = {
11069
+ [name]: class {
11070
+ constructor(values = {}) {
11071
+ Object.assign(this, defaults, values);
10938
11072
  }
10939
- }[name];
10940
- Class[DRAFTABLE] = true;
10941
- Object.assign(Class.prototype, _methods);
10942
- const metaClass = { fields, name, methods: _methods };
10943
- Object.assign(
10944
- Class,
10945
- {
10946
- getMetaClass: () => metaClass,
10947
- make(inArgs = {}, opts = {}) {
10948
- const args = {};
10949
- const scope = opts.scope ?? this[COMPONENT]?.scope ?? this.scope;
10950
- for (const key in inArgs) {
10951
- const field = fields[key];
10952
- if (compFields.has(key)) args[key] = mkCompField(field, scope, inArgs[key]);
10953
- else if (field === void 0)
10954
- console.warn("extra argument to constructor:", name, key, inArgs);
10955
- else args[key] = field.coerceOrDefault(inArgs[key]);
10956
- }
10957
- for (const key of compFields)
10958
- if (args[key] === void 0) args[key] = mkCompField(fields[key], scope, inArgs[key]);
10959
- return freeze(new this(args), true);
10960
- }
10961
- },
10962
- this._statics
10963
- );
10964
- return Class;
10965
- }
10966
- methods(proto) {
10967
- for (const k in proto) this._methods[k] = proto[k];
10968
- }
10969
- statics(proto) {
10970
- for (const k in proto) this._statics[k] = proto[k];
10971
- }
10972
- addField(name, dval, FieldCls) {
10973
- const field = new FieldCls(name, dval);
10974
- this.fields[name] = field;
10975
- return field;
10976
- }
10977
- addCompField(name, type3, args) {
10978
- const field = new FieldComp(type3, name, args);
10979
- this.compFields.add(name);
10980
- this.fields[name] = field;
10981
- return field;
10982
- }
10983
- };
10984
- var FIELD_CLASS = /* @__PURE__ */ Symbol.for("tutuca.fieldClass");
10985
- var fieldsByTypeName = {
10986
- text: FieldString,
10987
- int: FieldInt,
10988
- float: FieldFloat,
10989
- bool: FieldBool,
10990
- list: FieldList,
10991
- object: FieldObject,
10992
- map: FieldMap,
10993
- set: FieldSet,
10994
- any: FieldAny
10995
- };
10996
- function fieldFromDescriptor(name, value) {
10997
- const FieldCls = fieldsByTypeName[value.type] ?? FieldAny;
10998
- const probe = new FieldCls(name);
10999
- return [FieldCls, probe.coerceOr(value.defaultValue, probe.defaultValue)];
11000
- }
11001
- function classFromData(name, { fields = {}, methods, statics }) {
11002
- const b = new ClassBuilder(name);
11003
- for (const field in fields) {
11004
- const value = fields[field];
11005
- const type3 = typeof value;
11006
- if (type3 === "string") b.addField(field, value, FieldString);
11007
- else if (type3 === "number") b.addField(field, value, FieldFloat);
11008
- else if (type3 === "boolean") b.addField(field, value, FieldBool);
11009
- else if (Array.isArray(value)) b.addField(field, [...value], FieldList);
11010
- else if (value instanceof Set) b.addField(field, new Set(value), FieldSet);
11011
- else if (value instanceof Map) b.addField(field, new Map(value), FieldMap);
11012
- else if (value?.type && Object.hasOwn(value, "defaultValue")) {
11013
- const [FieldCls, dval] = fieldFromDescriptor(field, value);
11014
- b.addField(field, dval, FieldCls);
11015
- } else if (value?.component && value?.args !== void 0)
11016
- b.addCompField(field, value.component, value.args);
11017
- else if (isPlainObject(value)) b.addField(field, { ...value }, FieldObject);
11018
- else {
11019
- const FieldCls = value?.[FIELD_CLASS] ?? FieldAny;
11020
- b.addField(field, value, FieldCls);
11021
11073
  }
11022
- }
11023
- if (methods) b.methods(methods);
11024
- if (statics) b.statics(statics);
11025
- return b.build();
11074
+ }[name];
11075
+ Class[DRAFTABLE] = true;
11076
+ Object.assign(Class.prototype, methods);
11077
+ Object.assign(
11078
+ Class,
11079
+ {
11080
+ fields,
11081
+ methods,
11082
+ // The documented way for instance code to reach its class's fields
11083
+ // (`this.constructor.getMetaClass().fields.x.defaultValue`).
11084
+ getMetaClass: () => Class,
11085
+ make(inArgs = {}, opts = {}) {
11086
+ const args = {};
11087
+ const scope = opts.scope ?? this.scope;
11088
+ for (const key in inArgs) {
11089
+ const field = fields[key];
11090
+ if (field === void 0)
11091
+ console.warn("extra argument to constructor:", name, key, inArgs);
11092
+ else if (field instanceof FieldComp) args[key] = mkCompField(field, scope, inArgs[key]);
11093
+ else args[key] = field.coerceOrDefault(inArgs[key]);
11094
+ }
11095
+ for (const key in fields)
11096
+ if (fields[key] instanceof FieldComp && args[key] === void 0)
11097
+ args[key] = mkCompField(fields[key], scope, void 0);
11098
+ return freeze(new this(args), true);
11099
+ }
11100
+ },
11101
+ statics
11102
+ );
11103
+ return Class;
11026
11104
  }
11027
11105
  function validateDraftFields(current2, draft) {
11028
11106
  const meta = metaOf(current2);
@@ -11038,14 +11116,11 @@ function validateDraftFields(current2, draft) {
11038
11116
  }
11039
11117
  }
11040
11118
  }
11041
- var META_KEYS = "name id fields methods views receive intent alter provide provideType lookup spec extra commonStyle globalStyle scope _rawProvide _rawLookup".split(
11042
- " "
11043
- );
11044
11119
  var RESERVED_COMPONENT_STATICS = /* @__PURE__ */ new Set([
11045
- ...META_KEYS,
11046
- "make",
11047
- "getMetaClass",
11048
- ...Object.getOwnPropertyNames(Component.prototype)
11120
+ ..."name id fields methods views receive intent alter provide provideType lookup spec extra commonStyle globalStyle scope _rawProvide _rawLookup make getMetaClass".split(
11121
+ " "
11122
+ ),
11123
+ ...Object.keys(COMPONENT_METHODS)
11049
11124
  ]);
11050
11125
  function assertNoReservedComponentStatics(statics = {}) {
11051
11126
  for (const name in statics) {
@@ -11054,186 +11129,10 @@ function assertNoReservedComponentStatics(statics = {}) {
11054
11129
  }
11055
11130
  }
11056
11131
  }
11057
- Component.fromSpec = (opts) => {
11132
+ function component(opts) {
11058
11133
  assertNoReservedComponentStatics(opts.statics);
11059
- const Class = classFromData(opts.name, opts);
11060
- const comp = new Component(Class, opts);
11061
- const metaClass = Class.getMetaClass();
11062
- comp.fields = metaClass.fields;
11063
- comp.methods = metaClass.methods;
11064
- Class.getMetaClass = () => comp;
11065
- Class[COMPONENT] = comp;
11066
- for (const key of META_KEYS)
11067
- if (!Object.hasOwn(Class, key))
11068
- Object.defineProperty(Class, key, {
11069
- get() {
11070
- return comp[key];
11071
- },
11072
- set(v) {
11073
- comp[key] = v;
11074
- },
11075
- configurable: true
11076
- });
11077
- for (const key of Object.getOwnPropertyNames(Component.prototype))
11078
- if (key !== "constructor" && !Object.hasOwn(Class, key))
11079
- Class[key] = (...args) => comp[key](...args);
11080
- return Class;
11081
- };
11082
- var component = (opts) => Component.fromSpec(opts);
11083
-
11084
- // src/stack.js
11085
- var STOP = /* @__PURE__ */ Symbol("STOP");
11086
- var NEXT = /* @__PURE__ */ Symbol("NEXT");
11087
- var DEFAULT_ROUTE = ["dyn", "lex"];
11088
- function routeLookup(route, lex, dyn) {
11089
- for (let i = 0; i < route.length; i++) {
11090
- const leg = route[i];
11091
- if (leg === "dyn") {
11092
- const v = dyn();
11093
- if (v != null) return v;
11094
- } else if (leg === "lex") {
11095
- const v = lex();
11096
- if (v != null) return v;
11097
- } else {
11098
- console.warn("unknown lookup route leg", leg, '- expected "dyn" or "lex"');
11099
- }
11100
- }
11101
- return null;
11102
- }
11103
- function lookup(chain, name, dv = null) {
11104
- let n = chain;
11105
- while (n !== null) {
11106
- const r = n[0].lookup(name);
11107
- if (r === STOP) return dv;
11108
- if (r !== NEXT) return r;
11109
- n = n[1];
11110
- }
11111
- return dv;
11112
- }
11113
- var BindFrame = class {
11114
- constructor(it, binds, isFrame) {
11115
- this.it = it;
11116
- this.binds = binds;
11117
- this.isFrame = isFrame;
11118
- }
11119
- lookup(name) {
11120
- const v = this.binds[name];
11121
- return v === void 0 ? this.isFrame ? STOP : NEXT : v;
11122
- }
11123
- };
11124
- var ObjectFrame = class {
11125
- constructor(binds) {
11126
- this.binds = binds;
11127
- }
11128
- lookup(key) {
11129
- const v = this.binds[key];
11130
- return v === void 0 ? NEXT : v;
11131
- }
11132
- };
11133
- function computeViewsId(views) {
11134
- let s = "";
11135
- let n = views;
11136
- while (n !== null) {
11137
- s += n[0];
11138
- n = n[1];
11139
- }
11140
- return s === "main" ? "" : s;
11134
+ return initComponent(classFromData(opts.name ?? "UnkComp", opts), opts);
11141
11135
  }
11142
- var Stack = class _Stack {
11143
- constructor(comps, it, binds, dynBinds, views, viewsId, ctx = null) {
11144
- this.comps = comps;
11145
- this.it = it;
11146
- this.binds = binds;
11147
- this.dynBinds = dynBinds;
11148
- this.views = views;
11149
- this.viewsId = viewsId;
11150
- this.ctx = ctx;
11151
- }
11152
- // Evaluate every provide the entered component publishes and push them as one
11153
- // dynBinds frame, keyed by NAME. Published types go in the same frame: a type name
11154
- // starts A-Z and a value name does not, so the two namespaces cannot collide and
11155
- // nearest-ancestor-wins falls out of frame order for both. No-op with no provides.
11156
- _pushProvides() {
11157
- const comp = this.comps.getCompFor(this.it);
11158
- if (comp == null) return this;
11159
- const { provide, provideType } = comp;
11160
- const dynObj = {};
11161
- let has2 = false;
11162
- for (const k in provide) {
11163
- dynObj[k] = provide[k].val.eval(this);
11164
- has2 = true;
11165
- }
11166
- for (const k in provideType) {
11167
- dynObj[k] = provideType[k];
11168
- has2 = true;
11169
- }
11170
- if (!has2) return this;
11171
- const newDynBinds = [new ObjectFrame(dynObj), this.dynBinds];
11172
- const { comps, it, binds, views, viewsId, ctx } = this;
11173
- return new _Stack(comps, it, binds, newDynBinds, views, viewsId, ctx);
11174
- }
11175
- static root(comps, it, ctx) {
11176
- const binds = [new BindFrame(it, {}, true), null];
11177
- const dynBinds = [new ObjectFrame({}), null];
11178
- const views = ["main", null];
11179
- return new _Stack(comps, it, binds, dynBinds, views, "", ctx)._pushProvides();
11180
- }
11181
- enter(it, bindings = {}, isFrame = true) {
11182
- const { comps, binds, dynBinds, views, viewsId, ctx } = this;
11183
- const newBinds = [new BindFrame(it, bindings, isFrame), binds];
11184
- const stack = new _Stack(comps, it, newBinds, dynBinds, views, viewsId, ctx);
11185
- return isFrame ? stack._pushProvides() : stack;
11186
- }
11187
- pushViewName(name) {
11188
- const { comps, it, binds, dynBinds, views, ctx } = this;
11189
- const newViews = [name, views];
11190
- return new _Stack(comps, it, binds, dynBinds, newViews, computeViewsId(newViews), ctx);
11191
- }
11192
- // Published types are stable per scope and would only churn the render cache, so
11193
- // the cache key covers values alone.
11194
- _pushDynBindValuesToArray(arr, comp) {
11195
- for (const k in comp.provide) arr.push(this.lookupDynamic(k));
11196
- for (const k in comp.lookup) arr.push(this.lookupDynamic(k));
11197
- }
11198
- // `*name`: the nearest binding above (including this component's own provides,
11199
- // pushed on entering it), else this component's declared default, else null.
11200
- lookupDynamic(name) {
11201
- const v = lookup(this.dynBinds, name);
11202
- if (v != null) return v;
11203
- const comp = this.comps.getCompFor(this.it);
11204
- return comp?.lookup[name]?.val?.eval(this) ?? null;
11205
- }
11206
- lookupBind(name) {
11207
- return lookup(this.binds, name);
11208
- }
11209
- lookupFieldRaw(name) {
11210
- return this.it[name] ?? null;
11211
- }
11212
- lookupMethod(name) {
11213
- const fn = this.it[name];
11214
- return fn instanceof Function ? fn.call(this.it) : null;
11215
- }
11216
- // The dispatched DOM event / drag info, read only by EventMemberVal's
11217
- // `e.<member>` handler args. Null outside a live event transaction.
11218
- lookupEvent() {
11219
- return this.ctx?.event ?? null;
11220
- }
11221
- lookupDragInfo() {
11222
- return this.ctx?.dragInfo ?? null;
11223
- }
11224
- getHandlerFor(name, key) {
11225
- return this.comps.getHandlerFor(this.it, name, key);
11226
- }
11227
- lookupBestView(views, defaultViewName) {
11228
- let n = this.views;
11229
- while (n !== null) {
11230
- const view = views[n[0]];
11231
- if (view !== void 0) return view;
11232
- n = n[1];
11233
- }
11234
- return views[defaultViewName];
11235
- }
11236
- };
11237
11136
 
11238
11137
  // src/transactor.js
11239
11138
  var State2 = class {
@@ -11274,14 +11173,7 @@ var Transactor = class {
11274
11173
  // carry: kind, name, args, path, pathKeys, targetPath, handler, handlerName,
11275
11174
  // matched, before, after, parent, timestamp. Purely observational.
11276
11175
  observe(cb) {
11277
- this._observers.push(cb);
11278
- return () => {
11279
- const i = this._observers.indexOf(cb);
11280
- if (i !== -1) this._observers.splice(i, 1);
11281
- };
11282
- }
11283
- _emit(record) {
11284
- for (const cb of this._observers) cb(record);
11176
+ return subscribe(this._observers, cb);
11285
11177
  }
11286
11178
  // Record a refusal: a dispatch the runtime could not carry out. Kinds are
11287
11179
  // open strings; today the runtime raises NO_HANDLER (a receive name with no
@@ -11300,20 +11192,16 @@ var Transactor = class {
11300
11192
  // Subscribe to refusal records as they happen. Returns an unsubscribe fn,
11301
11193
  // like observe().
11302
11194
  observeRefusals(cb) {
11303
- this._refusalObservers.push(cb);
11304
- return () => {
11305
- const i = this._refusalObservers.indexOf(cb);
11306
- if (i !== -1) this._refusalObservers.splice(i, 1);
11307
- };
11195
+ return subscribe(this._refusalObservers, cb);
11308
11196
  }
11309
11197
  // Build and dispatch one observer record. Pins field-resolved keys (e.g. a
11310
11198
  // `.a[.selId]` render target reconstructed from a DOM event) against the root the
11311
11199
  // handler read, so pathKeys carries concrete keys instead of dropping the dynamic
11312
11200
  // step. No-op when nobody is observing.
11313
- _emitRecord(root, { kind, name, args, path, targetPath, handler, handlerName, matched, before, after, parent }) {
11201
+ _emitRecord(root, { kind, name, args, path: path2, targetPath, handler, handlerName, matched, before, after, parent }) {
11314
11202
  if (this._observers.length === 0) return;
11315
- const pinned = path.pinKeys(root);
11316
- this._emit({
11203
+ const pinned = path2.pinKeys(root);
11204
+ const record = {
11317
11205
  kind,
11318
11206
  name,
11319
11207
  args: args ?? null,
@@ -11327,14 +11215,14 @@ var Transactor = class {
11327
11215
  after,
11328
11216
  parent,
11329
11217
  timestamp: Date.now()
11330
- });
11218
+ };
11219
+ for (const cb of this._observers) cb(record);
11331
11220
  }
11332
11221
  // The observer record for a settled transaction. The resolved handler
11333
11222
  // (`_resolvedHandler`/`_matched`) and per-leaf before/after (`_before`/`_after`)
11334
11223
  // were captured while the handler ran (see callHandler / Transaction.run).
11335
11224
  _emitTransaction(transaction, root) {
11336
11225
  if (this._observers.length === 0) return;
11337
- if (transaction._resolvedHandler === void 0) return;
11338
11226
  this._emitRecord(root, {
11339
11227
  kind: transaction.observeKind,
11340
11228
  name: transaction.observeName,
@@ -11348,33 +11236,29 @@ var Transactor = class {
11348
11236
  parent: transaction.parentTransaction
11349
11237
  });
11350
11238
  }
11351
- // Make `child` a tracked unit of `parent`'s subtree: the parent's completion stays open
11352
- // until the child's *whole* subtree settles. Tracking happens at dispatch time — during
11353
- // the parent's handler or afterTransaction — while the parent's self-unit is still held,
11354
- // so the parent counter can't reach zero before the child is registered. Returns `child`.
11355
- _link(child, parent) {
11356
- if (parent) {
11357
- const release = parent.completion.track();
11358
- child.completion.whenSubtreeSettled().then(release);
11359
- }
11360
- return child;
11361
- }
11362
11239
  // `origin` is where the message came FROM, pinned now for the same reason an
11363
11240
  // intent's answerPath is: a reply must reach the sender that asked even if a key
11364
11241
  // moved while the message was in flight. Null when nobody is waiting — a host
11365
11242
  // sendAtRoot or a view's own `@on.*` — and ctx.sendReply refuses on that.
11366
- pushSend(path, name, args = [], parent = null, origin = null) {
11367
- const t = new SendEvent(path, this, name, args, parent);
11368
- t.origin = origin === null ? null : origin.toTransactionPath().pinKeys(this.state.val);
11243
+ //
11244
+ // The parent's subtree stays open until this message's whole subtree settles. The
11245
+ // unit is taken now, at dispatch — during the parent's handler or afterTransaction,
11246
+ // while the parent's self-unit is still held — so its counter can't reach zero first.
11247
+ pushSend(path2, name, args = [], parent = null, origin = null, txnPath = null) {
11248
+ const t = new SendEvent(path2, this, name, args, parent);
11249
+ t.txnPath = txnPath;
11250
+ t.origin = origin;
11251
+ t.originPinned = origin === null ? null : origin.toTransactionPath().pinKeys(this.state.val);
11369
11252
  this.pushTransaction(t);
11370
- return this._link(t, parent);
11253
+ if (parent) t.completion.carry(parent.completion.track());
11254
+ return t;
11371
11255
  }
11372
11256
  // Raise an intent: a job the sender did not address, walked along a route until
11373
11257
  // something answers. `opts.route` is a list of legs (see DEFAULT_ROUTE) and
11374
11258
  // `opts.livePath` opts out of pinning the answer's destination keys.
11375
- pushIntent(path, name, args = [], opts = {}, parent = null) {
11259
+ pushIntent(path2, name, args = [], opts = {}, parent = null) {
11376
11260
  const release = parent ? parent.completion.track() : null;
11377
- const walk = new IntentWalk(this, path, name, args, opts, parent, release);
11261
+ const walk = new IntentWalk(this, path2, name, args, opts, parent, release);
11378
11262
  walk.advance();
11379
11263
  return walk;
11380
11264
  }
@@ -11391,7 +11275,7 @@ var Transactor = class {
11391
11275
  return this.transactions.length > 0;
11392
11276
  }
11393
11277
  transactNext() {
11394
- if (this.hasPendingTransactions) this.transact(this.transactions.shift());
11278
+ this.transact(this.transactions.shift());
11395
11279
  }
11396
11280
  transact(transaction) {
11397
11281
  try {
@@ -11404,20 +11288,31 @@ var Transactor = class {
11404
11288
  } else console.warn("undefined new state", { curState, transaction });
11405
11289
  } finally {
11406
11290
  transaction.ensureWalkAdvanced?.();
11407
- transaction._completion?.ensureSelfSettled();
11408
- transaction._completion?.releaseSelf();
11291
+ transaction._completion?.finish();
11409
11292
  }
11410
11293
  }
11411
- transactInputNow(path, event, eventHandler, dragInfo) {
11412
- this.transact(new InputEvent(path, event, eventHandler, this, dragInfo));
11294
+ transactInputNow(path2, event, eventHandler, dragInfo) {
11295
+ this.transact(new InputEvent(path2, event, eventHandler, this, dragInfo));
11413
11296
  }
11414
11297
  };
11415
11298
  function nullHandler() {
11416
11299
  return this;
11417
11300
  }
11301
+ function subscribe(list, cb) {
11302
+ list.push(cb);
11303
+ return () => {
11304
+ const i = list.indexOf(cb);
11305
+ if (i !== -1) list.splice(i, 1);
11306
+ };
11307
+ }
11308
+ function warnUnknownLeg(what, leg) {
11309
+ console.warn(`unknown ${what} route leg`, leg, '- expected "dyn" or "lex"');
11310
+ return null;
11311
+ }
11418
11312
  var Transaction = class {
11419
- constructor(path, transactor, parentTransaction = null) {
11420
- this.path = path;
11313
+ constructor(path2, transactor, parentTransaction = null) {
11314
+ this.path = path2;
11315
+ this.txnPath = null;
11421
11316
  this.transactor = transactor;
11422
11317
  this.parentTransaction = parentTransaction;
11423
11318
  this._completion = null;
@@ -11437,39 +11332,41 @@ var Transaction = class {
11437
11332
  whenSubtreeSettled() {
11438
11333
  return this.completion.whenSubtreeSettled();
11439
11334
  }
11440
- afterTransaction() {
11441
- }
11442
- // Ending a walk and forwarding belong to the two dispatch buckets; the base warns
11443
- // rather than throwing, so a stray call from the wrong place is a message and not a
11444
- // crash. `walk` is undefined here, which is how ctx.reply/ctx.fail tell the two apart.
11445
- stop() {
11446
- warnNotIntent("stop");
11447
- }
11448
- forward(_opts) {
11449
- console.warn('ctx.forward() needs a "receive" or "intent" handler - ignored');
11450
- }
11451
- // The kind reported to observers (see Transactor.observe); null on the base.
11452
- get observeKind() {
11453
- return null;
11454
- }
11455
- // The name reported to observers; null on the base. Overridden by NameArgs (the
11456
- // dispatched message name) and InputEvent (the DOM event type). Kept separate from
11457
- // `name`/`ctx.name` so it can't change handler-visible behavior.
11458
- get observeName() {
11459
- return null;
11460
- }
11335
+ // Every transaction kind defines `observeKind` / `observeName` (what observers see;
11336
+ // kept apart from `name`/`ctx.name` so they can't change handler-visible behavior),
11337
+ // `getHandlerAndArgs(root, instance, comps)`, and the three `_forward*` hooks below.
11461
11338
  callHandler(root, instance, draft, comps) {
11462
11339
  const [handler, args] = this.getHandlerAndArgs(root, instance, comps);
11463
11340
  this._resolvedHandler = handler;
11464
11341
  return handler.apply(instance, [draft, ...args]);
11465
11342
  }
11466
- getHandlerAndArgs(_root, _instance, _comps) {
11467
- return null;
11343
+ // `forward` is where a name can LEAVE the component: the message being handled is
11344
+ // raised again as an INTENT under the same name (`_forwardName()`) with the same
11345
+ // arguments unless `opts.args` says otherwise, from the position `_forwardPath()`
11346
+ // names. Deferred to afterTransaction so the state the handler produced is in place
11347
+ // before the walk starts. (`IntentEvent` overrides both: in an intent body, forward
11348
+ // amends the walk that is already running.)
11349
+ forward(opts) {
11350
+ this._forward = opts ?? {};
11351
+ }
11352
+ afterTransaction() {
11353
+ const f = this._forward;
11354
+ if (f === void 0) return;
11355
+ this._forward = void 0;
11356
+ const name = this._forwardName();
11357
+ if (name === void 0) {
11358
+ this.transactor.refuse("FORWARD_NO_NAME", {});
11359
+ return;
11360
+ }
11361
+ const { args = this._forwardArgs(), ...rest } = f;
11362
+ this.transactor.pushIntent(this._forwardPath(), name, args, rest, this);
11468
11363
  }
11469
- // The path used to apply the mutation. Teleports dynamic-var renders so it lands on
11470
- // the data's real location (the dispatch `this.path` keeps intermediates).
11364
+ // The path used to apply the mutation: the ACTIVE frame of the dispatch path, so
11365
+ // an event inside a `<x render="*name">` subtree updates the value where it
11366
+ // really lives (the dispatch `this.path` keeps the visual callers, for bubbling).
11367
+ // `txnPath`, when pinned by the sender, wins.
11471
11368
  getTransactionPath() {
11472
- return this.path.toTransactionPath().compact();
11369
+ return this.txnPath ?? this.path.toTransactionPath();
11473
11370
  }
11474
11371
  run(curRoot, comps) {
11475
11372
  const txnPath = this.getTransactionPath();
@@ -11486,19 +11383,27 @@ var Transaction = class {
11486
11383
  }
11487
11384
  };
11488
11385
  var InputEvent = class extends Transaction {
11489
- constructor(path, e, handler, transactor, dragInfo) {
11490
- super(path, transactor);
11386
+ constructor(path2, e, handler, transactor, dragInfo) {
11387
+ super(path2, transactor);
11491
11388
  this.e = e;
11492
11389
  this.handler = handler;
11493
11390
  this.dragInfo = dragInfo;
11494
11391
  this._dispatchPath = null;
11495
11392
  }
11496
- // Frame steps removed, DynStep + one step per crossed component kept: bubbling
11497
- // it visits every component (including intermediates of a dynamic-var render).
11393
+ // Frame-only steps removed, one step per crossed component kept — inside every
11394
+ // continuation frame independently, so bubbling it visits every component and
11395
+ // then returns to the caller that wrote the `*name`.
11498
11396
  get dispatchPath() {
11499
11397
  this._dispatchPath ??= this.path.compact();
11500
11398
  return this._dispatchPath;
11501
11399
  }
11400
+ // Only a DOM event's path carries frame-only bind steps (they replay the handler's
11401
+ // arguments, but address no state); the compacted path is where the mutation lands,
11402
+ // so a handler inside @each still updates the component that owns the view. Every
11403
+ // other transaction is dispatched at an already-compacted position.
11404
+ getTransactionPath() {
11405
+ return this.dispatchPath.toTransactionPath();
11406
+ }
11502
11407
  // A DOM event is an ADDRESSED message like any other — it reaches the component that
11503
11408
  // owns the view and stops. It keeps its own class only because it resolves its handler
11504
11409
  // from the compiled view and runs synchronously, not because it is a different channel.
@@ -11508,47 +11413,36 @@ var InputEvent = class extends Transaction {
11508
11413
  get observeName() {
11509
11414
  return this.e?.type ?? null;
11510
11415
  }
11511
- // A view's name is a message. `forward` is where that name can LEAVE the component:
11512
- // it becomes an intent with the same name and the same arguments, so a view that says
11513
- // `@on.click="saveDraft .text"` never has to change when an ancestor takes the job over.
11514
- // (A `$method` handler has a name too, so forwarding one raises an intent under it.)
11515
- forward(opts) {
11516
- this._forward = opts ?? {};
11517
- }
11518
- afterTransaction() {
11519
- const f = this._forward;
11520
- if (f === void 0) return;
11521
- this._forward = void 0;
11522
- const { args = this._handlerArgs ?? [], ...rest } = f;
11416
+ // A view's name is a message, and forwarding it means a view that says
11417
+ // `@on.click="saveDraft .text"` never has to change when an ancestor takes the job
11418
+ // over. (A `$method` handler has a name too, so forwarding one raises an intent under
11419
+ // it.) `handler` is a NodeEvent, whose own `name` is the DOM event type; the MESSAGE
11420
+ // name is the one the view wrote, on the handler call it wraps.
11421
+ _forwardName() {
11523
11422
  const hv = this.handler?.handlerCall?.handlerVal ?? this.handler?.handlerVal;
11524
- const name = hv?.name;
11525
- if (name === void 0) {
11526
- this.transactor.refuse("FORWARD_NO_NAME", {});
11527
- return;
11528
- }
11529
- this.transactor.pushIntent(this.dispatchPath, name, args, rest, this);
11423
+ return hv?.name;
11424
+ }
11425
+ _forwardArgs() {
11426
+ return this._handlerArgs ?? [];
11427
+ }
11428
+ _forwardPath() {
11429
+ return this.dispatchPath;
11530
11430
  }
11531
11431
  getHandlerAndArgs(root, _instance, comps) {
11532
- const stack = this.path.toTransactionPath().buildStack(Stack.root(comps, root, this));
11432
+ const stack = this.path.buildStack(Stack.root(comps, root, this));
11533
11433
  const [handler, args] = this.handler.getHandlerAndArgs(stack, this);
11534
11434
  this._handlerArgs = [...args];
11535
- const path = this.dispatchPath;
11536
- args.push(new EventContext(path, this.transactor, this));
11435
+ const path2 = this.dispatchPath;
11436
+ args.push(new EventContext(path2, this.transactor, this));
11537
11437
  return [handler, args];
11538
11438
  }
11539
- // The dispatched DOM event, read only through `e.<member>` handler args
11540
- // (src/value.js EventMemberVal via Stack.lookupEvent). There is no bare
11541
- // implicit-name vocabulary anymore: every arg carries a sigil.
11542
- get event() {
11543
- return this.e;
11544
- }
11545
11439
  };
11546
11440
  var NameArgsTransaction = class extends Transaction {
11547
- constructor(path, transactor, name, args, parentTransaction) {
11548
- super(path, transactor, parentTransaction);
11441
+ constructor(path2, transactor, name, args, parentTransaction) {
11442
+ super(path2, transactor, parentTransaction);
11549
11443
  this.name = name;
11550
11444
  this.args = args;
11551
- this.targetPath = path;
11445
+ this.targetPath = path2;
11552
11446
  }
11553
11447
  handlerProp = null;
11554
11448
  // NameArgs verbs map their handler bucket straight to the observed kind:
@@ -11559,6 +11453,17 @@ var NameArgsTransaction = class extends Transaction {
11559
11453
  get observeName() {
11560
11454
  return this.name;
11561
11455
  }
11456
+ // `forward` in a RECEIVE body starts a walk: the message that arrived becomes an
11457
+ // intent, keeping its name and payload.
11458
+ _forwardName() {
11459
+ return this.name;
11460
+ }
11461
+ _forwardArgs() {
11462
+ return this.args;
11463
+ }
11464
+ _forwardPath() {
11465
+ return this.path;
11466
+ }
11562
11467
  getHandlerForName(comp) {
11563
11468
  const handlers = comp?.[this.handlerProp];
11564
11469
  const exact = handlers?.[this.name];
@@ -11589,24 +11494,11 @@ var SendEvent = class extends NameArgsTransaction {
11589
11494
  get observeKind() {
11590
11495
  return this._isAnswer ? "answer" : "receive";
11591
11496
  }
11592
- // `forward` in a RECEIVE body starts a walk: the message that arrived becomes an
11593
- // intent, keeping its name and payload. This is what lets a view's name leave the
11594
- // component without the view changing.
11595
- forward(opts) {
11596
- this._forward = opts ?? {};
11597
- }
11598
- afterTransaction() {
11599
- const f = this._forward;
11600
- if (f === void 0) return;
11601
- this._forward = void 0;
11602
- const { args = this.args, ...rest } = f;
11603
- this.transactor.pushIntent(this.path, this.name, args, rest, this);
11604
- }
11605
11497
  };
11606
11498
  var IntentEvent = class extends NameArgsTransaction {
11607
11499
  handlerProp = "intent";
11608
- constructor(path, transactor, walk) {
11609
- super(path, transactor, walk.name, walk.args, walk.parent);
11500
+ constructor(path2, transactor, walk) {
11501
+ super(path2, transactor, walk.name, walk.args, walk.parent);
11610
11502
  this.walk = walk;
11611
11503
  this.targetPath = walk.origin;
11612
11504
  }
@@ -11615,9 +11507,6 @@ var IntentEvent = class extends NameArgsTransaction {
11615
11507
  forward(opts) {
11616
11508
  this.walk.amend(opts, this.path);
11617
11509
  }
11618
- stop() {
11619
- this.walk.finish(null, null);
11620
- }
11621
11510
  afterTransaction() {
11622
11511
  this.ensureWalkAdvanced();
11623
11512
  }
@@ -11633,17 +11522,17 @@ var PASS = /* @__PURE__ */ Symbol.for("tutuca.intent.pass");
11633
11522
  var REFUSAL_RING_CAP = 200;
11634
11523
  var INTENT_DEPTH = 64;
11635
11524
  var IntentWalk = class {
11636
- constructor(transactor, path, name, args, opts, parent, release) {
11525
+ constructor(transactor, path2, name, args, opts, parent, release) {
11637
11526
  this.transactor = transactor;
11638
11527
  this.name = name;
11639
11528
  this.args = args;
11640
11529
  this.route = opts?.route ?? DEFAULT_ROUTE;
11641
11530
  this.parent = parent;
11642
11531
  this.release = release;
11643
- this.origin = path;
11644
- this.answerPath = opts?.livePath ? null : path.toTransactionPath().pinKeys(transactor.state.val);
11532
+ this.origin = path2;
11533
+ this.answerPath = opts?.livePath ? null : path2.toTransactionPath().pinKeys(transactor.state.val);
11645
11534
  this.legIndex = 0;
11646
- this.dynAt = path;
11535
+ this.dynAt = path2;
11647
11536
  this.hops = 0;
11648
11537
  this.ended = false;
11649
11538
  }
@@ -11655,7 +11544,7 @@ var IntentWalk = class {
11655
11544
  while (this.legIndex < this.route.length) {
11656
11545
  const leg = this.route[this.legIndex];
11657
11546
  if (leg === "dyn") {
11658
- if (this.dynAt.steps.length === 0) {
11547
+ if (!this.dynAt.canPop()) {
11659
11548
  this.legIndex++;
11660
11549
  continue;
11661
11550
  }
@@ -11667,7 +11556,7 @@ var IntentWalk = class {
11667
11556
  this.legIndex++;
11668
11557
  return this._tryLex();
11669
11558
  }
11670
- console.warn("unknown intent route leg", leg, '- expected "dyn" or "lex"');
11559
+ warnUnknownLeg("intent", leg);
11671
11560
  this.legIndex++;
11672
11561
  }
11673
11562
  this.exhaust("noHandler");
@@ -11752,11 +11641,11 @@ var IntentWalk = class {
11752
11641
  if (this.ended) return;
11753
11642
  this.ended = true;
11754
11643
  if (name === null) return this.release?.();
11755
- const path = this.answerPath ?? this.origin;
11756
- const t = new SendEvent(path, this.transactor, name, args, this.parent);
11644
+ const t = new SendEvent(this.origin, this.transactor, name, args, this.parent);
11645
+ t.txnPath = this.answerPath;
11757
11646
  t._isAnswer = true;
11758
11647
  this.transactor.pushTransaction(t);
11759
- if (this.release) t.completion.whenSubtreeSettled().then(this.release);
11648
+ if (this.release) t.completion.carry(this.release);
11760
11649
  }
11761
11650
  };
11762
11651
  var Completion = class {
@@ -11764,12 +11653,12 @@ var Completion = class {
11764
11653
  this.val = void 0;
11765
11654
  this.selfSettled = false;
11766
11655
  this.subtreeSettled = false;
11767
- this.pending = 1;
11656
+ this.pending = 0;
11768
11657
  this._selfResolve = null;
11769
11658
  this._selfPromise = null;
11770
11659
  this._subtreeResolve = null;
11771
11660
  this._subtreePromise = null;
11772
- this._selfReleased = false;
11661
+ this._releaseSelf = this.track();
11773
11662
  }
11774
11663
  whenSettled() {
11775
11664
  if (this.selfSettled) return Promise.resolve(this.val);
@@ -11792,38 +11681,38 @@ var Completion = class {
11792
11681
  this.val = val;
11793
11682
  this._selfResolve?.(val);
11794
11683
  }
11795
- // Settle self even when no handler produced a value (undefined-state / throw paths).
11796
- ensureSelfSettled() {
11797
- if (!this.selfSettled) this.markSelfSettled(this.val);
11684
+ // The transaction is done processing: self is settled (with the value the handler
11685
+ // produced, or none on the undefined-state / throw paths) and the self-unit goes.
11686
+ finish() {
11687
+ this.markSelfSettled(this.val);
11688
+ this._releaseSelf();
11798
11689
  }
11799
- // Register an outstanding unit; returns a one-shot release.
11690
+ // Register an outstanding unit; returns its one-shot release. The subtree settles
11691
+ // when the last unit is released.
11800
11692
  track() {
11801
11693
  this.pending++;
11802
11694
  let done = false;
11803
11695
  return () => {
11804
11696
  if (done) return;
11805
11697
  done = true;
11806
- this._release();
11698
+ if (--this.pending === 0) {
11699
+ this.subtreeSettled = true;
11700
+ this._subtreeResolve?.(this.val);
11701
+ }
11807
11702
  };
11808
11703
  }
11809
- releaseSelf() {
11810
- if (this._selfReleased) return;
11811
- this._selfReleased = true;
11812
- this._release();
11813
- }
11814
- _release() {
11815
- if (--this.pending === 0) {
11816
- this.subtreeSettled = true;
11817
- this._subtreeResolve?.(this.val);
11818
- }
11704
+ // Hand a unit held elsewhere to this subtree: `release` runs once this transaction
11705
+ // and everything it spawned have settled.
11706
+ carry(release) {
11707
+ this.whenSubtreeSettled().then(release);
11819
11708
  }
11820
11709
  };
11821
11710
  var Dispatcher = class {
11822
- constructor(path, transactor, parentTransaction, root = transactor.state.val) {
11823
- this.path = path;
11711
+ constructor(path2, transactor, parentTransaction) {
11712
+ this.path = path2;
11824
11713
  this.transactor = transactor;
11825
11714
  this.parent = parentTransaction;
11826
- this.root = root;
11715
+ this.root = transactor.state.val;
11827
11716
  }
11828
11717
  // Walk the component instances on this ctx's path, leaf→root, calling
11829
11718
  // callback(Component, instance). Return false from the callback to stop early.
@@ -11848,28 +11737,37 @@ var Dispatcher = class {
11848
11737
  // replayed; provides are pushed on every component frame either way, so a provide
11849
11738
  // that reads a loop binding is the one case this cannot reproduce faithfully.
11850
11739
  _stack() {
11851
- this._stackMemo ??= this.path.toTransactionPath().buildStack(Stack.root(this.transactor.comps, this.root, this.parent));
11740
+ this._stackMemo ??= this.path.buildStack(
11741
+ Stack.root(this.transactor.comps, this.root, this.parent)
11742
+ );
11852
11743
  return this._stackMemo;
11853
11744
  }
11854
11745
  // Resolve a name the way the renderer would. `opts.route` takes the same legs in
11855
11746
  // the same spelling as `ctx.intent` — `["dyn"]` the render ancestry, `["lex"]` the
11856
11747
  // registration scope, default both.
11748
+ // Legs are tried in route order, like the intent walker's; an unknown leg warns and
11749
+ // is skipped, and an empty route resolves to null.
11857
11750
  lookup(name, opts) {
11858
- return routeLookup(
11859
- opts?.route ?? DEFAULT_ROUTE,
11860
- () => this._lookupLex(name),
11861
- () => this._stack()?.lookupDynamic(name) ?? null
11862
- );
11751
+ for (const leg of opts?.route ?? DEFAULT_ROUTE) {
11752
+ const v = leg === "dyn" ? this._stack()?.lookupDynamic(name) ?? null : leg === "lex" ? this._lookupLex(name) : warnUnknownLeg("lookup", leg);
11753
+ if (v != null) return v;
11754
+ }
11755
+ return null;
11863
11756
  }
11864
11757
  // The `lex` leg without a Stack: the scope of the component whose handler is
11865
- // running, which is the leaf of this ctx's path.
11758
+ // running, which is the leaf of this ctx's path. A type name resolves to the
11759
+ // component registered under it; a value name to a path registered under it
11760
+ // (see ComponentStack.registerPaths), read against the current root.
11866
11761
  _lookupLex(name) {
11867
11762
  let Comp = null;
11868
11763
  this.walkPath((c) => {
11869
11764
  Comp = c;
11870
11765
  return false;
11871
11766
  });
11872
- return Comp?.scope?.lookupComponent(name) ?? null;
11767
+ const scope = Comp?.scope;
11768
+ if (scope == null) return null;
11769
+ if (isTypeName(name)) return scope.lookupComponent(name) ?? null;
11770
+ return scope.lookupPath(name)?.lookup(this.root) ?? null;
11873
11771
  }
11874
11772
  // A component lookup is a value lookup constrained to a component. The `lex` leg
11875
11773
  // can only ever answer with one; the `dyn` leg reads a binding an ancestor
@@ -11891,8 +11789,8 @@ var Dispatcher = class {
11891
11789
  send(name, args) {
11892
11790
  return this.sendAtPath(this.path, name, args);
11893
11791
  }
11894
- sendAtPath(path, name, args) {
11895
- return this.transactor.pushSend(path, name, args, this.parent, this.path);
11792
+ sendAtPath(path2, name, args) {
11793
+ return this.transactor.pushSend(path2, name, args, this.parent, this.path);
11896
11794
  }
11897
11795
  // An intent is ROUTED: it names a job and walks until something answers. The verb
11898
11796
  // does not decide which scope answers — `opts.route` does, written here at the call
@@ -11900,8 +11798,8 @@ var Dispatcher = class {
11900
11798
  intent(name, args, opts) {
11901
11799
  return this.intentAtPath(this.path, name, args, opts);
11902
11800
  }
11903
- intentAtPath(path, name, args, opts) {
11904
- return this.transactor.pushIntent(path, name, args, opts, this.parent);
11801
+ intentAtPath(path2, name, args, opts) {
11802
+ return this.transactor.pushIntent(path2, name, args, opts, this.parent);
11905
11803
  }
11906
11804
  };
11907
11805
  var EventContext = class extends Dispatcher {
@@ -11930,11 +11828,19 @@ var EventContext = class extends Dispatcher {
11930
11828
  this.transactor.refuse("NO_SENDER", { name });
11931
11829
  return null;
11932
11830
  }
11933
- return this.sendAtPath(origin, name, args);
11831
+ return this.transactor.pushSend(
11832
+ origin,
11833
+ name,
11834
+ args,
11835
+ this.parent,
11836
+ this.path,
11837
+ this.parent.originPinned
11838
+ );
11934
11839
  }
11935
- // End the walk answering nothing — "served, and no answer".
11840
+ // End the walk answering nothing — "served, and no answer". Like reply/fail,
11841
+ // legal only in an `intent` handler.
11936
11842
  stop() {
11937
- return this.parent.stop();
11843
+ return this.parent.walk === void 0 ? warnNotIntent("stop") : this.parent.walk.finish(null, null);
11938
11844
  }
11939
11845
  // From an `intent` body: hand the intent to the next hop, optionally amending it.
11940
11846
  // From a `receive` body: turn the message that arrived into an intent. One word from
@@ -11962,13 +11868,13 @@ var PathChanges = class extends PathBuilder {
11962
11868
  }
11963
11869
  };
11964
11870
  function rootDispatcher(transactor) {
11965
- return new Dispatcher(new Path([]), transactor, null);
11871
+ return new Dispatcher(new DispatchPath(), transactor, null);
11966
11872
  }
11967
11873
 
11968
11874
  // tools/core/results.js
11969
11875
  var ModuleInfo = class {
11970
- constructor({ path = null, present = /* @__PURE__ */ new Set(), counts = {}, warnings = [] }) {
11971
- this.path = path;
11876
+ constructor({ path: path2 = null, present = /* @__PURE__ */ new Set(), counts = {}, warnings = [] }) {
11877
+ this.path = path2;
11972
11878
  this.present = present;
11973
11879
  this.counts = counts;
11974
11880
  this.warnings = warnings;
@@ -12078,8 +11984,8 @@ var DescribeResult = class {
12078
11984
  }
12079
11985
  };
12080
11986
  var ModuleTestReport = class {
12081
- constructor({ path = null, suites = [], counts = { pass: 0, fail: 0, skip: 0, total: 0 } }) {
12082
- this.path = path;
11987
+ constructor({ path: path2 = null, suites = [], counts = { pass: 0, fail: 0, skip: 0, total: 0 } }) {
11988
+ this.path = path2;
12083
11989
  this.suites = suites;
12084
11990
  this.counts = counts;
12085
11991
  }
@@ -12122,8 +12028,8 @@ var Test = class {
12122
12028
  }
12123
12029
  };
12124
12030
  var ModuleTests = class {
12125
- constructor({ path = null, suites = [] } = {}) {
12126
- this.path = path;
12031
+ constructor({ path: path2 = null, suites = [] } = {}) {
12032
+ this.path = path2;
12127
12033
  this.suites = suites;
12128
12034
  }
12129
12035
  };
@@ -12145,8 +12051,8 @@ function titleFromArg(arg) {
12145
12051
  if (typeof arg === "function") return arg.name || "(anonymous)";
12146
12052
  return String(arg);
12147
12053
  }
12148
- function makeCollector({ path = null, components = [] } = {}) {
12149
- const moduleTests = new ModuleTests({ path, suites: [] });
12054
+ function makeCollector({ path: path2 = null, components = [] } = {}) {
12055
+ const moduleTests = new ModuleTests({ path: path2, suites: [] });
12150
12056
  const stack = [];
12151
12057
  function describe(...args) {
12152
12058
  let head;
@@ -12247,7 +12153,7 @@ async function driveStack(stack, value, phase, opts = {}) {
12247
12153
  val
12248
12154
  );
12249
12155
  });
12250
- dispatchPhase(rootDispatcher(transactor), new Path([]), phase, value);
12156
+ dispatchPhase(rootDispatcher(transactor), new DispatchPath(), phase, value);
12251
12157
  await transactor.settle();
12252
12158
  return transactor.state.val;
12253
12159
  }
@@ -12257,7 +12163,7 @@ async function drive(cfg, value, phase, opts = {}) {
12257
12163
  async function runTests({
12258
12164
  getTests,
12259
12165
  components = [],
12260
- path = null,
12166
+ path: path2 = null,
12261
12167
  expect: expect2,
12262
12168
  name = null,
12263
12169
  grep = null,
@@ -12268,13 +12174,13 @@ async function runTests({
12268
12174
  const counts = { pass: 0, fail: 0, skip: 0, total: 0 };
12269
12175
  if (typeof getTests !== "function") {
12270
12176
  return new TestReport({
12271
- modules: [new ModuleTestReport({ path, suites: [], counts })]
12177
+ modules: [new ModuleTestReport({ path: path2, suites: [], counts })]
12272
12178
  });
12273
12179
  }
12274
12180
  if (typeof expect2 !== "function") {
12275
12181
  throw new Error("runTests: expect must be provided (e.g. chai's expect)");
12276
12182
  }
12277
- const { describe, test: test3, moduleTests } = makeCollector({ path, components });
12183
+ const { describe, test: test3, moduleTests } = makeCollector({ path: path2, components });
12278
12184
  let _stack = null;
12279
12185
  const getStack = () => _stack ??= buildStack({ components, macros, intentHandlers });
12280
12186
  const driveLocal = (value, phase, opts = {}) => driveStack(getStack(), value, phase, opts);
@@ -12337,7 +12243,7 @@ async function runTests({
12337
12243
  if (r !== null) suiteResults.push(r);
12338
12244
  }
12339
12245
  return new TestReport({
12340
- modules: [new ModuleTestReport({ path, suites: suiteResults, counts })]
12246
+ modules: [new ModuleTestReport({ path: path2, suites: suiteResults, counts })]
12341
12247
  });
12342
12248
  }
12343
12249
 
@@ -12506,19 +12412,19 @@ function lintIdToMessage(id, info) {
12506
12412
  case "DYN_ALIAS_NOT_REFERENCED":
12507
12413
  return `Lookup '${info.name}' is defined but never used — remove it or reference it as '*${info.name}' in a view`;
12508
12414
  case "PROVIDE_NOT_ADDRESSABLE":
12509
- 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`;
12415
+ 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`;
12510
12416
  case "LOOKUP_BAD_SHAPE":
12511
12417
  return `Lookup '${info.name}' has an invalid shape: ${info.problem}`;
12512
12418
  case "LOOKUP_NO_PROVIDER":
12513
- 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`;
12419
+ 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`;
12514
12420
  case "PROVIDE_TYPE_BAD_SHAPE":
12515
12421
  return `Provide '${info.name}' starts uppercase, so it publishes a component type — its value must be 'self', not '${info.value}'`;
12516
- case "PROVIDE_NAME_COLLISION":
12517
- return `Provide '${info.name}' is also provided by '${info.other}' in the same scope — one name, one provider, so a lookup can find it`;
12518
12422
  case "UNKNOWN_MACRO_ARG":
12519
12423
  return `Argument '${info.name}' is not declared in macro '${info.macroName}'`;
12520
12424
  case "UNKNOWN_DIRECTIVE":
12521
12425
  return `Unknown directive '@${info.name}=${JSON.stringify(info.value)}'${fmtTagSuffix(info)}`;
12426
+ case "ORPHAN_DIRECTIVE":
12427
+ return `'@${info.name}=${JSON.stringify(info.value)}' needs an '@${info.needs}' on the same element — it was ignored${fmtTagSuffix(info)}`;
12522
12428
  case "UNKNOWN_X_OP":
12523
12429
  return `Unknown <x> op '${info.name}=${JSON.stringify(info.value)}'${fmtTagSuffix(info)}`;
12524
12430
  case "UNKNOWN_X_ATTR":
@@ -12652,7 +12558,6 @@ var App = class {
12652
12558
  this.transactor = new Transactor(comps, null);
12653
12559
  this.ParseContext = ParseContext2;
12654
12560
  this.renderer = renderer;
12655
- this.maxEventNodeDepth = Infinity;
12656
12561
  this._transactNextBatchId = this._evictCacheId = null;
12657
12562
  this._eventNames = new Set(_evs);
12658
12563
  this.dragInfo = this.curDragOver = null;
@@ -12679,18 +12584,17 @@ var App = class {
12679
12584
  _dispatchEvent(e) {
12680
12585
  const { type: type3 } = e;
12681
12586
  const isDrag = type3 === "dragover" || type3 === "dragstart" || type3 === "dragend" || type3 === "drop";
12682
- const { rootNode: root, maxEventNodeDepth: maxDepth, comps, transactor } = this;
12683
- const [path, handlers] = Path.fromNodeAndEventName(
12587
+ const { rootNode, comps, transactor } = this;
12588
+ const [path2, handlers] = DispatchPath.fromNodeAndEventName(
12684
12589
  e.target,
12685
12590
  type3,
12686
- root,
12687
- maxDepth,
12591
+ rootNode,
12688
12592
  comps,
12689
12593
  !isDrag
12690
12594
  );
12691
- if (isDrag) this._handleDragEvent(e, type3, path);
12692
- if (path !== null && handlers !== null)
12693
- for (const handler of handlers) transactor.transactInputNow(path, e, handler, this.dragInfo);
12595
+ if (isDrag) this._handleDragEvent(e, type3, path2);
12596
+ if (path2 !== null && handlers !== null)
12597
+ for (const handler of handlers) transactor.transactInputNow(path2, e, handler, this.dragInfo);
12694
12598
  }
12695
12599
  _handleTouchEvent(e) {
12696
12600
  const { type: type3 } = e;
@@ -12733,7 +12637,7 @@ var App = class {
12733
12637
  this._touch = null;
12734
12638
  }
12735
12639
  }
12736
- _handleDragEvent(e, type3, path) {
12640
+ _handleDragEvent(e, type3, path2) {
12737
12641
  if (type3 === "dragover") {
12738
12642
  const dropTarget = getClosestDropTarget(e.target, this.rootNode, Infinity);
12739
12643
  if (dropTarget !== null) {
@@ -12745,10 +12649,10 @@ var App = class {
12745
12649
  } else if (type3 === "dragstart") {
12746
12650
  e.target.dataset.dragging = 1;
12747
12651
  const rootValue = this.state.val;
12748
- const txnPath = path.compact().toTransactionPath();
12652
+ const txnPath = path2.compact().toTransactionPath();
12749
12653
  const value = txnPath.lookup(rootValue);
12750
12654
  const dragType = e.target.dataset.dragtype ?? "?";
12751
- const stack = path.toTransactionPath().buildStack(this.makeStack(rootValue));
12655
+ const stack = path2.buildStack(this.makeStack(rootValue));
12752
12656
  this.dragInfo = new DragInfo(stack, value, dragType, e.target);
12753
12657
  } else if (type3 === "drop") {
12754
12658
  e.preventDefault();
@@ -12793,10 +12697,9 @@ var App = class {
12793
12697
  }
12794
12698
  compile() {
12795
12699
  for (const Comp of this.comps.byId.values()) {
12796
- const meta = Comp[COMPONENT];
12797
- meta.compile(this.ParseContext);
12798
- for (const key in meta.views)
12799
- for (const name of meta.views[key].ctx.genEventNames()) this._eventNames.add(name);
12700
+ Comp.compile(this.ParseContext);
12701
+ for (const key in Comp.views)
12702
+ for (const name of Comp.views[key].ctx.genEventNames()) this._eventNames.add(name);
12800
12703
  }
12801
12704
  this._compiled = true;
12802
12705
  }
@@ -12819,11 +12722,13 @@ var App = class {
12819
12722
  }
12820
12723
  stop() {
12821
12724
  this.stopCacheEvictionInterval();
12725
+ clearTimeout(this._transactNextBatchId);
12726
+ this._transactNextBatchId = null;
12822
12727
  for (const name of this._eventNames)
12823
12728
  this.rootNode.removeEventListener(name, this, listenerOpts(name));
12824
12729
  }
12825
12730
  sendAtRoot(name, args) {
12826
- this.transactor.pushSend(new Path([]), name, args);
12731
+ this.transactor.pushSend(new DispatchPath(), name, args);
12827
12732
  }
12828
12733
  registerComponents(comps, opts) {
12829
12734
  const scope = this.compStack.enter();
@@ -12905,28 +12810,21 @@ var NullDomCache = class {
12905
12810
  set(_keys, _cacheKey, _v) {
12906
12811
  }
12907
12812
  evict() {
12908
- return { hit: 0, miss: 0, badKey: 0 };
12909
12813
  }
12910
12814
  };
12911
12815
  var WeakMapDomCache = class {
12912
12816
  constructor() {
12913
- this.hit = this.miss = this.badKey = 0;
12914
12817
  this.keysByLen = /* @__PURE__ */ new Map();
12915
12818
  }
12916
- _returnValue(r) {
12917
- if (r === void 0) this.miss += 1;
12918
- else this.hit += 1;
12919
- return r;
12920
- }
12921
12819
  get(keys, cacheKey) {
12922
12820
  const len = keys.length;
12923
12821
  let cur = this.keysByLen.get(len);
12924
- if (!cur) return this._returnValue(void 0);
12822
+ if (!cur) return void 0;
12925
12823
  for (let i = 0; i < len - 1; i++) {
12926
12824
  cur = cur.get(keys[i]);
12927
- if (!cur) return this._returnValue(void 0);
12825
+ if (!cur) return void 0;
12928
12826
  }
12929
- return this._returnValue(cur.get(keys[len - 1])?.[cacheKey]);
12827
+ return cur.get(keys[len - 1])?.[cacheKey];
12930
12828
  }
12931
12829
  set(keys, cacheKey, v) {
12932
12830
  const len = keys.length;
@@ -12939,10 +12837,7 @@ var WeakMapDomCache = class {
12939
12837
  const key = keys[i];
12940
12838
  let next = cur.get(key);
12941
12839
  if (!next) {
12942
- if (!isWeakKey(key)) {
12943
- this.badKey += 1;
12944
- return;
12945
- }
12840
+ if (!isWeakKey(key)) return;
12946
12841
  next = /* @__PURE__ */ new WeakMap();
12947
12842
  cur.set(key, next);
12948
12843
  }
@@ -12952,23 +12847,38 @@ var WeakMapDomCache = class {
12952
12847
  const leaf = cur.get(lastKey);
12953
12848
  if (leaf) leaf[cacheKey] = v;
12954
12849
  else if (isWeakKey(lastKey)) cur.set(lastKey, { [cacheKey]: v });
12955
- else this.badKey += 1;
12956
12850
  }
12957
12851
  evict() {
12958
- const { hit, miss, badKey } = this;
12959
- this.hit = this.miss = this.badKey = 0;
12960
12852
  this.keysByLen = /* @__PURE__ */ new Map();
12961
- return { hit, miss, badKey };
12962
12853
  }
12963
12854
  };
12964
12855
 
12965
12856
  // src/renderer.js
12966
- var DATASET_ATTRS = ["nid", "cid", "eid", "vid", "si", "sk"];
12857
+ function stampRenderBase(vdom, text) {
12858
+ if (vdom instanceof VNode)
12859
+ return new VNode(
12860
+ vdom.tag,
12861
+ { ...vdom.attrs, "data-rp": text },
12862
+ vdom.childs,
12863
+ vdom.key,
12864
+ vdom.namespace
12865
+ );
12866
+ if (vdom instanceof VFragment)
12867
+ return new VFragment(vdom.childs.map((c) => stampRenderBase(c, text)));
12868
+ return vdom;
12869
+ }
12967
12870
  var Renderer = class {
12968
12871
  constructor(comps) {
12969
12872
  this.comps = comps;
12970
12873
  this.cache = new WeakMapDomCache();
12971
- this.renderTag = h;
12874
+ }
12875
+ // Parse nodes build their VDOM through the renderer, never by importing vdom.js
12876
+ // themselves: a component may have been compiled by ANOTHER copy of the library
12877
+ // (a docs example imports the dist bundle while the host app runs from src), and
12878
+ // `render()` recognizes VNodes by `instanceof` against ITS copy's classes. Going
12879
+ // through `rx` guarantees the rendering copy makes them.
12880
+ renderTag(tag, attrs, childs, namespace) {
12881
+ return h(tag, attrs, childs, namespace);
12972
12882
  }
12973
12883
  renderFragment(childs) {
12974
12884
  return new VFragment(childs);
@@ -12979,38 +12889,24 @@ var Renderer = class {
12979
12889
  setNullCache() {
12980
12890
  this.cache = new NullDomCache();
12981
12891
  }
12982
- // Library utilities for consumers embedding tutuca: render a value to a detached
12983
- // DOM node / an HTML string. Not called by the framework itself.
12984
- renderToDOM(stack, val) {
12985
- const rootNode = document.createElement("div");
12986
- const rOpts = { document };
12987
- render(h("DIV", null, [this.renderRoot(stack, val)]), rootNode, rOpts);
12988
- return rootNode.childNodes[0];
12989
- }
12990
- renderToString(stack, val, cleanAttrs = true) {
12991
- const dom = this.renderToDOM(stack, val);
12992
- if (cleanAttrs) {
12993
- const nodes = dom.querySelectorAll("[data-nid],[data-cid],[data-eid]");
12994
- for (const { dataset } of nodes) for (const name of DATASET_ATTRS) delete dataset[name];
12995
- }
12996
- return dom.innerHTML;
12997
- }
12998
12892
  renderRoot(stack, val, viewName = null) {
12999
12893
  const comp = this.comps.getCompFor(val);
13000
12894
  if (comp === null) return null;
13001
12895
  return this._rValComp(stack, val, comp, comp.getView(viewName).anode, "ROOT", viewName);
13002
12896
  }
13003
- renderIt(stack, node, key, viewName) {
12897
+ // Render `stack.it` at a `<x render*>` site (`node`). `base` is the absolute
12898
+ // path the site resumed at, when it rendered a `*name` (see _rValComp).
12899
+ renderIt(stack, node, viewName, base = null) {
13004
12900
  const comp = this.comps.getCompFor(stack.it);
13005
- return comp ? this._rValComp(stack, stack.it, comp, node, key, viewName) : null;
12901
+ return comp ? this._rValComp(stack, stack.it, comp, node, "", viewName, base) : null;
13006
12902
  }
13007
12903
  // `node` is the parse node of the render site (`<x render>` / `render-it` /
13008
12904
  // `render-each`, or the view's root anode for the app root). It keys the
13009
12905
  // cache as a globally-unique object: node ids alone are unique only within a
13010
12906
  // single view, so the same value rendered by two components (e.g. through a
13011
12907
  // shared dynamic-var sequence) would otherwise collide in the cache.
13012
- _rValComp(stack, val, comp, node, key, viewName) {
13013
- const cacheKey = `${viewName ?? ""}${stack.viewsId ?? ""}${key}`;
12908
+ _rValComp(stack, val, comp, node, key, viewName, base = null) {
12909
+ const cacheKey = `${viewName ?? ""}${stack.viewsId ?? ""}${key}${stack.renderPath.addressKey}`;
13014
12910
  const cachePath = [node, val];
13015
12911
  stack._pushDynBindValuesToArray(cachePath, comp);
13016
12912
  const cachedNode = this.cache.get(cachePath, cacheKey);
@@ -13018,30 +12914,43 @@ var Renderer = class {
13018
12914
  const view = viewName ? comp.getView(viewName) : stack.lookupBestView(comp.views, "main");
13019
12915
  const body = this.renderView(view, stack);
13020
12916
  if (body == null) return null;
12917
+ const baseJson = base === null ? null : pathToJson(base);
13021
12918
  const meta = this._renderMetadata({
13022
12919
  $: "Comp",
13023
12920
  nid: node?.nodeId ?? null,
13024
12921
  cid: comp.id,
13025
- vid: view.name
12922
+ vid: view.name,
12923
+ ...baseJson === null ? null : { base: baseJson }
13026
12924
  });
13027
- const dom = new VFragment([meta, body]);
12925
+ const dom = new VFragment([
12926
+ meta,
12927
+ baseJson === null ? body : stampRenderBase(body, JSON.stringify(baseJson))
12928
+ ]);
13028
12929
  this.cache.set(cachePath, cacheKey, dom);
13029
12930
  return dom;
13030
12931
  }
13031
12932
  pushEachEntry(r, nid, attrName, key, dom) {
13032
12933
  r.push(this._renderMetadata({ $: "Each", nid, [attrName]: key }), dom);
13033
12934
  }
13034
- renderEachWhen(stack, iterInfo, view, nid) {
13035
- const { seq, filter, loopWith, enricher } = iterInfo.eval(stack);
12935
+ renderEachWhen(stack, each2) {
12936
+ const { val: seqVal, node: view, nodeId: nid } = each2;
12937
+ const { seq, filter, loopWith, enricher } = each2.evalIter(stack);
12938
+ const seqPath = seqVal instanceof DynVal ? stack.lookupDynamicLocated(seqVal.name)?.path ?? null : null;
13036
12939
  const r = [];
13037
12940
  const it = stack.it;
13038
12941
  const renderOne = (key, value, attrName, binds) => {
12942
+ const itemBase = seqPath === null ? null : keyedPath(seqPath, key);
12943
+ const itemStep = itemBase === null ? each2.itemStep(key) : null;
12944
+ const itemPath = itemBase !== null ? stack.renderPath.pushFrame(itemBase) : itemStep !== null ? stack.renderPath.pushItem(itemStep) : stack.renderPath;
13039
12945
  const cachePath = enricher ? [view, it, value] : [view, value];
13040
- const cacheKey = `${stack.viewsId ?? ""}${nid}${key}`;
12946
+ const cacheKey = `${stack.viewsId ?? ""}${nid}${key}${itemPath.addressKey}`;
13041
12947
  const cachedNode = this.cache.get(cachePath, cacheKey);
13042
12948
  if (cachedNode) this.pushEachEntry(r, nid, attrName, key, cachedNode);
13043
12949
  else {
13044
- const dom = this.renderView(view, stack.enter(value, binds, false));
12950
+ const dom = this.renderView(
12951
+ view,
12952
+ stack.enter(value, binds, false, itemPath, itemBase !== null)
12953
+ );
13045
12954
  if (dom != null) this.pushEachEntry(r, nid, attrName, key, dom);
13046
12955
  this.cache.set(cachePath, cacheKey, dom);
13047
12956
  }
@@ -13190,12 +13099,7 @@ function shadowCheckComponent(Comp) {
13190
13099
  shadowViews[name] = { name, ctx, rawView };
13191
13100
  }
13192
13101
  const shadowComp = Object.create(Comp);
13193
- Object.defineProperty(shadowComp, "views", {
13194
- value: shadowViews,
13195
- writable: true,
13196
- enumerable: true,
13197
- configurable: true
13198
- });
13102
+ shadowComp.views = shadowViews;
13199
13103
  return checkComponent(shadowComp).reports;
13200
13104
  }
13201
13105
  function check(app) {
@@ -13221,39 +13125,6 @@ function check(app) {
13221
13125
  );
13222
13126
  return counts;
13223
13127
  }
13224
- var LintClassCollectorCtx = class _LintClassCollectorCtx extends ParseCtxClassSetCollector {
13225
- constructor(...args) {
13226
- super(...args);
13227
- this.attrs = [];
13228
- this.parseIssues = [];
13229
- }
13230
- enterMacro(macroName, macroVars, macroSlots) {
13231
- const { document: document2, Text, Comment, nodes, events: events2, macroNodes } = this;
13232
- const frame = { macroName, macroVars, macroSlots };
13233
- const v = new _LintClassCollectorCtx(
13234
- document2,
13235
- Text,
13236
- Comment,
13237
- nodes,
13238
- events2,
13239
- macroNodes,
13240
- frame,
13241
- this
13242
- );
13243
- v.classes = this.classes;
13244
- v.attrs = this.attrs;
13245
- v.parseIssues = this.parseIssues;
13246
- return v;
13247
- }
13248
- onAttributes(attrs, wrapperAttrs, textChild, isMacroCall = false, tag = null) {
13249
- super.onAttributes(attrs, wrapperAttrs, textChild, isMacroCall, tag);
13250
- this.attrs.push({ attrs, wrapperAttrs, textChild, isMacroCall, tag });
13251
- }
13252
- onParseIssue(kind, info) {
13253
- const tag = this.currentTag;
13254
- this.parseIssues.push({ kind, info: tag && info.tag === void 0 ? { ...info, tag } : info });
13255
- }
13256
- };
13257
13128
  export {
13258
13129
  ALT_HANDLER_NOT_DEFINED,
13259
13130
  ALT_HANDLER_NOT_REFERENCED,
@@ -13273,7 +13144,6 @@ export {
13273
13144
  DescribeResult,
13274
13145
  EVENT_HANDLER_METHOD_NOT_ALLOWED,
13275
13146
  ExampleIndex,
13276
- FIELD_CLASS,
13277
13147
  FIELD_METHOD_NAME_COLLISION,
13278
13148
  FIELD_VAL_IS_METHOD,
13279
13149
  FIELD_VAL_NOT_DEFINED,
@@ -13282,7 +13152,6 @@ export {
13282
13152
  IF_NO_BRANCH_SET,
13283
13153
  LOOKUP_BAD_SHAPE,
13284
13154
  LOOKUP_NO_PROVIDER,
13285
- LintClassCollectorCtx,
13286
13155
  LintComponentResult,
13287
13156
  LintContext,
13288
13157
  LintFinding,
@@ -13295,9 +13164,9 @@ export {
13295
13164
  ModuleInfo,
13296
13165
  ModuleTestReport,
13297
13166
  ModuleTests,
13167
+ ORPHAN_DIRECTIVE,
13298
13168
  PASS,
13299
13169
  PLACEHOLDERLESS_TEMPLATE_STRING,
13300
- PROVIDE_NAME_COLLISION,
13301
13170
  PROVIDE_NOT_ADDRESSABLE,
13302
13171
  PROVIDE_TYPE_BAD_SHAPE,
13303
13172
  ParseContext,
@@ -13338,6 +13207,7 @@ export {
13338
13207
  lintIdToMessage,
13339
13208
  macro,
13340
13209
  makeCollector,
13210
+ path,
13341
13211
  phaseOps,
13342
13212
  reportTestReportToConsole,
13343
13213
  resolveArgs,