tutuca 0.14.0 → 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.
@@ -1073,7 +1073,7 @@ function pathFromJson(j) {
1073
1073
  function walkItems(stack, items, renderPath, path) {
1074
1074
  let prev = stack.it;
1075
1075
  for (const step of items) {
1076
- const next = step.lookup(prev, NONE);
1076
+ const next = step.lookup(prev);
1077
1077
  if (next === NONE) {
1078
1078
  console.warn("bad PathItem", { root: stack.it, step, path });
1079
1079
  return null;
@@ -1132,18 +1132,12 @@ function resolvePathPart(comp, nodeRefs, vid) {
1132
1132
  }
1133
1133
  return null;
1134
1134
  }
1135
- var NONE, readKey, writeKey, writeSeqKey, Step, BindStep, ScopeBindStep, FieldStep, SeqStep, SeqAccessStep, EachBindStep, EachRenderItStep, Path, EMPTY_PATH, DispatchPath, StepCtx, NO_EVENT_INFO, BUBBLING_EVENTS, PathBuilder;
1135
+ var NONE, writeKey, writeSeqKey, Step, BindStep, ScopeBindStep, FieldStep, SeqStep, SeqAccessStep, EachBindStep, EachRenderItStep, Path, EMPTY_PATH, DispatchPath, StepCtx, NO_EVENT_INFO, BUBBLING_EVENTS, PathBuilder;
1136
1136
  var init_path = __esm({
1137
1137
  "src/path.js"() {
1138
1138
  init_collection();
1139
1139
  init_immer2();
1140
1140
  NONE = /* @__PURE__ */ Symbol("NONE");
1141
- readKey = (value, key, dval = null) => {
1142
- if (value == null) return dval;
1143
- if (value instanceof Map) return value.has(key) ? value.get(key) : dval;
1144
- if (value instanceof Set) return value.has(key) ? key : dval;
1145
- return Object.hasOwn(value, key) ? value[key] : dval;
1146
- };
1147
1141
  writeKey = (value, key, next) => {
1148
1142
  if (value instanceof Map) value.set(key, next);
1149
1143
  else if (value instanceof Set) {
@@ -1151,16 +1145,8 @@ var init_path = __esm({
1151
1145
  value.add(next);
1152
1146
  } else value[key] = next;
1153
1147
  };
1154
- writeSeqKey = (value, key, next) => {
1155
- if (value instanceof Map || value instanceof Set || Array.isArray(value) || Object.hasOwn(value, key))
1156
- writeKey(value, key, next);
1157
- else if (typeof value?.set === "function") value.set(key, next);
1158
- else writeKey(value, key, next);
1159
- };
1148
+ 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);
1160
1149
  Step = class {
1161
- lookup(_v, dval = null) {
1162
- return dval;
1163
- }
1164
1150
  setDraftValue(_root, _v) {
1165
1151
  }
1166
1152
  // Re-enter this step while rebuilding a stack. `renderPath` is the dispatch
@@ -1184,28 +1170,22 @@ var init_path = __esm({
1184
1170
  return null;
1185
1171
  }
1186
1172
  };
1187
- BindStep = class _BindStep extends Step {
1173
+ BindStep = class extends Step {
1188
1174
  constructor(binds) {
1189
1175
  super();
1190
1176
  this.binds = binds;
1191
1177
  }
1192
- lookup(v, _dval) {
1178
+ lookup(v) {
1193
1179
  return v;
1194
1180
  }
1195
1181
  enterFrame(stack, next, renderPath) {
1196
1182
  return stack.enter(next, { ...this.binds }, false, renderPath);
1197
1183
  }
1198
- withIndex(i) {
1199
- return new _BindStep({ ...this.binds, key: i });
1200
- }
1201
- withKey(key) {
1202
- return new _BindStep({ ...this.binds, key });
1203
- }
1204
1184
  toAbstractPathStep() {
1205
1185
  return null;
1206
1186
  }
1207
1187
  };
1208
- ScopeBindStep = class _ScopeBindStep extends BindStep {
1188
+ ScopeBindStep = class extends BindStep {
1209
1189
  constructor(val, binds = {}) {
1210
1190
  super(binds);
1211
1191
  this.val = val;
@@ -1214,30 +1194,18 @@ var init_path = __esm({
1214
1194
  const dyn = this.val.evalAsHandler(stack)?.call(stack.it) ?? {};
1215
1195
  return stack.enter(next, { ...this.binds, ...dyn }, false, renderPath);
1216
1196
  }
1217
- withIndex(i) {
1218
- return new _ScopeBindStep(this.val, { ...this.binds, key: i });
1219
- }
1220
- withKey(key) {
1221
- return new _ScopeBindStep(this.val, { ...this.binds, key });
1222
- }
1223
1197
  };
1224
1198
  FieldStep = class extends Step {
1225
1199
  constructor(field) {
1226
1200
  super();
1227
1201
  this.field = field;
1228
1202
  }
1229
- lookup(v, dval = null) {
1230
- return readKey(v, this.field, dval);
1203
+ lookup(v) {
1204
+ return seqGet(v, this.field, NONE);
1231
1205
  }
1232
1206
  setDraftValue(root, v) {
1233
1207
  writeKey(root, this.field, v);
1234
1208
  }
1235
- withIndex(i) {
1236
- return new SeqStep(this.field, i);
1237
- }
1238
- withKey(k) {
1239
- return new SeqStep(this.field, k);
1240
- }
1241
1209
  toKey() {
1242
1210
  return { field: this.field };
1243
1211
  }
@@ -1248,11 +1216,11 @@ var init_path = __esm({
1248
1216
  this.field = field;
1249
1217
  this.key = key;
1250
1218
  }
1251
- lookup(v, dval = null) {
1252
- return seqGet(readKey(v, this.field, null), this.key, dval);
1219
+ lookup(v) {
1220
+ return seqGet(seqGet(v, this.field, null), this.key, NONE);
1253
1221
  }
1254
1222
  setDraftValue(root, v) {
1255
- const seq = readKey(root, this.field, null);
1223
+ const seq = seqGet(root, this.field, null);
1256
1224
  if (seq != null) writeSeqKey(seq, this.key, v);
1257
1225
  }
1258
1226
  enterFrame(stack, next, renderPath) {
@@ -1268,20 +1236,20 @@ var init_path = __esm({
1268
1236
  this.seqField = seqField;
1269
1237
  this.keyField = keyField;
1270
1238
  }
1271
- lookup(v, dval = null) {
1272
- const seq = readKey(v, this.seqField, NONE);
1273
- const key = readKey(v, this.keyField, NONE);
1274
- return key !== NONE && seq !== NONE ? seqGet(seq, key, dval) : dval;
1239
+ lookup(v) {
1240
+ const seq = seqGet(v, this.seqField, NONE);
1241
+ const key = seqGet(v, this.keyField, NONE);
1242
+ return key !== NONE && seq !== NONE ? seqGet(seq, key, NONE) : NONE;
1275
1243
  }
1276
1244
  setDraftValue(root, v) {
1277
- const seq = readKey(root, this.seqField, NONE);
1278
- const key = readKey(root, this.keyField, NONE);
1245
+ const seq = seqGet(root, this.seqField, NONE);
1246
+ const key = seqGet(root, this.keyField, NONE);
1279
1247
  if (seq !== NONE && key !== NONE) writeSeqKey(seq, key, v);
1280
1248
  }
1281
1249
  // Resolve `keyField` against `v` now and freeze it as a literal-key `SeqStep`, so a
1282
1250
  // later lookup/setValue lands on this same item even if `keyField` changes meanwhile.
1283
1251
  pinKey(v) {
1284
- const key = readKey(v, this.keyField, NONE);
1252
+ const key = seqGet(v, this.keyField, NONE);
1285
1253
  return key === NONE ? this : new SeqStep(this.seqField, key);
1286
1254
  }
1287
1255
  // The key is a *field reference* resolved live, so it is unknown without a value;
@@ -1292,18 +1260,18 @@ var init_path = __esm({
1292
1260
  }
1293
1261
  };
1294
1262
  EachBindStep = class extends Step {
1295
- constructor(iterInfo, key) {
1263
+ constructor(eachNode, key) {
1296
1264
  super();
1297
- this.iterInfo = iterInfo;
1265
+ this.eachNode = eachNode;
1298
1266
  this.key = key;
1299
1267
  }
1300
- lookup(v, _dval) {
1268
+ lookup(v) {
1301
1269
  return v;
1302
1270
  }
1303
1271
  // Replay the renderer's per-item binds (key, value + any @enrich-with binds)
1304
1272
  // so a rebuilt stack matches the one @each rendered with.
1305
1273
  enterFrame(stack, next, renderPath) {
1306
- return stack.enter(next, this.iterInfo.enrichBinds(stack, this.key), false, renderPath);
1274
+ return stack.enter(next, this.eachNode.enrichBinds(stack, this.key), false, renderPath);
1307
1275
  }
1308
1276
  toAbstractPathStep() {
1309
1277
  return null;
@@ -1324,9 +1292,6 @@ var init_path = __esm({
1324
1292
  concat(steps) {
1325
1293
  return new _Path(this.steps.concat(steps));
1326
1294
  }
1327
- popStep() {
1328
- return new _Path(this.steps.slice(0, -1));
1329
- }
1330
1295
  // Frame-only steps removed, one step per crossed component: `popStep` over the
1331
1296
  // result bubbles through every component.
1332
1297
  compact() {
@@ -1348,7 +1313,7 @@ var init_path = __esm({
1348
1313
  const step = this.steps[i];
1349
1314
  const pinned = step.pinKey(curVal);
1350
1315
  if (pinned !== step) (out ??= this.steps.slice())[i] = pinned;
1351
- curVal = step.lookup(curVal, NONE);
1316
+ curVal = step.lookup(curVal);
1352
1317
  if (curVal === NONE) break;
1353
1318
  }
1354
1319
  return out ? new _Path(out) : this;
@@ -1356,7 +1321,7 @@ var init_path = __esm({
1356
1321
  lookup(v, dval = null) {
1357
1322
  let curVal = v;
1358
1323
  for (const step of this.steps) {
1359
- curVal = step.lookup(curVal, NONE);
1324
+ curVal = step.lookup(curVal);
1360
1325
  if (curVal === NONE) return dval;
1361
1326
  }
1362
1327
  return curVal;
@@ -1369,7 +1334,7 @@ var init_path = __esm({
1369
1334
  const out = [root];
1370
1335
  let curVal = root;
1371
1336
  for (const step of this.steps) {
1372
- curVal = step.lookup(curVal, NONE);
1337
+ curVal = step.lookup(curVal);
1373
1338
  if (curVal === NONE) break;
1374
1339
  out.push(curVal);
1375
1340
  }
@@ -1392,15 +1357,12 @@ var init_path = __esm({
1392
1357
  return produce(root, (draft) => {
1393
1358
  let parent = draft;
1394
1359
  for (let i = 0; i < this.steps.length - 1; i++) {
1395
- parent = this.steps[i].lookup(parent, NONE);
1360
+ parent = this.steps[i].lookup(parent);
1396
1361
  if (parent === NONE) return;
1397
1362
  }
1398
1363
  this.steps.at(-1).setDraftValue(parent, v);
1399
1364
  });
1400
1365
  }
1401
- buildStack(stack) {
1402
- return walkItems(stack, this.steps, stack.renderPath ?? new DispatchPath(), this)?.[0] ?? null;
1403
- }
1404
1366
  };
1405
1367
  EMPTY_PATH = new Path([]);
1406
1368
  DispatchPath = class _DispatchPath {
@@ -1421,7 +1383,6 @@ var init_path = __esm({
1421
1383
  return new _DispatchPath(frames);
1422
1384
  }
1423
1385
  concat(steps) {
1424
- if (this.frames.length === 0) return _DispatchPath.ofSteps(steps);
1425
1386
  return this._withTopItems(this.top.items.concat(steps));
1426
1387
  }
1427
1388
  pushItem(step) {
@@ -1431,23 +1392,17 @@ var init_path = __esm({
1431
1392
  return new _DispatchPath(this.frames.concat({ base, items: [] }));
1432
1393
  }
1433
1394
  // Whether bubbling has anywhere left to go: another step in this frame, or a
1434
- // visual caller underneath it.
1395
+ // visual caller underneath it. (A path always has at least one frame.)
1435
1396
  canPop() {
1436
- const n = this.frames.length;
1437
- return n > 1 || n === 1 && this.frames[0].items.length > 0;
1438
- }
1439
- isRoot() {
1440
- return this.toTransactionPath().steps.length === 0;
1397
+ return this.frames.length > 1 || this.frames[0].items.length > 0;
1441
1398
  }
1442
1399
  // One component closer to the root. At the top of a frame that is popping back
1443
1400
  // to the visual caller, not to the producer's own parent — the caller is where
1444
1401
  // the `*name` was written, and where an unhandled message should keep going.
1445
1402
  popStep() {
1446
- const n = this.frames.length;
1447
- if (n === 0) return this;
1448
- const top = this.frames[n - 1];
1403
+ const { top } = this;
1449
1404
  if (top.items.length > 0) return this._withTopItems(top.items.slice(0, -1));
1450
- if (n > 1) return new _DispatchPath(this.frames.slice(0, -1));
1405
+ if (this.frames.length > 1) return new _DispatchPath(this.frames.slice(0, -1));
1451
1406
  return this;
1452
1407
  }
1453
1408
  // Drop frame-only steps inside every frame independently; a frame's base is
@@ -1469,8 +1424,8 @@ var init_path = __esm({
1469
1424
  // The active transaction address: the top frame's absolute base followed by
1470
1425
  // its ordinary descendant steps. This is where a mutation lands.
1471
1426
  toTransactionPath() {
1472
- const top = this.top;
1473
- return top === void 0 ? EMPTY_PATH : top.base.concat(top.items);
1427
+ const { base, items } = this.top;
1428
+ return base.concat(items);
1474
1429
  }
1475
1430
  // Rebuild the render stack this path was dispatched from. A frame with a base
1476
1431
  // re-enters at that absolute value first — replaying the resume a `*name`
@@ -1494,10 +1449,12 @@ var init_path = __esm({
1494
1449
  }
1495
1450
  return stack;
1496
1451
  }
1497
- static fromNodeAndEventName(node, eventName, rootNode, maxDepth, comps, stopOnNoEvent = true) {
1452
+ // Reconstruct the dispatch position of a DOM event from the `data-*` stamps and
1453
+ // `§…§` meta comments the renderer left on the way down. `stopOnNoEvent` is off for
1454
+ // drag events, whose path is needed even where no handler is registered.
1455
+ static fromNodeAndEventName(node, eventName, rootNode, comps, stopOnNoEvent = true) {
1498
1456
  const parts = [];
1499
1457
  const bubbles = BUBBLING_EVENTS.has(eventName);
1500
- let depth = 0;
1501
1458
  let eventIds = [];
1502
1459
  let handlers = null;
1503
1460
  let nodeRefs = [];
@@ -1523,7 +1480,7 @@ var init_path = __esm({
1523
1480
  nodeRefs = [];
1524
1481
  return true;
1525
1482
  };
1526
- while (node && node !== rootNode && depth < maxDepth) {
1483
+ while (node && node !== rootNode) {
1527
1484
  if (node?.dataset) {
1528
1485
  const { eid, cid, vid, rp } = node.dataset;
1529
1486
  if (eid !== void 0) eventIds.push(eid);
@@ -1546,7 +1503,6 @@ var init_path = __esm({
1546
1503
  }
1547
1504
  }
1548
1505
  }
1549
- depth += 1;
1550
1506
  node = node.parentNode;
1551
1507
  }
1552
1508
  parts.reverse();
@@ -1581,13 +1537,6 @@ var init_path = __esm({
1581
1537
  resolveNode() {
1582
1538
  return this.comp.getNodeForId(+this.meta.nid, this.vid);
1583
1539
  }
1584
- applyKey(pi) {
1585
- if (pi === null) return null;
1586
- const m = this.meta;
1587
- if (m.si !== void 0) return pi.withIndex(+m.si);
1588
- if (m.sk !== void 0) return pi.withKey(m.sk);
1589
- return pi;
1590
- }
1591
1540
  };
1592
1541
  NO_EVENT_INFO = [null, null];
1593
1542
  BUBBLING_EVENTS = /* @__PURE__ */ new Set(["drop"]);
@@ -1615,14 +1564,6 @@ var init_path = __esm({
1615
1564
  }
1616
1565
  });
1617
1566
 
1618
- // src/util/env.js
1619
- var isMac;
1620
- var init_env = __esm({
1621
- "src/util/env.js"() {
1622
- isMac = (globalThis.navigator?.userAgent ?? "").toLowerCase().includes("mac");
1623
- }
1624
- });
1625
-
1626
1567
  // src/value.js
1627
1568
  function sizeOf(v) {
1628
1569
  if (v == null) return null;
@@ -1759,25 +1700,12 @@ function _parsePredicate(s, tokens, px) {
1759
1700
  }
1760
1701
  return new PredicateVal(pred, args);
1761
1702
  }
1762
- function kindOf(val) {
1763
- if (val === null) return 0;
1764
- if (val instanceof ConstVal) return val.kind;
1765
- if (val instanceof StrTplVal) return val.kind;
1766
- if (val instanceof SeqAccessVal) return K_SEQ;
1767
- if (val instanceof FieldVal) return K_FIELD;
1768
- if (val instanceof MethodVal) return K_METHOD;
1769
- if (val instanceof BindVal) return K_BIND;
1770
- if (val instanceof DynVal) return K_DYN;
1771
- if (val instanceof NameVal) return K_NAME;
1772
- if (val instanceof EventMemberVal) return K_EVENT;
1773
- return 0;
1774
- }
1775
- var VALID_VAL_ID_RE, isValidValId, VALID_FLOAT_RE, STR_TPL_SPLIT_RE, mkVal, VAL_TOKEN_RE, tokenizeValue, unescapeStr, K_CONST, K_STRTPL, K_FIELD, K_BIND, K_DYN, K_NAME, K_SEQ, K_METHOD, K_EVENT, G_BOOL, G_TEXT, G_COMPONENT, G_SEQUENCE, G_PROVIDE, G_FIELD, G_VALUE, G_HANDLER_ARG, G_ALL, toNullIfNaN, predTruthy, PREDICATES, parseText, parseComponent, parseSequence, parseField, parseProvide, parseMacroAttr, parseReceiveHandler, parseAlterHandler, BaseVal, ConstVal, NULL_CONST_VAL, PredicateVal, VarVal, StrTplVal, NameVal, HandlerNameVal, mk404Handler, keyIs, macCtrl, nullSafe, EVENT_CONVENIENCES, EventMemberVal, RenderVal, RenderNameVal, BindVal, BindMemberVal, DynVal, FieldVal, MethodVal, SeqAccessVal;
1703
+ var isMac, VALID_VAL_ID_RE, isValidValId, VALID_FLOAT_RE, STR_TPL_SPLIT_RE, mkVal, VAL_TOKEN_RE, tokenizeValue, unescapeStr, K_CONST, K_STRTPL, K_FIELD, K_BIND, K_DYN, K_NAME, K_SEQ, K_METHOD, K_EVENT, G_BOOL, G_TEXT, G_COMPONENT, G_SEQUENCE, G_PROVIDE, G_FIELD, G_VALUE, G_HANDLER_ARG, G_ALL, toNullIfNaN, predTruthy, PREDICATES, parseText, parseComponent, parseSequence, parseField, parseProvide, parseMacroAttr, parseReceiveHandler, parseAlterHandler, kindOf, BaseVal, ConstVal, NULL_CONST_VAL, PredicateVal, StrTplVal, NameVal, HandlerNameVal, mk404Handler, keyIs, macCtrl, nullSafe, EVENT_CONVENIENCES, EventMemberVal, SigilNameVal, BindVal, BindMemberVal, DynVal, FieldVal, MethodVal, SeqAccessVal;
1776
1704
  var init_value = __esm({
1777
1705
  "src/value.js"() {
1778
1706
  init_collection();
1779
1707
  init_path();
1780
- init_env();
1708
+ isMac = (globalThis.navigator?.userAgent ?? "").toLowerCase().includes("mac");
1781
1709
  VALID_VAL_ID_RE = /^[a-zA-Z][a-zA-Z0-9_]*\??$/;
1782
1710
  isValidValId = (name) => VALID_VAL_ID_RE.test(name);
1783
1711
  VALID_FLOAT_RE = /^-?[0-9]+(\.[0-9]+)?$/;
@@ -1824,9 +1752,10 @@ var init_value = __esm({
1824
1752
  parseMacroAttr = (s, px) => _parseSingle(s, px, G_ALL);
1825
1753
  parseReceiveHandler = (s, px) => _parseHandler(s, px, "receive", true, true, false);
1826
1754
  parseAlterHandler = (s, px) => _parseHandler(s, px, "alter", false, false, true)?.handlerVal ?? null;
1755
+ kindOf = (val) => val?.kind ?? 0;
1827
1756
  BaseVal = class {
1828
- render(_stack, _rx) {
1829
- }
1757
+ // No kind: never accepted by a group (PredicateVal, which only parseBool builds).
1758
+ kind = 0;
1830
1759
  eval(_stack) {
1831
1760
  }
1832
1761
  toPathItem() {
@@ -1846,9 +1775,6 @@ var init_value = __esm({
1846
1775
  this.val = val;
1847
1776
  this.kind = kind;
1848
1777
  }
1849
- render(_stack, _rx) {
1850
- return this.val;
1851
- }
1852
1778
  eval(_stack) {
1853
1779
  return this.val;
1854
1780
  }
@@ -1874,9 +1800,7 @@ var init_value = __esm({
1874
1800
  return `${this.pred.name} ${this.args.map(String).join(" ")}`;
1875
1801
  }
1876
1802
  };
1877
- VarVal = class extends BaseVal {
1878
- };
1879
- StrTplVal = class _StrTplVal extends VarVal {
1803
+ StrTplVal = class _StrTplVal extends BaseVal {
1880
1804
  constructor(vals) {
1881
1805
  super();
1882
1806
  this.vals = vals;
@@ -1889,9 +1813,6 @@ var init_value = __esm({
1889
1813
  for (const v of this.vals) if (!(v instanceof ConstVal) || v.fromMacroVar) return false;
1890
1814
  return true;
1891
1815
  }
1892
- render(stack, _rx) {
1893
- return this.eval(stack);
1894
- }
1895
1816
  eval(stack) {
1896
1817
  const strs = new Array(this.vals.length);
1897
1818
  for (let i = 0; i < this.vals.length; i++) strs[i] = this.vals[i]?.eval(stack, "");
@@ -1928,7 +1849,8 @@ var init_value = __esm({
1928
1849
  return new _StrTplVal(lo === 0 && hi === vals.length ? vals : vals.slice(lo, hi));
1929
1850
  }
1930
1851
  };
1931
- NameVal = class extends VarVal {
1852
+ NameVal = class extends BaseVal {
1853
+ kind = K_NAME;
1932
1854
  constructor(name) {
1933
1855
  super();
1934
1856
  this.name = name;
@@ -1978,6 +1900,7 @@ var init_value = __esm({
1978
1900
  dragKey: nullSafe((info) => info.lookupBind("key"))
1979
1901
  };
1980
1902
  EventMemberVal = class extends BaseVal {
1903
+ kind = K_EVENT;
1981
1904
  constructor(members) {
1982
1905
  super();
1983
1906
  this.members = members;
@@ -2000,24 +1923,21 @@ var init_value = __esm({
2000
1923
  return `e.${this.members.join(".")}`;
2001
1924
  }
2002
1925
  };
2003
- RenderVal = class extends BaseVal {
2004
- render(stack, _rx) {
2005
- return this.eval(stack);
2006
- }
2007
- };
2008
- RenderNameVal = class extends RenderVal {
1926
+ SigilNameVal = class extends BaseVal {
2009
1927
  constructor(name) {
2010
1928
  super();
2011
1929
  this.name = name;
2012
1930
  }
1931
+ toString() {
1932
+ return this.sigil + this.name;
1933
+ }
2013
1934
  };
2014
- BindVal = class extends RenderNameVal {
1935
+ BindVal = class extends SigilNameVal {
1936
+ kind = K_BIND;
1937
+ sigil = "@";
2015
1938
  eval(stack) {
2016
1939
  return stack.lookupBind(this.name);
2017
1940
  }
2018
- toString() {
2019
- return `@${this.name}`;
2020
- }
2021
1941
  };
2022
1942
  BindMemberVal = class extends BindVal {
2023
1943
  constructor(name, member) {
@@ -2032,37 +1952,35 @@ var init_value = __esm({
2032
1952
  return `@${this.name}.${this.member}`;
2033
1953
  }
2034
1954
  };
2035
- DynVal = class extends RenderNameVal {
1955
+ DynVal = class extends SigilNameVal {
1956
+ kind = K_DYN;
1957
+ sigil = "*";
2036
1958
  eval(stack) {
2037
1959
  return stack.lookupDynamic(this.name);
2038
1960
  }
2039
- toString() {
2040
- return `*${this.name}`;
2041
- }
2042
1961
  };
2043
- FieldVal = class extends RenderNameVal {
1962
+ FieldVal = class extends SigilNameVal {
1963
+ kind = K_FIELD;
1964
+ sigil = ".";
2044
1965
  eval(stack) {
2045
1966
  return stack.lookupFieldRaw(this.name);
2046
1967
  }
2047
1968
  toPathItem() {
2048
1969
  return new FieldStep(this.name);
2049
1970
  }
2050
- toString() {
2051
- return `.${this.name}`;
2052
- }
2053
1971
  };
2054
- MethodVal = class extends RenderNameVal {
1972
+ MethodVal = class extends SigilNameVal {
1973
+ kind = K_METHOD;
1974
+ sigil = "$";
2055
1975
  eval(stack) {
2056
1976
  return stack.lookupMethod(this.name);
2057
1977
  }
2058
1978
  evalAsHandler(stack) {
2059
1979
  return stack.lookupFieldRaw(this.name);
2060
1980
  }
2061
- toString() {
2062
- return `$${this.name}`;
2063
- }
2064
1981
  };
2065
- SeqAccessVal = class extends RenderVal {
1982
+ SeqAccessVal = class extends BaseVal {
1983
+ kind = K_SEQ;
2066
1984
  constructor(seqVal, keyVal) {
2067
1985
  super();
2068
1986
  this.seqVal = seqVal;
@@ -2097,11 +2015,11 @@ function parseDirectiveValue(px, directiveName, source, parser) {
2097
2015
  function parseIterationDirectives(attributes, px) {
2098
2016
  const parseNamed = (name) => {
2099
2017
  const attr = attributes.getNamedItem(`@${name}`);
2100
- return attr ? parseDirectiveValue(px, name, attr.value, parseAlterHandler) : null;
2018
+ return attr ? parseIterDirective(px, name, attr.value) : null;
2101
2019
  };
2102
2020
  return { whenVal: parseNamed("when"), loopWithVal: parseNamed("loop-with") };
2103
2021
  }
2104
- var Attributes, booleanAttrsRaw, booleanAttrs, AttrParser, ConstAttrs, DynAttrs, BaseAttr, Attr, ConstAttr, RawHtmlAttr, NOT_SET_VAL, IfAttr, EventHandler;
2022
+ var Attributes, booleanAttrsRaw, booleanAttrs, ITER_DIRECTIVES, parseIterDirective, AttrParser, ConstAttrs, DynAttrs, BaseAttr, Attr, ConstAttr, RawHtmlAttr, NOT_SET_VAL, IfAttr, EventHandler;
2105
2023
  var init_attribute = __esm({
2106
2024
  "src/attribute.js"() {
2107
2025
  init_value();
@@ -2109,15 +2027,18 @@ var init_attribute = __esm({
2109
2027
  constructor(items) {
2110
2028
  this.items = items;
2111
2029
  }
2112
- static parse(attributes, px, parseAll = false) {
2113
- return new AttrParser(px).parse(attributes, parseAll);
2114
- }
2115
2030
  isConstant() {
2116
2031
  return false;
2117
2032
  }
2118
2033
  };
2119
2034
  booleanAttrsRaw = "itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly,async,autofocus,autoplay,controls,default,defer,disabled,hidden,inert,loop,open,required,reversed,scoped,seamless,checked,muted,multiple,selected";
2120
2035
  booleanAttrs = new Set(booleanAttrsRaw.split(","));
2036
+ ITER_DIRECTIVES = {
2037
+ when: "whenVal",
2038
+ "loop-with": "loopWithVal",
2039
+ "enrich-with": "enrichWithVal"
2040
+ };
2041
+ parseIterDirective = (px, name, s) => parseDirectiveValue(px, name, s, parseAlterHandler);
2121
2042
  AttrParser = class {
2122
2043
  constructor(px) {
2123
2044
  this.px = px;
@@ -2155,11 +2076,22 @@ var init_attribute = __esm({
2155
2076
  this.px.onParseIssue("bad-value", info);
2156
2077
  }
2157
2078
  }
2158
- parseThen(s) {
2159
- if (this.ifAttr) this.ifAttr.thenVal = parseText(s, this.px) ?? NOT_SET_VAL;
2079
+ // `@then` / `@else` fill the branches of the `@if.<attr>` on the same element.
2080
+ parseBranch(slot, name, s) {
2081
+ if (this.ifAttr === null) return this._orphan(name, s, "if");
2082
+ this.ifAttr[slot] = parseText(s, this.px) ?? NOT_SET_VAL;
2083
+ }
2084
+ // `@when` / `@loop-with` / `@enrich-with` amend the `@each` on the same element. A
2085
+ // loop-less `@enrich-with` is a scope of its own; the other two need the loop.
2086
+ parseIter(name, s) {
2087
+ const val = parseIterDirective(this.px, name, s);
2088
+ if (this.eachAttr !== null) this.eachAttr[ITER_DIRECTIVES[name]] = val;
2089
+ else if (name === "enrich-with") this.pushWrapper("scope", s, val);
2090
+ else this._orphan(name, s, "each");
2160
2091
  }
2161
- parseElse(value) {
2162
- if (this.ifAttr) this.ifAttr.elseVal = parseText(value, this.px) ?? NOT_SET_VAL;
2092
+ // A directive that only means something next to another one, written alone.
2093
+ _orphan(name, value, needs) {
2094
+ this.px.onParseIssue("orphan-directive", { name, value, needs });
2163
2095
  }
2164
2096
  parseEvent(directiveName, value) {
2165
2097
  const [eventName, ...modifiers] = directiveName.slice(3).split("+");
@@ -2173,77 +2105,51 @@ var init_attribute = __esm({
2173
2105
  this.events.add(eventName, handler, modifiers);
2174
2106
  }
2175
2107
  }
2176
- _parseDirectiveValue(directiveName, s, parserFn) {
2177
- return parseDirectiveValue(this.px, directiveName, s, parserFn);
2178
- }
2179
2108
  parseDirective(s, directiveName) {
2180
2109
  switch (directiveName) {
2181
2110
  case "dangerouslysetinnerhtml":
2182
2111
  this.attrs ??= [];
2183
- this.attrs.push(new RawHtmlAttr(this._parseDirectiveValue(directiveName, s, parseText)));
2112
+ this.attrs.push(new RawHtmlAttr(parseDirectiveValue(this.px, directiveName, s, parseText)));
2184
2113
  this.hasDynamic = true;
2185
2114
  return;
2186
2115
  case "push-view":
2187
- this.pushWrapper("push-view", s, this._parseDirectiveValue(directiveName, s, parseText));
2116
+ this.pushWrapper("push-view", s, parseDirectiveValue(this.px, directiveName, s, parseText));
2188
2117
  return;
2189
2118
  case "text":
2190
- this.textChild = this._parseDirectiveValue(directiveName, s, parseText);
2119
+ this.textChild = parseDirectiveValue(this.px, directiveName, s, parseText);
2191
2120
  return;
2192
2121
  case "show":
2193
- this.pushWrapper("show", s, this._parseDirectiveValue(directiveName, s, parseBool));
2122
+ this.pushWrapper("show", s, parseDirectiveValue(this.px, directiveName, s, parseBool));
2194
2123
  return;
2195
2124
  case "hide":
2196
- this.pushWrapper("hide", s, this._parseDirectiveValue(directiveName, s, parseBool));
2125
+ this.pushWrapper("hide", s, parseDirectiveValue(this.px, directiveName, s, parseBool));
2197
2126
  return;
2198
2127
  case "each": {
2199
- const val = this._parseDirectiveValue(directiveName, s, parseSequence);
2128
+ const val = parseDirectiveValue(this.px, directiveName, s, parseSequence);
2200
2129
  this.eachAttr = this.pushWrapper("each", s, val);
2201
2130
  return;
2202
2131
  }
2203
- case "enrich-with":
2204
- if (this.eachAttr !== null)
2205
- this.eachAttr.enrichWithVal = this._parseDirectiveValue(
2206
- directiveName,
2207
- s,
2208
- parseAlterHandler
2209
- );
2210
- else
2211
- this.pushWrapper(
2212
- "scope",
2213
- s,
2214
- this._parseDirectiveValue(directiveName, s, parseAlterHandler)
2215
- );
2216
- return;
2217
2132
  case "when":
2218
- this._parseWhen(s);
2219
- return;
2220
2133
  case "loop-with":
2221
- this._parseLoopWith(s);
2134
+ case "enrich-with":
2135
+ this.parseIter(directiveName, s);
2222
2136
  return;
2223
2137
  case "then":
2224
- this.parseThen(s);
2138
+ this.parseBranch("thenVal", directiveName, s);
2225
2139
  return;
2226
2140
  case "else":
2227
- this.parseElse(s);
2141
+ this.parseBranch("elseVal", directiveName, s);
2228
2142
  return;
2229
2143
  }
2230
2144
  if (directiveName.startsWith("on.")) this.parseEvent(directiveName, s);
2231
2145
  else if (directiveName.startsWith("if.")) this.parseIf(directiveName, s);
2232
- else if (directiveName.startsWith("then.")) this.parseThen(s);
2233
- else if (directiveName.startsWith("else.")) this.parseElse(s);
2146
+ else if (directiveName.startsWith("then.")) this.parseBranch("thenVal", directiveName, s);
2147
+ else if (directiveName.startsWith("else.")) this.parseBranch("elseVal", directiveName, s);
2234
2148
  else {
2235
2149
  const info = { name: directiveName, value: s };
2236
2150
  this.px.onParseIssue("unknown-directive", info);
2237
2151
  }
2238
2152
  }
2239
- _parseWhen(s) {
2240
- if (this.eachAttr !== null)
2241
- this.eachAttr.whenVal = this._parseDirectiveValue("when", s, parseAlterHandler);
2242
- }
2243
- _parseLoopWith(s) {
2244
- if (this.eachAttr !== null)
2245
- this.eachAttr.loopWithVal = this._parseDirectiveValue("loop-with", s, parseAlterHandler);
2246
- }
2247
2153
  parse(attributes, parseAll = false) {
2248
2154
  for (const { name, value } of attributes) {
2249
2155
  const charCode = name.charCodeAt(0);
@@ -2504,6 +2410,17 @@ function addChild(normalizedChildren, child) {
2504
2410
  else normalizedChildren.push(child);
2505
2411
  } else normalizedChildren.push(new VText(child));
2506
2412
  }
2413
+ function applyAttrs(node, attrs, placeChildren) {
2414
+ const hasValue = "value" in attrs;
2415
+ const hasChecked = "checked" in attrs;
2416
+ if (hasValue || hasChecked) {
2417
+ const { value: _v, checked: _c, ...rest } = attrs;
2418
+ applyProperties(node, rest);
2419
+ } else applyProperties(node, attrs);
2420
+ placeChildren();
2421
+ if (hasValue) applyValueLast(node, attrs.value);
2422
+ if (hasChecked) setProp(node, "checked", attrs.checked, isNamespaced(node));
2423
+ }
2507
2424
  function diffProps(a, b) {
2508
2425
  if (a === b) return null;
2509
2426
  let diff = null;
@@ -2534,22 +2451,16 @@ function morphNode(domNode, source, target, opts) {
2534
2451
  }
2535
2452
  if (type3 === 1 && source.isSameKind(target)) {
2536
2453
  const propsDiff = diffProps(source.attrs, target.attrs);
2537
- const hasValue = propsDiff != null && "value" in propsDiff;
2538
- const hasChecked = propsDiff != null && "checked" in propsDiff;
2539
- if (propsDiff) {
2540
- if (hasValue || hasChecked) {
2541
- const { value: _v, checked: _c, ...rest } = propsDiff;
2542
- applyProperties(domNode, rest);
2543
- } else applyProperties(domNode, propsDiff);
2544
- }
2545
- if (!target.attrs.dangerouslySetInnerHTML) {
2454
+ const placeChildren = () => {
2455
+ if (target.attrs.dangerouslySetInnerHTML) return;
2546
2456
  const ns = effectiveNs(target, opts);
2547
2457
  morphChildren(domNode, source.childs, target.childs, childOpts(target, ns, opts));
2458
+ };
2459
+ if (propsDiff) applyAttrs(domNode, propsDiff, placeChildren);
2460
+ else placeChildren();
2461
+ if (!(propsDiff && "value" in propsDiff) && source.tag === "SELECT") {
2462
+ if (target.attrs.value !== void 0) applyValueLast(domNode, target.attrs.value);
2548
2463
  }
2549
- if (hasValue) applyValueLast(domNode, propsDiff.value);
2550
- else if (source.tag === "SELECT" && target.attrs.value !== void 0)
2551
- applyValueLast(domNode, target.attrs.value);
2552
- if (hasChecked) setProp(domNode, "checked", propsDiff.checked, false);
2553
2464
  return domNode;
2554
2465
  }
2555
2466
  if (type3 === 11) {
@@ -2769,16 +2680,7 @@ var init_vdom = __esm({
2769
2680
  const createOpts = attrs.is != null ? { is: attrs.is } : void 0;
2770
2681
  const node = ns === null ? doc.createElement(tag, createOpts) : doc.createElementNS(ns, tag, createOpts);
2771
2682
  const cOpts = childOpts(this, ns, opts);
2772
- if ("value" in attrs || "checked" in attrs) {
2773
- const { value, checked, ...rest } = attrs;
2774
- applyProperties(node, rest);
2775
- appendChildNodes(node, this.childs, cOpts);
2776
- if (value !== void 0) applyValueLast(node, value);
2777
- if (checked !== void 0) setProp(node, "checked", checked, false);
2778
- } else {
2779
- applyProperties(node, attrs);
2780
- appendChildNodes(node, this.childs, cOpts);
2781
- }
2683
+ applyAttrs(node, attrs, () => appendChildNodes(node, this.childs, cOpts));
2782
2684
  return node;
2783
2685
  }
2784
2686
  };
@@ -2797,13 +2699,6 @@ function renderTarget(val, stack) {
2797
2699
  const path = stack.renderPath.pushItem(step);
2798
2700
  return [val.eval(stack), path, stack.pendingFrame ? path.toTransactionPath() : null];
2799
2701
  }
2800
- function optimizeChilds(childs) {
2801
- for (let i = 0; i < childs.length; i++) {
2802
- const child = childs[i];
2803
- if (child.isConstant()) childs[i] = new RenderOnceNode(child);
2804
- else child.optimize();
2805
- }
2806
- }
2807
2702
  function optimizeNode(node) {
2808
2703
  if (node.isConstant()) return new RenderOnceNode(node);
2809
2704
  node.optimize();
@@ -2919,7 +2814,7 @@ function xOp(consumed = [], { wrappable = false, wrapper = null, ignoresChildren
2919
2814
  return { consumed: new Set(consumed), wrappable, wrapper, ignoresChildren };
2920
2815
  }
2921
2816
  function trimEdgeWhite(node) {
2922
- if (!node.isWhiteSpace?.()) return false;
2817
+ if (!node.isWhiteSpace()) return false;
2923
2818
  node.condenseWhiteSpace();
2924
2819
  return true;
2925
2820
  }
@@ -2930,7 +2825,7 @@ function condenseChildsWhites(childs) {
2930
2825
  if (last > 0 && trimEdgeWhite(childs[last])) emptied = true;
2931
2826
  for (let i = 1; i < last; i++) {
2932
2827
  const cur = childs[i];
2933
- if (!(cur.isWhiteSpace?.() && cur.hasNewLine())) continue;
2828
+ if (!(cur.isWhiteSpace() && cur.hasNewLine())) continue;
2934
2829
  const bothBlock = isBlockDomNode(childs[i - 1]) && isBlockDomNode(childs[i + 1]);
2935
2830
  cur.condenseWhiteSpace(bothBlock ? "" : " ");
2936
2831
  if (bothBlock) emptied = true;
@@ -2957,7 +2852,7 @@ function compileModifiers(eventName, names) {
2957
2852
  return w(this, f, args, ctx);
2958
2853
  };
2959
2854
  }
2960
- var BaseNode, TextNode, CommentNode, ChildsNode, DomNode, FragmentNode, maybeFragment, VALID_NODE_RE, ANode, MacroNode, RenderViewId, RenderNode, RenderItNode, RenderTextNode, RenderOnceNode, WrapperNode, ShowNode, HideNode, PushViewNameNode, SlotNode, ScopeNode, EachNode, IterInfo, X_OPS, WRAPPER_NODES, ParseContext, _htmlBlockTags, HTML_BLOCK_TAGS, isBlockDomNode, isEmptyText, isIgnorableXChild, hasMeaningfulChilds, View, NodeEvents, NodeEvent, fwdIfCtxPred, fwdIfEventPred, fwdIfKey, fwdCtrl, fwdMeta, fwdAlt, MOD_WRAPPERS_FOR_ANY_EVENT, MOD_WRAPPERS_BY_EVENT, MOD_EFFECTS, NO_WRAPPERS, identityModifierWrapper;
2855
+ var BaseNode, TextNode, CommentNode, ChildsNode, DomNode, FragmentNode, maybeFragment, VALID_NODE_RE, ANode, MacroNode, RenderViewId, RenderNode, RenderItNode, RenderTextNode, RenderOnceNode, WrapperNode, ShowNode, HideNode, PushViewNameNode, SlotNode, ScopeNode, EachNode, IterInfo, X_OPS, WRAPPER_NODES, ParseContext, _htmlBlockTags, HTML_BLOCK_TAGS, isBlockDomNode, isEmptyText, isIgnorableXChild, hasMeaningfulChilds, NodeEvents, NodeEvent, fwdIfCtxPred, fwdIfEventPred, fwdIfKey, fwdCtrl, fwdMeta, fwdAlt, MOD_WRAPPERS_FOR_ANY_EVENT, MOD_WRAPPERS_BY_EVENT, MOD_EFFECTS, NO_WRAPPERS, identityModifierWrapper;
2961
2856
  var init_anode = __esm({
2962
2857
  "src/anode.js"() {
2963
2858
  init_attribute();
@@ -2969,8 +2864,11 @@ var init_anode = __esm({
2969
2864
  render(_stack, _rx) {
2970
2865
  return null;
2971
2866
  }
2972
- setDataAttr(key, val) {
2973
- console.warn("setDataAttr not implemented for", this, { key, val });
2867
+ // Stamp a `data-*` attribute on the element(s) this node renders. A no-op for
2868
+ // nodes that produce no element of their own (text, `<x render*>`): a view whose
2869
+ // root is one of those records its component boundary in the `§Comp§` meta
2870
+ // comment instead (see Renderer._rValComp).
2871
+ setDataAttr(_key, _val) {
2974
2872
  }
2975
2873
  isConstant() {
2976
2874
  return false;
@@ -3009,8 +2907,6 @@ var init_anode = __esm({
3009
2907
  isConstant() {
3010
2908
  return true;
3011
2909
  }
3012
- setDataAttr(_key, _val) {
3013
- }
3014
2910
  };
3015
2911
  CommentNode = class extends TextNode {
3016
2912
  render(_stack, rx) {
@@ -3026,7 +2922,8 @@ var init_anode = __esm({
3026
2922
  return this.childs.every((v) => v.isConstant());
3027
2923
  }
3028
2924
  optimize() {
3029
- optimizeChilds(this.childs);
2925
+ const { childs } = this;
2926
+ for (let i = 0; i < childs.length; i++) childs[i] = optimizeNode(childs[i]);
3030
2927
  }
3031
2928
  };
3032
2929
  DomNode = class extends ChildsNode {
@@ -3038,8 +2935,7 @@ var init_anode = __esm({
3038
2935
  }
3039
2936
  render(stack, rx) {
3040
2937
  const childNodes = new Array(this.childs.length);
3041
- for (let i = 0; i < childNodes.length; i++)
3042
- childNodes[i] = this.childs[i]?.render?.(stack, rx) ?? null;
2938
+ for (let i = 0; i < childNodes.length; i++) childNodes[i] = this.childs[i].render(stack, rx);
3043
2939
  return rx.renderTag(this.tagName, this.attrs.eval(stack), childNodes, this.namespace);
3044
2940
  }
3045
2941
  setDataAttr(key, val) {
@@ -3051,7 +2947,7 @@ var init_anode = __esm({
3051
2947
  };
3052
2948
  FragmentNode = class extends ChildsNode {
3053
2949
  render(stack, rx) {
3054
- return rx.renderFragment(this.childs.map((c) => c?.render(stack, rx)));
2950
+ return rx.renderFragment(this.childs.map((c) => c.render(stack, rx)));
3055
2951
  }
3056
2952
  setDataAttr(key, val) {
3057
2953
  for (const child of this.childs) child.setDataAttr(key, val);
@@ -3065,8 +2961,10 @@ var init_anode = __esm({
3065
2961
  this.nodeId = nodeId;
3066
2962
  this.val = val;
3067
2963
  }
3068
- toPathStep(ctx) {
3069
- return ctx.applyKey(this.val?.toPathItem?.() ?? null);
2964
+ // The addressing step this node contributes to an event's dispatch path, given
2965
+ // the `StepCtx` of the meta that named it; null when it addresses nothing.
2966
+ toPathStep(_ctx) {
2967
+ return this.val?.toPathItem?.() ?? null;
3070
2968
  }
3071
2969
  static parse(html, px) {
3072
2970
  const nodes = px.parseHTML(html);
@@ -3082,8 +2980,8 @@ var init_anode = __esm({
3082
2980
  return maybeFragment(trimmed);
3083
2981
  }
3084
2982
  static fromDOM(node, px) {
3085
- if (node instanceof px.Text) return new TextNode(node.textContent);
3086
- else if (node instanceof px.Comment) return new CommentNode(node.textContent);
2983
+ if (node.nodeType === 3) return new TextNode(node.textContent);
2984
+ if (node.nodeType === 8) return new CommentNode(node.textContent);
3087
2985
  const { childNodes, attributes: attrs, tagName: tag } = node;
3088
2986
  const childs = [];
3089
2987
  for (let i = 0; i < childNodes.length; i++) {
@@ -3101,11 +2999,11 @@ var init_anode = __esm({
3101
2999
  const slotName = attrs.getNamedItem("name")?.value ?? "_";
3102
3000
  return px.frame.macroSlots[slotName] ?? maybeFragment(childs);
3103
3001
  }
3104
- const [nAttrs, wrappers] = Attributes.parse(attrs, px, true);
3002
+ const [nAttrs, wrappers] = new AttrParser(px).parse(attrs, true);
3105
3003
  px.onAttributes(nAttrs, wrappers, null, true, tag);
3106
3004
  return wrap(px.newMacroNode(macroName, nAttrs.toMacroVars(), childs), px, wrappers);
3107
3005
  } else if (VALID_NODE_RE.test(tag)) {
3108
- const [nAttrs, wrappers, textChild] = Attributes.parse(attrs, px);
3006
+ const [nAttrs, wrappers, textChild] = new AttrParser(px).parse(attrs);
3109
3007
  px.onAttributes(nAttrs, wrappers, textChild, false, tag);
3110
3008
  if (textChild) childs.unshift(new RenderTextNode(null, textChild));
3111
3009
  const domChilds = tag !== "PRE" ? condenseChildsWhites(childs) : childs;
@@ -3164,17 +3062,12 @@ var init_anode = __esm({
3164
3062
  evalViewName(stack) {
3165
3063
  return this.viewVal ? this.viewVal.eval(stack) : null;
3166
3064
  }
3167
- // A `<x render*>` produces no DOM element of its own to carry `data-cid`;
3168
- // when it is a view's root the component boundary is recorded in the `Comp`
3169
- // meta comment instead (see Renderer._rValComp), so this is a no-op.
3170
- setDataAttr(_key, _val) {
3171
- }
3172
3065
  };
3173
3066
  RenderNode = class extends RenderViewId {
3174
3067
  render(stack, rx) {
3175
3068
  const [value, renderPath, base] = renderTarget(this.val, stack);
3176
3069
  const newStack = stack.enter(value, {}, true, renderPath, false);
3177
- return rx.renderIt(newStack, this, "", this.evalViewName(stack), base);
3070
+ return rx.renderIt(newStack, this, this.evalViewName(stack), base);
3178
3071
  }
3179
3072
  // A `*name` target contributes no step: the site recorded the absolute base it
3180
3073
  // resumed at, and event reconstruction turns that into a continuation frame.
@@ -3187,7 +3080,7 @@ var init_anode = __esm({
3187
3080
  render(stack, rx) {
3188
3081
  const base = stack.pendingFrame ? stack.renderPath.toTransactionPath() : null;
3189
3082
  const newStack = stack.enter(stack.it, {}, true, stack.renderPath, false);
3190
- return rx.renderIt(newStack, this, "", this.evalViewName(stack), base);
3083
+ return rx.renderIt(newStack, this, this.evalViewName(stack), base);
3191
3084
  }
3192
3085
  toPathStep(ctx) {
3193
3086
  const next = ctx.next();
@@ -3204,9 +3097,6 @@ var init_anode = __esm({
3204
3097
  render(stack, _rx) {
3205
3098
  return this.val.eval(stack);
3206
3099
  }
3207
- // Renders to a text node, which can't carry `data-cid`.
3208
- setDataAttr(_key, _val) {
3209
- }
3210
3100
  };
3211
3101
  RenderOnceNode = class extends BaseNode {
3212
3102
  constructor(node) {
@@ -3281,13 +3171,29 @@ var init_anode = __esm({
3281
3171
  EachNode = class extends WrapperNode {
3282
3172
  constructor(nodeId, val) {
3283
3173
  super(nodeId, val);
3284
- this.iterInfo = new IterInfo(val, null, null, null);
3174
+ this.iterInfo = new IterInfo();
3285
3175
  }
3286
3176
  render(stack, rx) {
3287
3177
  return rx.renderEachWhen(stack, this);
3288
3178
  }
3179
+ // The sequence and the three loop handlers, resolved against `stack`.
3180
+ evalIter(stack) {
3181
+ const { whenVal, loopWithVal, enrichWithVal } = this.iterInfo;
3182
+ return {
3183
+ seq: this.val.eval(stack) ?? [],
3184
+ filter: whenVal?.evalAsHandler(stack) ?? filterAlwaysTrue,
3185
+ loopWith: loopWithVal?.evalAsHandler(stack) ?? nullLoopWith,
3186
+ enricher: enrichWithVal?.evalAsHandler(stack) ?? null
3187
+ };
3188
+ }
3189
+ // Rebuild the per-item binds for `key` (see iteration.js bindsForKey).
3190
+ enrichBinds(stack, key) {
3191
+ const { seq, filter, loopWith, enricher } = this.evalIter(stack);
3192
+ const ctx = makeLoopCtx(stack, filter);
3193
+ return bindsForKey({ seq, it: stack.it, loopWith, enricher, ctx }, key);
3194
+ }
3289
3195
  toPathStep(ctx) {
3290
- return ctx.hasKey ? new EachBindStep(this.iterInfo, ctx.key) : null;
3196
+ return ctx.hasKey ? new EachBindStep(this, ctx.key) : null;
3291
3197
  }
3292
3198
  // Where one item lives, for the render path. `@each` re-binds `it` to the item
3293
3199
  // whether or not the body is a component, so the position moves either way and
@@ -3300,24 +3206,10 @@ var init_anode = __esm({
3300
3206
  static register = true;
3301
3207
  };
3302
3208
  IterInfo = class {
3303
- constructor(val, whenVal, loopWithVal, enrichWithVal) {
3304
- this.val = val;
3305
- this.whenVal = whenVal;
3306
- this.loopWithVal = loopWithVal;
3307
- this.enrichWithVal = enrichWithVal;
3308
- }
3309
- eval(stack) {
3310
- const seq = this.val.eval(stack) ?? [];
3311
- const filter = this.whenVal?.evalAsHandler(stack) ?? filterAlwaysTrue;
3312
- const loopWith = this.loopWithVal?.evalAsHandler(stack) ?? nullLoopWith;
3313
- const enricher = this.enrichWithVal?.evalAsHandler(stack) ?? null;
3314
- return { seq, filter, loopWith, enricher };
3315
- }
3316
- // Rebuild the per-item binds for `key` (see iteration.js bindsForKey).
3317
- enrichBinds(stack, key) {
3318
- const { seq, filter, loopWith, enricher } = this.eval(stack);
3319
- const ctx = makeLoopCtx(stack, filter);
3320
- return bindsForKey({ seq, it: stack.it, loopWith, enricher, ctx }, key);
3209
+ constructor() {
3210
+ this.whenVal = null;
3211
+ this.loopWithVal = null;
3212
+ this.enrichWithVal = null;
3321
3213
  }
3322
3214
  };
3323
3215
  X_OPS = {
@@ -3342,26 +3234,31 @@ var init_anode = __esm({
3342
3234
  scope: ScopeNode,
3343
3235
  "push-view": PushViewNameNode
3344
3236
  };
3345
- ParseContext = class _ParseContext {
3346
- constructor(document2, Text, Comment, nodes, events2, macroNodes, frame, parent) {
3347
- this.nodes = nodes ?? [];
3348
- this.events = events2 ?? [];
3349
- this.macroNodes = macroNodes ?? [];
3350
- this.parent = parent ?? null;
3351
- this.frame = frame ?? {};
3352
- this.document = document2 ?? globalThis.document;
3353
- this.Text = Text ?? globalThis.Text;
3354
- this.Comment = Comment ?? globalThis.Comment;
3355
- this.cacheConstNodes = true;
3237
+ ParseContext = class {
3238
+ constructor(document2 = globalThis.document) {
3239
+ this.document = document2;
3240
+ this.nodes = [];
3241
+ this.events = [];
3242
+ this.macroNodes = [];
3243
+ this.parent = null;
3244
+ this.frame = {};
3356
3245
  this.currentTag = null;
3357
3246
  }
3358
3247
  isInsideMacro(name) {
3359
3248
  return this.frame.macroName === name || this.parent?.isInsideMacro(name);
3360
3249
  }
3250
+ // A macro body parses in a child context that shares every accumulator with
3251
+ // its parent (nodes, events, macroNodes, and whatever a subclass collects) and
3252
+ // differs only in its frame. Cloned rather than constructed so a subclass
3253
+ // keeps collecting inside macro bodies without re-implementing this — the
3254
+ // lint and class-set contexts used to lose (or had to copy) exactly that.
3361
3255
  enterMacro(macroName, macroVars, macroSlots) {
3362
- const { document: document2, Text, Comment, nodes, events: events2, macroNodes } = this;
3363
- const frame = { macroName, macroVars, macroSlots };
3364
- return new _ParseContext(document2, Text, Comment, nodes, events2, macroNodes, frame, this);
3256
+ const child = Object.create(Object.getPrototypeOf(this));
3257
+ return Object.assign(child, this, {
3258
+ frame: { macroName, macroVars, macroSlots },
3259
+ parent: this,
3260
+ currentTag: null
3261
+ });
3365
3262
  }
3366
3263
  parseHTML(html) {
3367
3264
  const t = this.document.createElement("template");
@@ -3426,33 +3323,8 @@ var init_anode = __esm({
3426
3323
  return node instanceof DomNode && HTML_BLOCK_TAGS.has(node.tagName);
3427
3324
  };
3428
3325
  isEmptyText = (c) => c instanceof TextNode && c.val === "";
3429
- isIgnorableXChild = (c) => c instanceof CommentNode || (c.isWhiteSpace?.() ?? false);
3326
+ isIgnorableXChild = (c) => c instanceof CommentNode || c.isWhiteSpace();
3430
3327
  hasMeaningfulChilds = (childs) => childs.some((c) => !isIgnorableXChild(c));
3431
- View = class {
3432
- constructor(name, rawView = "No View Defined", style = "", anode = null, ctx = null) {
3433
- this.name = name;
3434
- this.anode = anode;
3435
- this.style = style;
3436
- this.ctx = ctx;
3437
- this.rawView = rawView;
3438
- }
3439
- compile(ctx, scope, cid) {
3440
- this.ctx = ctx;
3441
- this.anode = ANode.parse(this.rawView, ctx);
3442
- this.anode.setDataAttr("data-cid", cid);
3443
- this.anode.setDataAttr("data-vid", this.name);
3444
- this.ctx.compile(scope);
3445
- if (ctx.cacheConstNodes) this.anode = optimizeNode(this.anode);
3446
- }
3447
- render(stack, rx) {
3448
- if (this.anode === null) {
3449
- throw new Error(
3450
- `tutuca: view "${this.name}" was rendered before it was compiled — its component is not registered in this app/scope. Source: ${String(this.rawView).slice(0, 80).replace(/\s+/g, " ")}…`
3451
- );
3452
- }
3453
- return this.anode.render(stack, rx);
3454
- }
3455
- };
3456
3328
  NodeEvents = class {
3457
3329
  constructor(id) {
3458
3330
  this.id = id;
@@ -3467,7 +3339,7 @@ var init_anode = __esm({
3467
3339
  getHandlersFor(eventName) {
3468
3340
  let r = null;
3469
3341
  for (const handler of this.handlers)
3470
- if (handler.handlesEventName(eventName)) {
3342
+ if (handler.name === eventName) {
3471
3343
  r ??= [];
3472
3344
  r.push(handler);
3473
3345
  }
@@ -3481,9 +3353,6 @@ var init_anode = __esm({
3481
3353
  this.modifierWrapper = compileModifiers(name, modifiers);
3482
3354
  this.modifiers = modifiers;
3483
3355
  }
3484
- handlesEventName(name) {
3485
- return this.name === name;
3486
- }
3487
3356
  getHandlerAndArgs(stack, event) {
3488
3357
  const r = this.handlerCall.getHandlerAndArgs(stack, event);
3489
3358
  r[0] = this.modifierWrapper(r[0], event);
@@ -3518,21 +3387,6 @@ var init_anode = __esm({
3518
3387
  });
3519
3388
 
3520
3389
  // src/stack.js
3521
- function routeLookup(route, lex, dyn) {
3522
- for (let i = 0; i < route.length; i++) {
3523
- const leg = route[i];
3524
- if (leg === "dyn") {
3525
- const v = dyn();
3526
- if (v != null) return v;
3527
- } else if (leg === "lex") {
3528
- const v = lex();
3529
- if (v != null) return v;
3530
- } else {
3531
- console.warn("unknown lookup route leg", leg, '- expected "dyn" or "lex"');
3532
- }
3533
- }
3534
- return null;
3535
- }
3536
3390
  function lookup(chain, name, dv = null) {
3537
3391
  let n = chain;
3538
3392
  while (n !== null) {
@@ -3605,9 +3459,9 @@ var init_stack = __esm({
3605
3459
  let has2 = false;
3606
3460
  const base = this._publishBase();
3607
3461
  for (const k in provide) {
3608
- const step = provide[k].val.toPathItem?.() ?? null;
3462
+ const step = provide[k].toPathItem?.() ?? null;
3609
3463
  if (step === null) continue;
3610
- const value = provide[k].val.eval(this);
3464
+ const value = provide[k].eval(this);
3611
3465
  binds[k] = { value, path: base === null ? null : base.concat([step]) };
3612
3466
  has2 = true;
3613
3467
  }
@@ -3687,7 +3541,7 @@ var init_stack = __esm({
3687
3541
  const value2 = path.lookup(this.root, NOT_FOUND);
3688
3542
  if (value2 !== NOT_FOUND) return { value: value2, path };
3689
3543
  }
3690
- const dval = comp.lookup[name]?.val ?? null;
3544
+ const dval = comp.lookup[name] ?? null;
3691
3545
  if (dval === null) return null;
3692
3546
  const step = dval.toPathItem?.() ?? null;
3693
3547
  const value = dval.eval(this);
@@ -3708,9 +3562,10 @@ var init_stack = __esm({
3708
3562
  return fn instanceof Function ? fn.call(this.it) : null;
3709
3563
  }
3710
3564
  // The dispatched DOM event / drag info, read only by EventMemberVal's
3711
- // `e.<member>` handler args. Null outside a live event transaction.
3565
+ // `e.<member>` handler args. Null outside a live event transaction (`ctx` is
3566
+ // then a send/intent transaction, which carries no `e`).
3712
3567
  lookupEvent() {
3713
- return this.ctx?.event ?? null;
3568
+ return this.ctx?.e ?? null;
3714
3569
  }
3715
3570
  lookupDragInfo() {
3716
3571
  return this.ctx?.dragInfo ?? null;
@@ -3733,10 +3588,9 @@ var init_stack = __esm({
3733
3588
  });
3734
3589
 
3735
3590
  // src/components.js
3736
- var COMPONENT, Components, ComponentStack, ProvideInfo, LookupInfo, isString, _rawSpecKeys, KNOWN_SPEC_KEYS, _compId, Component;
3591
+ var COMPONENT, Components, ComponentStack, isString, _rawSpecKeys, KNOWN_SPEC_KEYS, COMPONENT_METHODS;
3737
3592
  var init_components = __esm({
3738
3593
  "src/components.js"() {
3739
- init_anode();
3740
3594
  init_stack();
3741
3595
  init_value();
3742
3596
  COMPONENT = /* @__PURE__ */ Symbol.for("tutuca.component");
@@ -3745,7 +3599,7 @@ var init_components = __esm({
3745
3599
  this.byId = /* @__PURE__ */ new Map();
3746
3600
  }
3747
3601
  registerComponent(Comp) {
3748
- this.byId.set(Comp[COMPONENT].id, Comp);
3602
+ this.byId.set(Comp.id, Comp);
3749
3603
  }
3750
3604
  getComponentForId(id) {
3751
3605
  return this.byId.get(id) ?? null;
@@ -3765,7 +3619,7 @@ var init_components = __esm({
3765
3619
  }
3766
3620
  compileStyles() {
3767
3621
  const styles2 = [];
3768
- for (const Comp of this.byId.values()) styles2.push(Comp[COMPONENT].compileStyle());
3622
+ for (const Comp of this.byId.values()) styles2.push(Comp.compileStyle());
3769
3623
  return styles2.join("\n");
3770
3624
  }
3771
3625
  };
@@ -3786,7 +3640,7 @@ var init_components = __esm({
3786
3640
  if (paths) this.registerPaths(paths);
3787
3641
  for (let i = 0; i < comps.length; i++) {
3788
3642
  const Comp = comps[i];
3789
- Comp[COMPONENT].scope = this.enter();
3643
+ Comp.scope = this.enter();
3790
3644
  this.comps.registerComponent(Comp);
3791
3645
  this.byName[Comp.name] = Comp;
3792
3646
  }
@@ -3812,7 +3666,7 @@ var init_components = __esm({
3812
3666
  console.warn("registerPaths: a type name has no path", name);
3813
3667
  continue;
3814
3668
  }
3815
- this.paths[name] = paths[name].toPath?.() ?? paths[name];
3669
+ this.paths[name] = paths[name].toPath();
3816
3670
  }
3817
3671
  }
3818
3672
  lookupPath(name) {
@@ -3864,77 +3718,41 @@ var init_components = __esm({
3864
3718
  return this.macros[name] ?? this.parent?.lookupMacro(name) ?? null;
3865
3719
  }
3866
3720
  };
3867
- ProvideInfo = class {
3868
- constructor(val) {
3869
- this.val = val;
3870
- }
3871
- };
3872
- LookupInfo = class {
3873
- constructor(val) {
3874
- this.val = val;
3875
- }
3876
- };
3877
3721
  isString = (v) => typeof v === "string";
3878
3722
  _rawSpecKeys = "name view style commonStyle globalStyle receive intent alter views provide lookup fields methods statics";
3879
3723
  KNOWN_SPEC_KEYS = new Set(_rawSpecKeys.split(" "));
3880
- _compId = 0;
3881
- Component = class {
3882
- constructor(Class, o) {
3883
- this.id = _compId++;
3884
- this.name = o.name ?? "UnkComp";
3885
- this.Class = Class;
3886
- this.views = { main: new View("main", o.view, o.style) };
3887
- this.commonStyle = o.commonStyle ?? "";
3888
- this.globalStyle = o.globalStyle ?? "";
3889
- this.receive = o.receive ?? {};
3890
- this.intent = o.intent ?? {};
3891
- this.alter = o.alter ?? {};
3892
- for (const name in o.views ?? {}) {
3893
- const v = o.views[name];
3894
- const { view, style } = isString(v) ? { view: v } : v;
3895
- this.views[name] = new View(name, view, style);
3896
- }
3897
- this._rawProvide = o.provide ?? {};
3898
- this._rawLookup = o.lookup ?? [];
3899
- this.provide = {};
3900
- this.provideType = {};
3901
- this.lookup = {};
3902
- this.scope = null;
3903
- this.spec = o;
3904
- this.extra = {};
3905
- for (const key of Object.keys(o)) if (!KNOWN_SPEC_KEYS.has(key)) this.extra[key] = o[key];
3906
- }
3724
+ COMPONENT_METHODS = {
3907
3725
  compile(ParseContext2) {
3908
3726
  for (const name in this.views)
3909
3727
  this.views[name].compile(new ParseContext2(), this.scope, this.id);
3910
3728
  const ctx = this.views.main.ctx;
3911
3729
  for (const key in this._rawProvide) {
3912
3730
  if (isTypeName(key)) {
3913
- if (this._rawProvide[key] === "self") this.provideType[key] = this.Class;
3731
+ if (this._rawProvide[key] === "self") this.provideType[key] = this;
3914
3732
  continue;
3915
3733
  }
3916
3734
  const val = parseProvide(this._rawProvide[key], ctx);
3917
- if (val) this.provide[key] = new ProvideInfo(val);
3735
+ if (val) this.provide[key] = val;
3918
3736
  }
3919
3737
  for (const entry of this._rawLookup) {
3920
3738
  const name = isString(entry) ? entry : isString(entry?.name) ? entry.name : null;
3921
3739
  if (name === null) continue;
3922
3740
  const defStr = isString(entry?.default) ? entry.default : null;
3923
- this.lookup[name] = new LookupInfo(defStr === null ? null : parseField(defStr, ctx));
3741
+ this.lookup[name] = defStr === null ? null : parseField(defStr, ctx);
3924
3742
  }
3925
3743
  for (const key in this.lookup)
3926
3744
  if (this.provide[key] !== void 0)
3927
3745
  console.warn("name declared in both provide and lookup", this.name, key);
3928
- }
3746
+ },
3929
3747
  getView(name) {
3930
3748
  return this.views[name] ?? this.views.main;
3931
- }
3932
- getEventForId(id, name = "main") {
3933
- return this.getView(name).ctx.getEventForId(id);
3934
- }
3935
- getNodeForId(id, name = "main") {
3936
- return this.getView(name).ctx.getNodeForId(id);
3937
- }
3749
+ },
3750
+ getEventForId(id, viewName) {
3751
+ return this.getView(viewName).ctx.getEventForId(id);
3752
+ },
3753
+ getNodeForId(id, viewName) {
3754
+ return this.getView(viewName).ctx.getNodeForId(id);
3755
+ },
3938
3756
  compileStyle() {
3939
3757
  const { id, commonStyle, globalStyle, views } = this;
3940
3758
  const styles2 = commonStyle ? [`[data-cid="${id}"]{${commonStyle}}`] : [];
@@ -3949,6 +3767,63 @@ var init_components = __esm({
3949
3767
  }
3950
3768
  });
3951
3769
 
3770
+ // src/util/parsectx.js
3771
+ var ParseCtxClassSetCollector;
3772
+ var init_parsectx = __esm({
3773
+ "src/util/parsectx.js"() {
3774
+ init_anode();
3775
+ init_value();
3776
+ ParseCtxClassSetCollector = class extends ParseContext {
3777
+ constructor(...args) {
3778
+ super(...args);
3779
+ this.classes = /* @__PURE__ */ new Set();
3780
+ }
3781
+ _addClasses(s) {
3782
+ for (const v of s.split(/\s+/)) {
3783
+ this.classes.add(v);
3784
+ }
3785
+ }
3786
+ onAttributes(attrs, _wrapperAttrs, _textChild, _isMacroCall, _tag) {
3787
+ if (Array.isArray(attrs.items)) {
3788
+ for (const attr of attrs.items) {
3789
+ if (attr.name !== "class") {
3790
+ continue;
3791
+ }
3792
+ const { val, thenVal, elseVal } = attr;
3793
+ if (thenVal !== void 0) {
3794
+ this._maybeAddVal(thenVal);
3795
+ this._maybeAddVal(elseVal);
3796
+ } else {
3797
+ this._maybeAddVal(val);
3798
+ }
3799
+ }
3800
+ } else {
3801
+ const attr = attrs.items.class;
3802
+ if (attr) {
3803
+ this._addClasses(attr);
3804
+ }
3805
+ }
3806
+ }
3807
+ _maybeAddVal(value) {
3808
+ if (!this._maybeAddStrTpl(value) && typeof value?.val === "string") {
3809
+ this._addClasses(value.val);
3810
+ }
3811
+ }
3812
+ _maybeAddStrTpl(value) {
3813
+ if (value?.vals !== void 0) {
3814
+ for (const val of value.vals) {
3815
+ if (val instanceof ConstVal && val.val !== "") {
3816
+ this._addClasses(val.val);
3817
+ }
3818
+ }
3819
+ return true;
3820
+ }
3821
+ return false;
3822
+ }
3823
+ };
3824
+ }
3825
+ });
3826
+
3952
3827
  // tools/core/html-tokenizer.js
3953
3828
  function isWhitespace(c) {
3954
3829
  return c === CharCodes.Space || c === CharCodes.NewLine || c === CharCodes.Tab || c === CharCodes.FormFeed || c === CharCodes.CarriageReturn;
@@ -6900,7 +6775,7 @@ function checkLookupsHaveProviders(lx, Comp) {
6900
6775
  for (const name in Comp.lookup) {
6901
6776
  if (isTypeName2(name)) continue;
6902
6777
  if (scope.hasProvider?.(name) || scope.lookupPath?.(name)) continue;
6903
- const info = { name, hasDefault: Comp.lookup[name].val != null };
6778
+ const info = { name, hasDefault: Comp.lookup[name] != null };
6904
6779
  if (info.hasDefault) lx.hint(LOOKUP_NO_PROVIDER, info);
6905
6780
  else lx.error(LOOKUP_NO_PROVIDER, info);
6906
6781
  }
@@ -6921,11 +6796,12 @@ function checkUnreferencedDynamics(lx, Comp, referencedDynamics) {
6921
6796
  }
6922
6797
  }
6923
6798
  }
6924
- var KNOWN_COMPONENT_SPEC_KEYS, EMPTY_SET, FRAMEWORK_WELL_KNOWN_EXTRAS, KNOWN_DIRECTIVE_NAMES, isTypeName2, ALT_HANDLER_NOT_DEFINED, ALT_HANDLER_NOT_REFERENCED, DYN_VAL_NOT_DEFINED, DYN_ALIAS_NOT_REFERENCED, PROVIDE_NOT_ADDRESSABLE, PROVIDE_TYPE_BAD_SHAPE, LOOKUP_BAD_SHAPE, LOOKUP_NO_PROVIDER, RENDER_IT_OUTSIDE_OF_LOOP, UNKNOWN_EVENT_MODIFIER, RECEIVE_HANDLER_NOT_IMPLEMENTED, EVENT_HANDLER_METHOD_NOT_ALLOWED, HANDLER_NAME_COLLISION, FIELD_VAL_NOT_DEFINED, FIELD_VAL_IS_METHOD, METHOD_VAL_NOT_DEFINED, METHOD_VAL_IS_FIELD, DUPLICATE_ATTR_DEFINITION, IF_NO_BRANCH_SET, UNKNOWN_COMPONENT_NAME, UNKNOWN_MACRO_ARG, UNKNOWN_DIRECTIVE, UNKNOWN_X_OP, UNKNOWN_X_ATTR, X_OP_IGNORES_CHILDREN, MAYBE_DROP_AT_PREFIX, MAYBE_ADD_AT_PREFIX, BAD_VALUE, UNSUPPORTED_EXPR_SYNTAX, BINDING_MEMBER_TOO_DEEP, SUGGEST_BINDING_MEMBER, REDUNDANT_TEMPLATE_STRING, PLACEHOLDERLESS_TEMPLATE_STRING, CONSTANT_CONDITION, UNKNOWN_COMPONENT_SPEC_KEY, COMP_FIELD_BAD_SHAPE, ASYNC_HANDLER, TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE, GLOBAL_SELECTOR_IN_SCOPED_STYLE, FIELD_METHOD_NAME_COLLISION, X_KNOWN_OP_NAMES, X_KNOWN_ATTR_NAMES, HOST_DIRECTIVE_ONLY_NAMES, LEVEL_WARN2, LEVEL_ERROR2, LEVEL_HINT, PARSE_ISSUES, BINDING_MEMBER_TOO_DEEP_RE, UNSUPPORTED_EXPR_GUIDANCE, HTML_LINT_OPTS, NO_WRAPPERS2, ANY_EVENT_MODIFIERS, fixTo, BOOL_CONDITION_ORIGINS, isBoolConditionCtx, ATTR_VAL_CHECKERS, NODE_KIND_TO_CTX, HANDLER_CHANNELS, ASYNC_HANDLER_HELP, NON_NESTABLE_AT_RULE, GLOBAL_LEADING_SELECTOR, IGNORE_DIRECTIVE, blankRun, STYLE_TO_GLOBAL_HELP, KNOWN_LOOKUP_KEYS, LintContext, LintParseContext;
6799
+ var KNOWN_COMPONENT_SPEC_KEYS, EMPTY_SET, FRAMEWORK_WELL_KNOWN_EXTRAS, KNOWN_DIRECTIVE_NAMES, isTypeName2, ALT_HANDLER_NOT_DEFINED, ALT_HANDLER_NOT_REFERENCED, DYN_VAL_NOT_DEFINED, DYN_ALIAS_NOT_REFERENCED, PROVIDE_NOT_ADDRESSABLE, PROVIDE_TYPE_BAD_SHAPE, LOOKUP_BAD_SHAPE, LOOKUP_NO_PROVIDER, RENDER_IT_OUTSIDE_OF_LOOP, UNKNOWN_EVENT_MODIFIER, RECEIVE_HANDLER_NOT_IMPLEMENTED, EVENT_HANDLER_METHOD_NOT_ALLOWED, HANDLER_NAME_COLLISION, FIELD_VAL_NOT_DEFINED, FIELD_VAL_IS_METHOD, METHOD_VAL_NOT_DEFINED, METHOD_VAL_IS_FIELD, DUPLICATE_ATTR_DEFINITION, IF_NO_BRANCH_SET, UNKNOWN_COMPONENT_NAME, UNKNOWN_MACRO_ARG, UNKNOWN_DIRECTIVE, ORPHAN_DIRECTIVE, UNKNOWN_X_OP, UNKNOWN_X_ATTR, X_OP_IGNORES_CHILDREN, MAYBE_DROP_AT_PREFIX, MAYBE_ADD_AT_PREFIX, BAD_VALUE, UNSUPPORTED_EXPR_SYNTAX, BINDING_MEMBER_TOO_DEEP, SUGGEST_BINDING_MEMBER, REDUNDANT_TEMPLATE_STRING, PLACEHOLDERLESS_TEMPLATE_STRING, CONSTANT_CONDITION, UNKNOWN_COMPONENT_SPEC_KEY, COMP_FIELD_BAD_SHAPE, ASYNC_HANDLER, TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE, GLOBAL_SELECTOR_IN_SCOPED_STYLE, FIELD_METHOD_NAME_COLLISION, X_KNOWN_OP_NAMES, X_KNOWN_ATTR_NAMES, HOST_DIRECTIVE_ONLY_NAMES, LEVEL_WARN2, LEVEL_ERROR2, LEVEL_HINT, PARSE_ISSUES, BINDING_MEMBER_TOO_DEEP_RE, UNSUPPORTED_EXPR_GUIDANCE, HTML_LINT_OPTS, NO_WRAPPERS2, ANY_EVENT_MODIFIERS, fixTo, BOOL_CONDITION_ORIGINS, isBoolConditionCtx, ATTR_VAL_CHECKERS, NODE_KIND_TO_CTX, HANDLER_CHANNELS, ASYNC_HANDLER_HELP, NON_NESTABLE_AT_RULE, GLOBAL_LEADING_SELECTOR, IGNORE_DIRECTIVE, blankRun, STYLE_TO_GLOBAL_HELP, KNOWN_LOOKUP_KEYS, LintContext, LintParseContext;
6925
6800
  var init_lint_check = __esm({
6926
6801
  "tools/core/lint-check.js"() {
6927
6802
  init_anode();
6928
6803
  init_components();
6804
+ init_parsectx();
6929
6805
  init_htmllinter();
6930
6806
  init_closest_name();
6931
6807
  KNOWN_COMPONENT_SPEC_KEYS = new Set(
@@ -6975,6 +6851,7 @@ var init_lint_check = __esm({
6975
6851
  UNKNOWN_COMPONENT_NAME = "UNKNOWN_COMPONENT_NAME";
6976
6852
  UNKNOWN_MACRO_ARG = "UNKNOWN_MACRO_ARG";
6977
6853
  UNKNOWN_DIRECTIVE = "UNKNOWN_DIRECTIVE";
6854
+ ORPHAN_DIRECTIVE = "ORPHAN_DIRECTIVE";
6978
6855
  UNKNOWN_X_OP = "UNKNOWN_X_OP";
6979
6856
  UNKNOWN_X_ATTR = "UNKNOWN_X_ATTR";
6980
6857
  X_OP_IGNORES_CHILDREN = "X_OP_IGNORES_CHILDREN";
@@ -7009,6 +6886,7 @@ var init_lint_check = __esm({
7009
6886
  LEVEL_HINT = "hint";
7010
6887
  PARSE_ISSUES = {
7011
6888
  "unknown-directive": { id: UNKNOWN_DIRECTIVE, candidates: KNOWN_DIRECTIVE_NAMES },
6889
+ "orphan-directive": { id: ORPHAN_DIRECTIVE },
7012
6890
  "unknown-x-op": { id: UNKNOWN_X_OP, candidates: X_KNOWN_OP_NAMES, atPrefix: X_KNOWN_OP_NAMES },
7013
6891
  "unknown-x-attr": {
7014
6892
  id: UNKNOWN_X_ATTR,
@@ -7163,13 +7041,14 @@ var init_lint_check = __esm({
7163
7041
  this.reports.push({ id, info, level, context: { ...this.frame }, suggestion });
7164
7042
  }
7165
7043
  };
7166
- LintParseContext = class extends ParseContext {
7167
- constructor(document2, Text, Comment) {
7168
- super(document2, Text, Comment);
7044
+ LintParseContext = class extends ParseCtxClassSetCollector {
7045
+ constructor(document2) {
7046
+ super(document2);
7169
7047
  this.attrs = [];
7170
7048
  this.parseIssues = [];
7171
7049
  }
7172
7050
  onAttributes(attrs, wrapperAttrs, textChild, isMacroCall = false, tag = null) {
7051
+ super.onAttributes(attrs, wrapperAttrs, textChild, isMacroCall, tag);
7173
7052
  this.attrs.push({ attrs, wrapperAttrs, textChild, isMacroCall, tag });
7174
7053
  }
7175
7054
  onParseIssue(kind, info) {
@@ -7325,6 +7204,12 @@ var init_lint_rules = __esm({
7325
7204
  group: "Templates / events",
7326
7205
  summary: "`@directive` name is not recognized (typo or unsupported)."
7327
7206
  },
7207
+ {
7208
+ code: ORPHAN_DIRECTIVE,
7209
+ level: "error",
7210
+ group: "Templates / events",
7211
+ summary: "`@when` / `@loop-with` without an `@each`, or `@then` / `@else` without an `@if`, on the same element — the directive is ignored."
7212
+ },
7328
7213
  {
7329
7214
  code: UNKNOWN_X_OP,
7330
7215
  level: "error",
@@ -7593,6 +7478,8 @@ function lintIdToMessage(id, info) {
7593
7478
  return `Argument '${info.name}' is not declared in macro '${info.macroName}'`;
7594
7479
  case "UNKNOWN_DIRECTIVE":
7595
7480
  return `Unknown directive '@${info.name}=${JSON.stringify(info.value)}'${fmtTagSuffix(info)}`;
7481
+ case "ORPHAN_DIRECTIVE":
7482
+ return `'@${info.name}=${JSON.stringify(info.value)}' needs an '@${info.needs}' on the same element — it was ignored${fmtTagSuffix(info)}`;
7596
7483
  case "UNKNOWN_X_OP":
7597
7484
  return `Unknown <x> op '${info.name}=${JSON.stringify(info.value)}'${fmtTagSuffix(info)}`;
7598
7485
  case "UNKNOWN_X_ATTR":
@@ -13064,45 +12951,6 @@ var init_list = __esm({
13064
12951
  });
13065
12952
 
13066
12953
  // src/oo.js
13067
- function mkCompField(field, scope, args) {
13068
- const Comp = scope?.lookupComponent(field.type) ?? null;
13069
- if (Comp === null)
13070
- console.warn(
13071
- scope ? `component field "${field.name}": component "${field.type}" not found in scope` : `component field "${field.name}": cannot resolve component "${field.type}" — built without a registered scope (use ${field.type}.make({}) as the default, or build via a registered component)`
13072
- );
13073
- return Comp?.make({ ...field.args, ...args }, { scope }) ?? null;
13074
- }
13075
- function fieldFromDescriptor(name, value) {
13076
- const FieldCls = fieldsByTypeName[value.type] ?? FieldAny;
13077
- const probe = new FieldCls(name);
13078
- return [FieldCls, probe.coerceOr(value.defaultValue, probe.defaultValue)];
13079
- }
13080
- function classFromData(name, { fields = {}, methods, statics }) {
13081
- const b = new ClassBuilder(name);
13082
- for (const field in fields) {
13083
- const value = fields[field];
13084
- const type3 = typeof value;
13085
- if (type3 === "string") b.addField(field, value, FieldString);
13086
- else if (type3 === "number") b.addField(field, value, FieldFloat);
13087
- else if (type3 === "boolean") b.addField(field, value, FieldBool);
13088
- else if (Array.isArray(value)) b.addField(field, [...value], FieldList);
13089
- else if (value instanceof Set) b.addField(field, new Set(value), FieldSet);
13090
- else if (value instanceof Map) b.addField(field, new Map(value), FieldMap);
13091
- else if (value?.type && Object.hasOwn(value, "defaultValue")) {
13092
- const [FieldCls, dval] = fieldFromDescriptor(field, value);
13093
- b.addField(field, dval, FieldCls);
13094
- } else if (value?.component && value?.args !== void 0)
13095
- b.addCompField(field, value.component, value.args);
13096
- else if (isPlainObject(value)) b.addField(field, { ...value }, FieldObject);
13097
- else {
13098
- const FieldCls = value?.[FIELD_CLASS] ?? FieldAny;
13099
- b.addField(field, value, FieldCls);
13100
- }
13101
- }
13102
- if (methods) b.methods(methods);
13103
- if (statics) b.statics(statics);
13104
- return b.build();
13105
- }
13106
12954
  function validateDraftFields(current2, draft) {
13107
12955
  const meta = metaOf(current2);
13108
12956
  if (!meta) return;
@@ -13117,226 +12965,41 @@ function validateDraftFields(current2, draft) {
13117
12965
  }
13118
12966
  }
13119
12967
  }
13120
- function assertNoReservedComponentStatics(statics = {}) {
13121
- for (const name in statics) {
13122
- if (RESERVED_COMPONENT_STATICS.has(name)) {
13123
- throw new TypeError(`component static "${name}" is reserved by the framework`);
13124
- }
13125
- }
13126
- }
13127
- var BAD_VALUE2, nullCoercer, Field, CHECK_TYPE_ANY, CHECK_TYPE_INT, CHECK_TYPE_FLOAT, CHECK_TYPE_BOOL, CHECK_TYPE_STRING, CHECK_TYPE_LIST, CHECK_TYPE_OBJECT, CHECK_TYPE_MAP, CHECK_TYPE_SET, COERCE_NONE, COERCE_BOOL, COERCE_STRING, COERCE_INT, COERCE_LIST, COERCE_OBJECT, COERCE_MAP, COERCE_SET, FieldBool, FieldAny, FieldString, FieldInt, FieldFloat, metaOf, getTypeName, FieldComp, FieldList, FieldObject, FieldMap, FieldSet, ClassBuilder, FIELD_CLASS, fieldsByTypeName, META_KEYS, RESERVED_COMPONENT_STATICS;
12968
+ var BAD_VALUE2, COERCE_NONE, COERCE_MAP, FIELD_TYPES, metaOf, RESERVED_COMPONENT_STATICS;
13128
12969
  var init_oo = __esm({
13129
12970
  "src/oo.js"() {
13130
12971
  init_collection();
13131
12972
  init_components();
13132
- init_immer2();
13133
12973
  BAD_VALUE2 = /* @__PURE__ */ Symbol("BadValue");
13134
- nullCoercer = (v) => v;
13135
- Field = class {
13136
- constructor(type3, name, typeCheck, coercer, defaultValue = null) {
13137
- this.type = type3;
13138
- this.name = name;
13139
- this.typeCheck = typeCheck;
13140
- this.coercer = coercer;
13141
- this.defaultValue = defaultValue;
13142
- }
13143
- isValid(v) {
13144
- return this.typeCheck(v);
13145
- }
13146
- coerceOr(v, defaultValue = null) {
13147
- if (this.isValid(v)) return v;
13148
- const v1 = this.coercer(v);
13149
- return this.isValid(v1) ? v1 : defaultValue;
13150
- }
13151
- coerceOrDefault(v) {
13152
- return this.coerceOr(v, this.defaultValue);
13153
- }
13154
- };
13155
- CHECK_TYPE_ANY = (_v) => true;
13156
- CHECK_TYPE_INT = Number.isInteger;
13157
- CHECK_TYPE_FLOAT = Number.isFinite;
13158
- CHECK_TYPE_BOOL = (v) => typeof v === "boolean";
13159
- CHECK_TYPE_STRING = (v) => typeof v === "string";
13160
- CHECK_TYPE_LIST = Array.isArray;
13161
- CHECK_TYPE_OBJECT = isPlainObject;
13162
- CHECK_TYPE_MAP = (v) => v instanceof Map;
13163
- CHECK_TYPE_SET = (v) => v instanceof Set;
13164
12974
  COERCE_NONE = (_v) => null;
13165
- COERCE_BOOL = (v) => !!v;
13166
- COERCE_STRING = (v) => v?.toString?.() ?? "";
13167
- COERCE_INT = (v) => Number.isFinite(v) ? Math.trunc(v) : null;
13168
- COERCE_LIST = (v) => Array.isArray(v) ? [...v] : null;
13169
- COERCE_OBJECT = (v) => isPlainObject(v) ? { ...v } : null;
13170
12975
  COERCE_MAP = (v) => {
13171
12976
  if (v instanceof Map) return new Map(v);
13172
12977
  if (Array.isArray(v) || isPlainObject(v))
13173
12978
  return new Map(Array.isArray(v) ? v : Object.entries(v));
13174
12979
  return null;
13175
12980
  };
13176
- COERCE_SET = (v) => v instanceof Set || Array.isArray(v) ? new Set(v) : null;
13177
- FieldBool = class extends Field {
13178
- constructor(name, defaultValue = false) {
13179
- super("bool", name, CHECK_TYPE_BOOL, COERCE_BOOL, defaultValue);
13180
- }
13181
- };
13182
- FieldAny = class extends Field {
13183
- constructor(name, defaultValue = null) {
13184
- super("any", name, CHECK_TYPE_ANY, nullCoercer, defaultValue);
13185
- }
13186
- };
13187
- FieldString = class extends Field {
13188
- constructor(name, defaultValue = "") {
13189
- super("text", name, CHECK_TYPE_STRING, COERCE_STRING, defaultValue);
13190
- }
13191
- };
13192
- FieldInt = class extends Field {
13193
- constructor(name, defaultValue = 0) {
13194
- super("int", name, CHECK_TYPE_INT, COERCE_INT, defaultValue);
13195
- }
13196
- };
13197
- FieldFloat = class extends Field {
13198
- constructor(name, defaultValue = 0) {
13199
- super("float", name, CHECK_TYPE_FLOAT, COERCE_NONE, defaultValue);
13200
- }
13201
- };
13202
- metaOf = (v) => v?.constructor?.[COMPONENT] ?? v?.constructor?.getMetaClass?.();
13203
- getTypeName = (v) => metaOf(v)?.name ?? null;
13204
- FieldComp = class extends Field {
13205
- constructor(type3, name, args) {
13206
- super(type3, name, (v) => getTypeName(v) === type3, nullCoercer, null);
13207
- this.args = args;
13208
- }
13209
- };
13210
- FieldList = class extends Field {
13211
- constructor(name, defaultValue = []) {
13212
- super("list", name, CHECK_TYPE_LIST, COERCE_LIST, defaultValue);
13213
- }
13214
- };
13215
- FieldObject = class extends Field {
13216
- constructor(name, defaultValue = {}) {
13217
- super("object", name, CHECK_TYPE_OBJECT, COERCE_OBJECT, defaultValue);
13218
- }
13219
- };
13220
- FieldMap = class extends Field {
13221
- constructor(name, defaultValue = /* @__PURE__ */ new Map()) {
13222
- super("map", name, CHECK_TYPE_MAP, COERCE_MAP, defaultValue);
13223
- }
13224
- };
13225
- FieldSet = class extends Field {
13226
- constructor(name, defaultValue = /* @__PURE__ */ new Set()) {
13227
- super("set", name, CHECK_TYPE_SET, COERCE_SET, defaultValue);
13228
- }
12981
+ FIELD_TYPES = {
12982
+ any: [(_v) => true, COERCE_NONE, () => null],
12983
+ text: [(v) => typeof v === "string", (v) => v?.toString?.() ?? "", () => ""],
12984
+ int: [Number.isInteger, (v) => Number.isFinite(v) ? Math.trunc(v) : null, () => 0],
12985
+ float: [Number.isFinite, COERCE_NONE, () => 0],
12986
+ bool: [(v) => typeof v === "boolean", (v) => !!v, () => false],
12987
+ list: [Array.isArray, (v) => Array.isArray(v) ? [...v] : null, () => []],
12988
+ object: [isPlainObject, (v) => isPlainObject(v) ? { ...v } : null, () => ({})],
12989
+ map: [(v) => v instanceof Map, COERCE_MAP, () => /* @__PURE__ */ new Map()],
12990
+ set: [
12991
+ (v) => v instanceof Set,
12992
+ (v) => v instanceof Set || Array.isArray(v) ? new Set(v) : null,
12993
+ () => /* @__PURE__ */ new Set()
12994
+ ]
13229
12995
  };
13230
- ClassBuilder = class {
13231
- constructor(name) {
13232
- this.name = name;
13233
- this.fields = {};
13234
- this.compFields = /* @__PURE__ */ new Set();
13235
- this._methods = {};
13236
- this._statics = {};
13237
- }
13238
- build() {
13239
- const { name, fields, compFields, _methods } = this;
13240
- const defaults = Object.fromEntries(
13241
- Object.entries(fields).map(([fieldName, field]) => [fieldName, field.defaultValue])
13242
- );
13243
- const Class = {
13244
- [name]: class {
13245
- constructor(values = {}) {
13246
- Object.assign(this, defaults, values);
13247
- }
13248
- }
13249
- }[name];
13250
- Class[DRAFTABLE] = true;
13251
- Object.assign(Class.prototype, _methods);
13252
- const metaClass = { fields, name, methods: _methods };
13253
- Object.assign(
13254
- Class,
13255
- {
13256
- getMetaClass: () => metaClass,
13257
- make(inArgs = {}, opts = {}) {
13258
- const args = {};
13259
- const scope = opts.scope ?? this[COMPONENT]?.scope ?? this.scope;
13260
- for (const key in inArgs) {
13261
- const field = fields[key];
13262
- if (compFields.has(key)) args[key] = mkCompField(field, scope, inArgs[key]);
13263
- else if (field === void 0)
13264
- console.warn("extra argument to constructor:", name, key, inArgs);
13265
- else args[key] = field.coerceOrDefault(inArgs[key]);
13266
- }
13267
- for (const key of compFields)
13268
- if (args[key] === void 0) args[key] = mkCompField(fields[key], scope, inArgs[key]);
13269
- return freeze(new this(args), true);
13270
- }
13271
- },
13272
- this._statics
13273
- );
13274
- return Class;
13275
- }
13276
- methods(proto) {
13277
- for (const k in proto) this._methods[k] = proto[k];
13278
- }
13279
- statics(proto) {
13280
- for (const k in proto) this._statics[k] = proto[k];
13281
- }
13282
- addField(name, dval, FieldCls) {
13283
- const field = new FieldCls(name, dval);
13284
- this.fields[name] = field;
13285
- return field;
13286
- }
13287
- addCompField(name, type3, args) {
13288
- const field = new FieldComp(type3, name, args);
13289
- this.compFields.add(name);
13290
- this.fields[name] = field;
13291
- return field;
13292
- }
13293
- };
13294
- FIELD_CLASS = /* @__PURE__ */ Symbol.for("tutuca.fieldClass");
13295
- fieldsByTypeName = {
13296
- text: FieldString,
13297
- int: FieldInt,
13298
- float: FieldFloat,
13299
- bool: FieldBool,
13300
- list: FieldList,
13301
- object: FieldObject,
13302
- map: FieldMap,
13303
- set: FieldSet,
13304
- any: FieldAny
13305
- };
13306
- META_KEYS = "name id fields methods views receive intent alter provide provideType lookup spec extra commonStyle globalStyle scope _rawProvide _rawLookup".split(
13307
- " "
13308
- );
12996
+ metaOf = (v) => v?.constructor?.getMetaClass?.();
13309
12997
  RESERVED_COMPONENT_STATICS = /* @__PURE__ */ new Set([
13310
- ...META_KEYS,
13311
- "make",
13312
- "getMetaClass",
13313
- ...Object.getOwnPropertyNames(Component.prototype)
12998
+ ..."name id fields methods views receive intent alter provide provideType lookup spec extra commonStyle globalStyle scope _rawProvide _rawLookup make getMetaClass".split(
12999
+ " "
13000
+ ),
13001
+ ...Object.keys(COMPONENT_METHODS)
13314
13002
  ]);
13315
- Component.fromSpec = (opts) => {
13316
- assertNoReservedComponentStatics(opts.statics);
13317
- const Class = classFromData(opts.name, opts);
13318
- const comp = new Component(Class, opts);
13319
- const metaClass = Class.getMetaClass();
13320
- comp.fields = metaClass.fields;
13321
- comp.methods = metaClass.methods;
13322
- Class.getMetaClass = () => comp;
13323
- Class[COMPONENT] = comp;
13324
- for (const key of META_KEYS)
13325
- if (!Object.hasOwn(Class, key))
13326
- Object.defineProperty(Class, key, {
13327
- get() {
13328
- return comp[key];
13329
- },
13330
- set(v) {
13331
- comp[key] = v;
13332
- },
13333
- configurable: true
13334
- });
13335
- for (const key of Object.getOwnPropertyNames(Component.prototype))
13336
- if (key !== "constructor" && !Object.hasOwn(Class, key))
13337
- Class[key] = (...args) => comp[key](...args);
13338
- return Class;
13339
- };
13340
13003
  }
13341
13004
  });
13342
13005
 
@@ -13344,6 +13007,17 @@ var init_oo = __esm({
13344
13007
  function nullHandler() {
13345
13008
  return this;
13346
13009
  }
13010
+ function subscribe(list, cb) {
13011
+ list.push(cb);
13012
+ return () => {
13013
+ const i = list.indexOf(cb);
13014
+ if (i !== -1) list.splice(i, 1);
13015
+ };
13016
+ }
13017
+ function warnUnknownLeg(what, leg) {
13018
+ console.warn(`unknown ${what} route leg`, leg, '- expected "dyn" or "lex"');
13019
+ return null;
13020
+ }
13347
13021
  function warnNotIntent(verb) {
13348
13022
  console.warn(`ctx.${verb}() is only meaningful in an "intent" handler - ignored`);
13349
13023
  }
@@ -13396,14 +13070,7 @@ var init_transactor = __esm({
13396
13070
  // carry: kind, name, args, path, pathKeys, targetPath, handler, handlerName,
13397
13071
  // matched, before, after, parent, timestamp. Purely observational.
13398
13072
  observe(cb) {
13399
- this._observers.push(cb);
13400
- return () => {
13401
- const i = this._observers.indexOf(cb);
13402
- if (i !== -1) this._observers.splice(i, 1);
13403
- };
13404
- }
13405
- _emit(record) {
13406
- for (const cb of this._observers) cb(record);
13073
+ return subscribe(this._observers, cb);
13407
13074
  }
13408
13075
  // Record a refusal: a dispatch the runtime could not carry out. Kinds are
13409
13076
  // open strings; today the runtime raises NO_HANDLER (a receive name with no
@@ -13422,11 +13089,7 @@ var init_transactor = __esm({
13422
13089
  // Subscribe to refusal records as they happen. Returns an unsubscribe fn,
13423
13090
  // like observe().
13424
13091
  observeRefusals(cb) {
13425
- this._refusalObservers.push(cb);
13426
- return () => {
13427
- const i = this._refusalObservers.indexOf(cb);
13428
- if (i !== -1) this._refusalObservers.splice(i, 1);
13429
- };
13092
+ return subscribe(this._refusalObservers, cb);
13430
13093
  }
13431
13094
  // Build and dispatch one observer record. Pins field-resolved keys (e.g. a
13432
13095
  // `.a[.selId]` render target reconstructed from a DOM event) against the root the
@@ -13435,7 +13098,7 @@ var init_transactor = __esm({
13435
13098
  _emitRecord(root, { kind, name, args, path, targetPath, handler, handlerName, matched, before, after, parent }) {
13436
13099
  if (this._observers.length === 0) return;
13437
13100
  const pinned = path.pinKeys(root);
13438
- this._emit({
13101
+ const record = {
13439
13102
  kind,
13440
13103
  name,
13441
13104
  args: args ?? null,
@@ -13449,14 +13112,14 @@ var init_transactor = __esm({
13449
13112
  after,
13450
13113
  parent,
13451
13114
  timestamp: Date.now()
13452
- });
13115
+ };
13116
+ for (const cb of this._observers) cb(record);
13453
13117
  }
13454
13118
  // The observer record for a settled transaction. The resolved handler
13455
13119
  // (`_resolvedHandler`/`_matched`) and per-leaf before/after (`_before`/`_after`)
13456
13120
  // were captured while the handler ran (see callHandler / Transaction.run).
13457
13121
  _emitTransaction(transaction, root) {
13458
13122
  if (this._observers.length === 0) return;
13459
- if (transaction._resolvedHandler === void 0) return;
13460
13123
  this._emitRecord(root, {
13461
13124
  kind: transaction.observeKind,
13462
13125
  name: transaction.observeName,
@@ -13470,28 +13133,22 @@ var init_transactor = __esm({
13470
13133
  parent: transaction.parentTransaction
13471
13134
  });
13472
13135
  }
13473
- // Make `child` a tracked unit of `parent`'s subtree: the parent's completion stays open
13474
- // until the child's *whole* subtree settles. Tracking happens at dispatch time — during
13475
- // the parent's handler or afterTransaction — while the parent's self-unit is still held,
13476
- // so the parent counter can't reach zero before the child is registered. Returns `child`.
13477
- _link(child, parent) {
13478
- if (parent) {
13479
- const release = parent.completion.track();
13480
- child.completion.whenSubtreeSettled().then(release);
13481
- }
13482
- return child;
13483
- }
13484
13136
  // `origin` is where the message came FROM, pinned now for the same reason an
13485
13137
  // intent's answerPath is: a reply must reach the sender that asked even if a key
13486
13138
  // moved while the message was in flight. Null when nobody is waiting — a host
13487
13139
  // sendAtRoot or a view's own `@on.*` — and ctx.sendReply refuses on that.
13140
+ //
13141
+ // The parent's subtree stays open until this message's whole subtree settles. The
13142
+ // unit is taken now, at dispatch — during the parent's handler or afterTransaction,
13143
+ // while the parent's self-unit is still held — so its counter can't reach zero first.
13488
13144
  pushSend(path, name, args = [], parent = null, origin = null, txnPath = null) {
13489
13145
  const t = new SendEvent(path, this, name, args, parent);
13490
13146
  t.txnPath = txnPath;
13491
13147
  t.origin = origin;
13492
13148
  t.originPinned = origin === null ? null : origin.toTransactionPath().pinKeys(this.state.val);
13493
13149
  this.pushTransaction(t);
13494
- return this._link(t, parent);
13150
+ if (parent) t.completion.carry(parent.completion.track());
13151
+ return t;
13495
13152
  }
13496
13153
  // Raise an intent: a job the sender did not address, walked along a route until
13497
13154
  // something answers. `opts.route` is a list of legs (see DEFAULT_ROUTE) and
@@ -13515,7 +13172,7 @@ var init_transactor = __esm({
13515
13172
  return this.transactions.length > 0;
13516
13173
  }
13517
13174
  transactNext() {
13518
- if (this.hasPendingTransactions) this.transact(this.transactions.shift());
13175
+ this.transact(this.transactions.shift());
13519
13176
  }
13520
13177
  transact(transaction) {
13521
13178
  try {
@@ -13528,8 +13185,7 @@ var init_transactor = __esm({
13528
13185
  } else console.warn("undefined new state", { curState, transaction });
13529
13186
  } finally {
13530
13187
  transaction.ensureWalkAdvanced?.();
13531
- transaction._completion?.ensureSelfSettled();
13532
- transaction._completion?.releaseSelf();
13188
+ transaction._completion?.finish();
13533
13189
  }
13534
13190
  }
13535
13191
  transactInputNow(path, event, eventHandler, dragInfo) {
@@ -13559,41 +13215,41 @@ var init_transactor = __esm({
13559
13215
  whenSubtreeSettled() {
13560
13216
  return this.completion.whenSubtreeSettled();
13561
13217
  }
13562
- afterTransaction() {
13563
- }
13564
- // Ending a walk and forwarding belong to the two dispatch buckets; the base warns
13565
- // rather than throwing, so a stray call from the wrong place is a message and not a
13566
- // crash. `walk` is undefined here, which is how ctx.reply/ctx.fail tell the two apart.
13567
- stop() {
13568
- warnNotIntent("stop");
13569
- }
13570
- forward(_opts) {
13571
- console.warn('ctx.forward() needs a "receive" or "intent" handler - ignored');
13572
- }
13573
- // The kind reported to observers (see Transactor.observe); null on the base.
13574
- get observeKind() {
13575
- return null;
13576
- }
13577
- // The name reported to observers; null on the base. Overridden by NameArgs (the
13578
- // dispatched message name) and InputEvent (the DOM event type). Kept separate from
13579
- // `name`/`ctx.name` so it can't change handler-visible behavior.
13580
- get observeName() {
13581
- return null;
13582
- }
13218
+ // Every transaction kind defines `observeKind` / `observeName` (what observers see;
13219
+ // kept apart from `name`/`ctx.name` so they can't change handler-visible behavior),
13220
+ // `getHandlerAndArgs(root, instance, comps)`, and the three `_forward*` hooks below.
13583
13221
  callHandler(root, instance, draft, comps) {
13584
13222
  const [handler, args] = this.getHandlerAndArgs(root, instance, comps);
13585
13223
  this._resolvedHandler = handler;
13586
13224
  return handler.apply(instance, [draft, ...args]);
13587
13225
  }
13588
- getHandlerAndArgs(_root, _instance, _comps) {
13589
- return null;
13226
+ // `forward` is where a name can LEAVE the component: the message being handled is
13227
+ // raised again as an INTENT under the same name (`_forwardName()`) with the same
13228
+ // arguments unless `opts.args` says otherwise, from the position `_forwardPath()`
13229
+ // names. Deferred to afterTransaction so the state the handler produced is in place
13230
+ // before the walk starts. (`IntentEvent` overrides both: in an intent body, forward
13231
+ // amends the walk that is already running.)
13232
+ forward(opts) {
13233
+ this._forward = opts ?? {};
13234
+ }
13235
+ afterTransaction() {
13236
+ const f = this._forward;
13237
+ if (f === void 0) return;
13238
+ this._forward = void 0;
13239
+ const name = this._forwardName();
13240
+ if (name === void 0) {
13241
+ this.transactor.refuse("FORWARD_NO_NAME", {});
13242
+ return;
13243
+ }
13244
+ const { args = this._forwardArgs(), ...rest } = f;
13245
+ this.transactor.pushIntent(this._forwardPath(), name, args, rest, this);
13590
13246
  }
13591
13247
  // The path used to apply the mutation: the ACTIVE frame of the dispatch path, so
13592
13248
  // an event inside a `<x render="*name">` subtree updates the value where it
13593
13249
  // really lives (the dispatch `this.path` keeps the visual callers, for bubbling).
13250
+ // `txnPath`, when pinned by the sender, wins.
13594
13251
  getTransactionPath() {
13595
- if (this.txnPath !== null) return this.txnPath;
13596
- return this.path.toTransactionPath().compact();
13252
+ return this.txnPath ?? this.path.toTransactionPath();
13597
13253
  }
13598
13254
  run(curRoot, comps) {
13599
13255
  const txnPath = this.getTransactionPath();
@@ -13624,6 +13280,13 @@ var init_transactor = __esm({
13624
13280
  this._dispatchPath ??= this.path.compact();
13625
13281
  return this._dispatchPath;
13626
13282
  }
13283
+ // Only a DOM event's path carries frame-only bind steps (they replay the handler's
13284
+ // arguments, but address no state); the compacted path is where the mutation lands,
13285
+ // so a handler inside @each still updates the component that owns the view. Every
13286
+ // other transaction is dispatched at an already-compacted position.
13287
+ getTransactionPath() {
13288
+ return this.dispatchPath.toTransactionPath();
13289
+ }
13627
13290
  // A DOM event is an ADDRESSED message like any other — it reaches the component that
13628
13291
  // owns the view and stops. It keeps its own class only because it resolves its handler
13629
13292
  // from the compiled view and runs synchronously, not because it is a different channel.
@@ -13633,25 +13296,20 @@ var init_transactor = __esm({
13633
13296
  get observeName() {
13634
13297
  return this.e?.type ?? null;
13635
13298
  }
13636
- // A view's name is a message. `forward` is where that name can LEAVE the component:
13637
- // it becomes an intent with the same name and the same arguments, so a view that says
13638
- // `@on.click="saveDraft .text"` never has to change when an ancestor takes the job over.
13639
- // (A `$method` handler has a name too, so forwarding one raises an intent under it.)
13640
- forward(opts) {
13641
- this._forward = opts ?? {};
13642
- }
13643
- afterTransaction() {
13644
- const f = this._forward;
13645
- if (f === void 0) return;
13646
- this._forward = void 0;
13647
- const { args = this._handlerArgs ?? [], ...rest } = f;
13299
+ // A view's name is a message, and forwarding it means a view that says
13300
+ // `@on.click="saveDraft .text"` never has to change when an ancestor takes the job
13301
+ // over. (A `$method` handler has a name too, so forwarding one raises an intent under
13302
+ // it.) `handler` is a NodeEvent, whose own `name` is the DOM event type; the MESSAGE
13303
+ // name is the one the view wrote, on the handler call it wraps.
13304
+ _forwardName() {
13648
13305
  const hv = this.handler?.handlerCall?.handlerVal ?? this.handler?.handlerVal;
13649
- const name = hv?.name;
13650
- if (name === void 0) {
13651
- this.transactor.refuse("FORWARD_NO_NAME", {});
13652
- return;
13653
- }
13654
- this.transactor.pushIntent(this.dispatchPath, name, args, rest, this);
13306
+ return hv?.name;
13307
+ }
13308
+ _forwardArgs() {
13309
+ return this._handlerArgs ?? [];
13310
+ }
13311
+ _forwardPath() {
13312
+ return this.dispatchPath;
13655
13313
  }
13656
13314
  getHandlerAndArgs(root, _instance, comps) {
13657
13315
  const stack = this.path.buildStack(Stack.root(comps, root, this));
@@ -13661,12 +13319,6 @@ var init_transactor = __esm({
13661
13319
  args.push(new EventContext(path, this.transactor, this));
13662
13320
  return [handler, args];
13663
13321
  }
13664
- // The dispatched DOM event, read only through `e.<member>` handler args
13665
- // (src/value.js EventMemberVal via Stack.lookupEvent). There is no bare
13666
- // implicit-name vocabulary anymore: every arg carries a sigil.
13667
- get event() {
13668
- return this.e;
13669
- }
13670
13322
  };
13671
13323
  NameArgsTransaction = class extends Transaction {
13672
13324
  constructor(path, transactor, name, args, parentTransaction) {
@@ -13684,6 +13336,17 @@ var init_transactor = __esm({
13684
13336
  get observeName() {
13685
13337
  return this.name;
13686
13338
  }
13339
+ // `forward` in a RECEIVE body starts a walk: the message that arrived becomes an
13340
+ // intent, keeping its name and payload.
13341
+ _forwardName() {
13342
+ return this.name;
13343
+ }
13344
+ _forwardArgs() {
13345
+ return this.args;
13346
+ }
13347
+ _forwardPath() {
13348
+ return this.path;
13349
+ }
13687
13350
  getHandlerForName(comp) {
13688
13351
  const handlers = comp?.[this.handlerProp];
13689
13352
  const exact = handlers?.[this.name];
@@ -13714,19 +13377,6 @@ var init_transactor = __esm({
13714
13377
  get observeKind() {
13715
13378
  return this._isAnswer ? "answer" : "receive";
13716
13379
  }
13717
- // `forward` in a RECEIVE body starts a walk: the message that arrived becomes an
13718
- // intent, keeping its name and payload. This is what lets a view's name leave the
13719
- // component without the view changing.
13720
- forward(opts) {
13721
- this._forward = opts ?? {};
13722
- }
13723
- afterTransaction() {
13724
- const f = this._forward;
13725
- if (f === void 0) return;
13726
- this._forward = void 0;
13727
- const { args = this.args, ...rest } = f;
13728
- this.transactor.pushIntent(this.path, this.name, args, rest, this);
13729
- }
13730
13380
  };
13731
13381
  IntentEvent = class extends NameArgsTransaction {
13732
13382
  handlerProp = "intent";
@@ -13740,9 +13390,6 @@ var init_transactor = __esm({
13740
13390
  forward(opts) {
13741
13391
  this.walk.amend(opts, this.path);
13742
13392
  }
13743
- stop() {
13744
- this.walk.finish(null, null);
13745
- }
13746
13393
  afterTransaction() {
13747
13394
  this.ensureWalkAdvanced();
13748
13395
  }
@@ -13792,7 +13439,7 @@ var init_transactor = __esm({
13792
13439
  this.legIndex++;
13793
13440
  return this._tryLex();
13794
13441
  }
13795
- console.warn("unknown intent route leg", leg, '- expected "dyn" or "lex"');
13442
+ warnUnknownLeg("intent", leg);
13796
13443
  this.legIndex++;
13797
13444
  }
13798
13445
  this.exhaust("noHandler");
@@ -13881,7 +13528,7 @@ var init_transactor = __esm({
13881
13528
  t.txnPath = this.answerPath;
13882
13529
  t._isAnswer = true;
13883
13530
  this.transactor.pushTransaction(t);
13884
- if (this.release) t.completion.whenSubtreeSettled().then(this.release);
13531
+ if (this.release) t.completion.carry(this.release);
13885
13532
  }
13886
13533
  };
13887
13534
  Completion = class {
@@ -13889,12 +13536,12 @@ var init_transactor = __esm({
13889
13536
  this.val = void 0;
13890
13537
  this.selfSettled = false;
13891
13538
  this.subtreeSettled = false;
13892
- this.pending = 1;
13539
+ this.pending = 0;
13893
13540
  this._selfResolve = null;
13894
13541
  this._selfPromise = null;
13895
13542
  this._subtreeResolve = null;
13896
13543
  this._subtreePromise = null;
13897
- this._selfReleased = false;
13544
+ this._releaseSelf = this.track();
13898
13545
  }
13899
13546
  whenSettled() {
13900
13547
  if (this.selfSettled) return Promise.resolve(this.val);
@@ -13917,38 +13564,38 @@ var init_transactor = __esm({
13917
13564
  this.val = val;
13918
13565
  this._selfResolve?.(val);
13919
13566
  }
13920
- // Settle self even when no handler produced a value (undefined-state / throw paths).
13921
- ensureSelfSettled() {
13922
- if (!this.selfSettled) this.markSelfSettled(this.val);
13567
+ // The transaction is done processing: self is settled (with the value the handler
13568
+ // produced, or none on the undefined-state / throw paths) and the self-unit goes.
13569
+ finish() {
13570
+ this.markSelfSettled(this.val);
13571
+ this._releaseSelf();
13923
13572
  }
13924
- // Register an outstanding unit; returns a one-shot release.
13573
+ // Register an outstanding unit; returns its one-shot release. The subtree settles
13574
+ // when the last unit is released.
13925
13575
  track() {
13926
13576
  this.pending++;
13927
13577
  let done = false;
13928
13578
  return () => {
13929
13579
  if (done) return;
13930
13580
  done = true;
13931
- this._release();
13581
+ if (--this.pending === 0) {
13582
+ this.subtreeSettled = true;
13583
+ this._subtreeResolve?.(this.val);
13584
+ }
13932
13585
  };
13933
13586
  }
13934
- releaseSelf() {
13935
- if (this._selfReleased) return;
13936
- this._selfReleased = true;
13937
- this._release();
13938
- }
13939
- _release() {
13940
- if (--this.pending === 0) {
13941
- this.subtreeSettled = true;
13942
- this._subtreeResolve?.(this.val);
13943
- }
13587
+ // Hand a unit held elsewhere to this subtree: `release` runs once this transaction
13588
+ // and everything it spawned have settled.
13589
+ carry(release) {
13590
+ this.whenSubtreeSettled().then(release);
13944
13591
  }
13945
13592
  };
13946
13593
  Dispatcher = class {
13947
- constructor(path, transactor, parentTransaction, root = transactor.state.val) {
13594
+ constructor(path, transactor, parentTransaction) {
13948
13595
  this.path = path;
13949
13596
  this.transactor = transactor;
13950
13597
  this.parent = parentTransaction;
13951
- this.root = root;
13598
+ this.root = transactor.state.val;
13952
13599
  }
13953
13600
  // Walk the component instances on this ctx's path, leaf→root, calling
13954
13601
  // callback(Component, instance). Return false from the callback to stop early.
@@ -13981,12 +13628,14 @@ var init_transactor = __esm({
13981
13628
  // Resolve a name the way the renderer would. `opts.route` takes the same legs in
13982
13629
  // the same spelling as `ctx.intent` — `["dyn"]` the render ancestry, `["lex"]` the
13983
13630
  // registration scope, default both.
13631
+ // Legs are tried in route order, like the intent walker's; an unknown leg warns and
13632
+ // is skipped, and an empty route resolves to null.
13984
13633
  lookup(name, opts) {
13985
- return routeLookup(
13986
- opts?.route ?? DEFAULT_ROUTE,
13987
- () => this._lookupLex(name),
13988
- () => this._stack()?.lookupDynamic(name) ?? null
13989
- );
13634
+ for (const leg of opts?.route ?? DEFAULT_ROUTE) {
13635
+ const v = leg === "dyn" ? this._stack()?.lookupDynamic(name) ?? null : leg === "lex" ? this._lookupLex(name) : warnUnknownLeg("lookup", leg);
13636
+ if (v != null) return v;
13637
+ }
13638
+ return null;
13990
13639
  }
13991
13640
  // The `lex` leg without a Stack: the scope of the component whose handler is
13992
13641
  // running, which is the leaf of this ctx's path. A type name resolves to the
@@ -14071,9 +13720,10 @@ var init_transactor = __esm({
14071
13720
  this.parent.originPinned
14072
13721
  );
14073
13722
  }
14074
- // End the walk answering nothing — "served, and no answer".
13723
+ // End the walk answering nothing — "served, and no answer". Like reply/fail,
13724
+ // legal only in an `intent` handler.
14075
13725
  stop() {
14076
- return this.parent.stop();
13726
+ return this.parent.walk === void 0 ? warnNotIntent("stop") : this.parent.walk.finish(null, null);
14077
13727
  }
14078
13728
  // From an `intent` body: hand the intent to the next hop, optionally amending it.
14079
13729
  // From a `receive` body: turn the message that arrived into an intent. One word from
@@ -14152,7 +13802,6 @@ var init_app = __esm({
14152
13802
  this.transactor = new Transactor(comps, null);
14153
13803
  this.ParseContext = ParseContext2;
14154
13804
  this.renderer = renderer;
14155
- this.maxEventNodeDepth = Infinity;
14156
13805
  this._transactNextBatchId = this._evictCacheId = null;
14157
13806
  this._eventNames = new Set(_evs);
14158
13807
  this.dragInfo = this.curDragOver = null;
@@ -14179,12 +13828,11 @@ var init_app = __esm({
14179
13828
  _dispatchEvent(e) {
14180
13829
  const { type: type3 } = e;
14181
13830
  const isDrag = type3 === "dragover" || type3 === "dragstart" || type3 === "dragend" || type3 === "drop";
14182
- const { rootNode: root, maxEventNodeDepth: maxDepth, comps, transactor } = this;
13831
+ const { rootNode, comps, transactor } = this;
14183
13832
  const [path, handlers] = DispatchPath.fromNodeAndEventName(
14184
13833
  e.target,
14185
13834
  type3,
14186
- root,
14187
- maxDepth,
13835
+ rootNode,
14188
13836
  comps,
14189
13837
  !isDrag
14190
13838
  );
@@ -14293,10 +13941,9 @@ var init_app = __esm({
14293
13941
  }
14294
13942
  compile() {
14295
13943
  for (const Comp of this.comps.byId.values()) {
14296
- const meta = Comp[COMPONENT];
14297
- meta.compile(this.ParseContext);
14298
- for (const key in meta.views)
14299
- for (const name of meta.views[key].ctx.genEventNames()) this._eventNames.add(name);
13944
+ Comp.compile(this.ParseContext);
13945
+ for (const key in Comp.views)
13946
+ for (const name of Comp.views[key].ctx.genEventNames()) this._eventNames.add(name);
14300
13947
  }
14301
13948
  this._compiled = true;
14302
13949
  }
@@ -14319,6 +13966,8 @@ var init_app = __esm({
14319
13966
  }
14320
13967
  stop() {
14321
13968
  this.stopCacheEvictionInterval();
13969
+ clearTimeout(this._transactNextBatchId);
13970
+ this._transactNextBatchId = null;
14322
13971
  for (const name of this._eventNames)
14323
13972
  this.rootNode.removeEventListener(name, this, listenerOpts(name));
14324
13973
  }
@@ -14407,28 +14056,21 @@ var init_cache = __esm({
14407
14056
  set(_keys, _cacheKey, _v) {
14408
14057
  }
14409
14058
  evict() {
14410
- return { hit: 0, miss: 0, badKey: 0 };
14411
14059
  }
14412
14060
  };
14413
14061
  WeakMapDomCache = class {
14414
14062
  constructor() {
14415
- this.hit = this.miss = this.badKey = 0;
14416
14063
  this.keysByLen = /* @__PURE__ */ new Map();
14417
14064
  }
14418
- _returnValue(r) {
14419
- if (r === void 0) this.miss += 1;
14420
- else this.hit += 1;
14421
- return r;
14422
- }
14423
14065
  get(keys, cacheKey) {
14424
14066
  const len = keys.length;
14425
14067
  let cur = this.keysByLen.get(len);
14426
- if (!cur) return this._returnValue(void 0);
14068
+ if (!cur) return void 0;
14427
14069
  for (let i = 0; i < len - 1; i++) {
14428
14070
  cur = cur.get(keys[i]);
14429
- if (!cur) return this._returnValue(void 0);
14071
+ if (!cur) return void 0;
14430
14072
  }
14431
- return this._returnValue(cur.get(keys[len - 1])?.[cacheKey]);
14073
+ return cur.get(keys[len - 1])?.[cacheKey];
14432
14074
  }
14433
14075
  set(keys, cacheKey, v) {
14434
14076
  const len = keys.length;
@@ -14441,10 +14083,7 @@ var init_cache = __esm({
14441
14083
  const key = keys[i];
14442
14084
  let next = cur.get(key);
14443
14085
  if (!next) {
14444
- if (!isWeakKey(key)) {
14445
- this.badKey += 1;
14446
- return;
14447
- }
14086
+ if (!isWeakKey(key)) return;
14448
14087
  next = /* @__PURE__ */ new WeakMap();
14449
14088
  cur.set(key, next);
14450
14089
  }
@@ -14454,13 +14093,9 @@ var init_cache = __esm({
14454
14093
  const leaf = cur.get(lastKey);
14455
14094
  if (leaf) leaf[cacheKey] = v;
14456
14095
  else if (isWeakKey(lastKey)) cur.set(lastKey, { [cacheKey]: v });
14457
- else this.badKey += 1;
14458
14096
  }
14459
14097
  evict() {
14460
- const { hit, miss, badKey } = this;
14461
- this.hit = this.miss = this.badKey = 0;
14462
14098
  this.keysByLen = /* @__PURE__ */ new Map();
14463
- return { hit, miss, badKey };
14464
14099
  }
14465
14100
  };
14466
14101
  }
@@ -14480,7 +14115,7 @@ function stampRenderBase(vdom, text) {
14480
14115
  return new VFragment(vdom.childs.map((c) => stampRenderBase(c, text)));
14481
14116
  return vdom;
14482
14117
  }
14483
- var DATASET_ATTRS, Renderer;
14118
+ var Renderer;
14484
14119
  var init_renderer = __esm({
14485
14120
  "src/renderer.js"() {
14486
14121
  init_cache();
@@ -14488,12 +14123,18 @@ var init_renderer = __esm({
14488
14123
  init_path();
14489
14124
  init_value();
14490
14125
  init_vdom();
14491
- DATASET_ATTRS = ["nid", "cid", "eid", "vid", "si", "sk", "rp"];
14492
14126
  Renderer = class {
14493
14127
  constructor(comps) {
14494
14128
  this.comps = comps;
14495
14129
  this.cache = new WeakMapDomCache();
14496
- this.renderTag = h;
14130
+ }
14131
+ // Parse nodes build their VDOM through the renderer, never by importing vdom.js
14132
+ // themselves: a component may have been compiled by ANOTHER copy of the library
14133
+ // (a docs example imports the dist bundle while the host app runs from src), and
14134
+ // `render()` recognizes VNodes by `instanceof` against ITS copy's classes. Going
14135
+ // through `rx` guarantees the rendering copy makes them.
14136
+ renderTag(tag, attrs, childs, namespace) {
14137
+ return h(tag, attrs, childs, namespace);
14497
14138
  }
14498
14139
  renderFragment(childs) {
14499
14140
  return new VFragment(childs);
@@ -14504,30 +14145,16 @@ var init_renderer = __esm({
14504
14145
  setNullCache() {
14505
14146
  this.cache = new NullDomCache();
14506
14147
  }
14507
- // Library utilities for consumers embedding tutuca: render a value to a detached
14508
- // DOM node / an HTML string. Not called by the framework itself.
14509
- renderToDOM(stack, val) {
14510
- const rootNode = document.createElement("div");
14511
- const rOpts = { document };
14512
- render(h("DIV", null, [this.renderRoot(stack, val)]), rootNode, rOpts);
14513
- return rootNode.childNodes[0];
14514
- }
14515
- renderToString(stack, val, cleanAttrs = true) {
14516
- const dom = this.renderToDOM(stack, val);
14517
- if (cleanAttrs) {
14518
- const nodes = dom.querySelectorAll("[data-nid],[data-cid],[data-eid]");
14519
- for (const { dataset } of nodes) for (const name of DATASET_ATTRS) delete dataset[name];
14520
- }
14521
- return dom.innerHTML;
14522
- }
14523
14148
  renderRoot(stack, val, viewName = null) {
14524
14149
  const comp = this.comps.getCompFor(val);
14525
14150
  if (comp === null) return null;
14526
14151
  return this._rValComp(stack, val, comp, comp.getView(viewName).anode, "ROOT", viewName);
14527
14152
  }
14528
- renderIt(stack, node, key, viewName, base = null) {
14153
+ // Render `stack.it` at a `<x render*>` site (`node`). `base` is the absolute
14154
+ // path the site resumed at, when it rendered a `*name` (see _rValComp).
14155
+ renderIt(stack, node, viewName, base = null) {
14529
14156
  const comp = this.comps.getCompFor(stack.it);
14530
- return comp ? this._rValComp(stack, stack.it, comp, node, key, viewName, base) : null;
14157
+ return comp ? this._rValComp(stack, stack.it, comp, node, "", viewName, base) : null;
14531
14158
  }
14532
14159
  // `node` is the parse node of the render site (`<x render>` / `render-it` /
14533
14160
  // `render-each`, or the view's root anode for the app root). It keys the
@@ -14562,9 +14189,9 @@ var init_renderer = __esm({
14562
14189
  r.push(this._renderMetadata({ $: "Each", nid, [attrName]: key }), dom);
14563
14190
  }
14564
14191
  renderEachWhen(stack, each2) {
14565
- const { iterInfo, node: view, nodeId: nid } = each2;
14566
- const { seq, filter, loopWith, enricher } = iterInfo.eval(stack);
14567
- const seqPath = iterInfo.val instanceof DynVal ? stack.lookupDynamicLocated(iterInfo.val.name)?.path ?? null : null;
14192
+ const { val: seqVal, node: view, nodeId: nid } = each2;
14193
+ const { seq, filter, loopWith, enricher } = each2.evalIter(stack);
14194
+ const seqPath = seqVal instanceof DynVal ? stack.lookupDynamicLocated(seqVal.name)?.path ?? null : null;
14568
14195
  const r = [];
14569
14196
  const it = stack.it;
14570
14197
  const renderOne = (key, value, attrName, binds) => {
@@ -14617,9 +14244,7 @@ var init_renderer = __esm({
14617
14244
 
14618
14245
  // src/util/render.js
14619
14246
  function reindexComponents(comps) {
14620
- for (let i = 0; i < comps.length; i++) {
14621
- comps[i][COMPONENT].id = i;
14622
- }
14247
+ for (let i = 0; i < comps.length; i++) comps[i].id = i;
14623
14248
  }
14624
14249
  function serializeContainer(container) {
14625
14250
  for (const input of container.querySelectorAll("input")) {
@@ -14628,19 +14253,19 @@ function serializeContainer(container) {
14628
14253
  }
14629
14254
  return container.innerHTML;
14630
14255
  }
14631
- function renderToHTMLNode(document2, components, macros, rootState, ParseContext2, opts = { noCache: true }) {
14256
+ function renderToHTMLNode(document2, components, macros, rootState, ParseContext2, { noCache = true, paths = null, intentHandlers = null, view = null } = {}) {
14632
14257
  const container = document2.createElement("div");
14633
14258
  document2.body.appendChild(container);
14634
14259
  reindexComponents(components);
14635
14260
  const comps = new Components();
14636
14261
  const renderer = new Renderer(comps);
14637
14262
  const app = new App(container, comps, renderer, ParseContext2);
14638
- const scope = app.registerComponents(components, { paths: opts.paths });
14263
+ const scope = app.registerComponents(components, { paths });
14639
14264
  if (macros) scope.registerMacros(macros);
14640
- if (opts.intentHandlers) scope.registerIntentHandlers(opts.intentHandlers);
14641
- app.rootViewName = opts.view ?? null;
14265
+ if (intentHandlers) scope.registerIntentHandlers(intentHandlers);
14266
+ app.rootViewName = view;
14642
14267
  app.transactor.state.set(rootState);
14643
- app.start(opts);
14268
+ app.start({ noCache });
14644
14269
  return {
14645
14270
  container,
14646
14271
  app,
@@ -14650,14 +14275,14 @@ function renderToHTMLNode(document2, components, macros, rootState, ParseContext
14650
14275
  }
14651
14276
  };
14652
14277
  }
14653
- async function renderToHTMLDriven(document2, components, macros, rootState, ParseContext2, { phase = null, intentHandlers = null, view = null } = {}) {
14278
+ async function renderToHTMLDriven(document2, components, macros, rootState, ParseContext2, { phase = null, ...opts } = {}) {
14654
14279
  const { container, app, cleanup } = renderToHTMLNode(
14655
14280
  document2,
14656
14281
  components,
14657
14282
  macros,
14658
14283
  rootState,
14659
14284
  ParseContext2,
14660
- { noCache: true, intentHandlers, view }
14285
+ opts
14661
14286
  );
14662
14287
  try {
14663
14288
  if (phase) {
@@ -15599,23 +15224,30 @@ function installSkill(skill, root, scope, force, dotAgents, dryRun, opts) {
15599
15224
  });
15600
15225
  }
15601
15226
  const target = targetDir(scope, skill.name, dotAgents);
15602
- if (targetHasSkillFiles(target) && !force) {
15603
- emitError(opts, {
15604
- code: CODES.SKILL_TARGET_EXISTS,
15605
- message: `${target} already contains skill files`,
15606
- hint: "Re-run with --force to overwrite, or --dry-run to see what would change."
15607
- });
15608
- }
15609
15227
  const baseDir = dotAgents ? ".agents/skills" : ".claude/skills";
15610
15228
  const rel = scope === "project" ? `${baseDir}/${skill.name}` : target;
15229
+ const exists = targetHasSkillFiles(target);
15611
15230
  if (dryRun) {
15612
15231
  const files = walkFiles(src, { match: () => true }).map((f) => relative(src, f));
15613
15232
  process.stdout.write(`would install ${skill.name} skill → ${rel}
15614
15233
  `);
15615
15234
  for (const f of files) process.stdout.write(` + ${f}
15616
15235
  `);
15236
+ if (exists) {
15237
+ process.stdout.write(
15238
+ ` note: ${rel} already contains skill files; re-run with --force to overwrite them
15239
+ `
15240
+ );
15241
+ }
15617
15242
  return;
15618
15243
  }
15244
+ if (exists && !force) {
15245
+ emitError(opts, {
15246
+ code: CODES.SKILL_TARGET_EXISTS,
15247
+ message: `${target} already contains skill files`,
15248
+ hint: "Re-run with --force to overwrite, or --dry-run to see what would change."
15249
+ });
15250
+ }
15619
15251
  mkdirSync2(target, { recursive: true });
15620
15252
  cpSync(src, target, { recursive: true });
15621
15253
  process.stdout.write(`installed ${skill.name} skill → ${rel}
@@ -15713,16 +15345,16 @@ async function createNodeEnv() {
15713
15345
  const dom = new JSDOM("<!DOCTYPE html><html><head></head><body></body></html>", {
15714
15346
  virtualConsole
15715
15347
  });
15716
- const { document: document2, Text, Comment } = dom.window;
15348
+ const { document: document2 } = dom.window;
15717
15349
  globalThis.document = document2;
15718
15350
  class HeadlessParseContext extends ParseContext {
15719
15351
  constructor() {
15720
- super(document2, Text, Comment);
15352
+ super(document2);
15721
15353
  }
15722
15354
  }
15723
15355
  class HeadlessLintParseContext extends LintParseContext {
15724
15356
  constructor() {
15725
- super(document2, Text, Comment);
15357
+ super(document2);
15726
15358
  }
15727
15359
  }
15728
15360
  return {
@@ -15731,7 +15363,7 @@ async function createNodeEnv() {
15731
15363
  LintParseContext: HeadlessLintParseContext
15732
15364
  };
15733
15365
  }
15734
- var init_env2 = __esm({
15366
+ var init_env = __esm({
15735
15367
  "tools/cli/env.js"() {
15736
15368
  init_anode();
15737
15369
  init_lint_check();
@@ -16232,7 +15864,7 @@ var init_storybook = __esm({
16232
15864
  init_chai2();
16233
15865
  init_module();
16234
15866
  init_test();
16235
- init_env2();
15867
+ init_env();
16236
15868
  init_errors();
16237
15869
  init_pkg();
16238
15870
  init_walk();
@@ -16417,7 +16049,7 @@ export async function resolve(specifier, context, nextResolve) {
16417
16049
  init_errors();
16418
16050
 
16419
16051
  // tools/cli/with-module.js
16420
- init_env2();
16052
+ init_env();
16421
16053
  init_errors();
16422
16054
  import { statSync as statSync2 } from "node:fs";
16423
16055
  import { parseArgs as parseArgs4 } from "node:util";