tutuca 0.9.97 → 0.9.99

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.
@@ -95,7 +95,6 @@ import {
95
95
  util
96
96
  } from "chai";
97
97
  chai.use(jestMatchers);
98
-
99
98
  // src/value.js
100
99
  import { is } from "immutable";
101
100
 
@@ -1842,37 +1841,47 @@ class Renderer {
1842
1841
  renderEach(stack, iterInfo, node, viewName) {
1843
1842
  const { seq, filter, loopWith } = iterInfo.eval(stack);
1844
1843
  const r = [];
1845
- const { iterData, start, end } = unpackLoopResult(loopWith.call(stack.it, seq), seq);
1846
- getSeqInfo(seq)(seq, (key, value, attrName) => {
1847
- if (filter.call(stack.it, key, value, iterData)) {
1848
- const dom = this.renderIt(stack.enter(value, { key }, true), node, key, viewName);
1849
- this.pushEachEntry(r, node.nodeId, attrName, key, dom);
1850
- }
1851
- }, start, end);
1844
+ const { iterData, start, end, keys } = unpackLoopResult(loopWith.call(stack.it, seq, makeLoopCtx(stack, filter)), seq);
1845
+ const renderOne = (key, value, attrName) => {
1846
+ const dom = this.renderIt(stack.enter(value, { key }, true), node, key, viewName);
1847
+ this.pushEachEntry(r, node.nodeId, attrName, key, dom);
1848
+ };
1849
+ if (keys)
1850
+ imKeysIter(seq, renderOne, keys);
1851
+ else
1852
+ getSeqInfo(seq)(seq, (key, value, attrName) => {
1853
+ if (filter.call(stack.it, key, value, iterData))
1854
+ renderOne(key, value, attrName);
1855
+ }, start, end);
1852
1856
  return r;
1853
1857
  }
1854
1858
  renderEachWhen(stack, iterInfo, view, nid) {
1855
1859
  const { seq, filter, loopWith, enricher } = iterInfo.eval(stack);
1856
1860
  const r = [];
1857
1861
  const it = stack.it;
1858
- const { iterData, start, end } = unpackLoopResult(loopWith.call(it, seq), seq);
1859
- getSeqInfo(seq)(seq, (key, value, attrName) => {
1860
- if (filter.call(it, key, value, iterData)) {
1861
- const cachePath = enricher ? [view, it, value] : [view, value];
1862
- const binds = { key, value };
1863
- const cacheKey = `${nid}-${key}`;
1864
- if (enricher)
1865
- enricher.call(it, binds, key, value, iterData);
1866
- const cachedNode = this.cache.get(cachePath, cacheKey);
1867
- if (cachedNode)
1868
- this.pushEachEntry(r, nid, attrName, key, cachedNode);
1869
- else {
1870
- const dom = this.renderView(view, stack.enter(value, binds, false));
1871
- this.pushEachEntry(r, nid, attrName, key, dom);
1872
- this.cache.set(cachePath, cacheKey, dom);
1873
- }
1862
+ const { iterData, start, end, keys } = unpackLoopResult(loopWith.call(it, seq, makeLoopCtx(stack, filter)), seq);
1863
+ const renderOne = (key, value, attrName) => {
1864
+ const cachePath = enricher ? [view, it, value] : [view, value];
1865
+ const binds = { key, value };
1866
+ const cacheKey = `${nid}-${key}`;
1867
+ if (enricher)
1868
+ enricher.call(it, binds, key, value, iterData);
1869
+ const cachedNode = this.cache.get(cachePath, cacheKey);
1870
+ if (cachedNode)
1871
+ this.pushEachEntry(r, nid, attrName, key, cachedNode);
1872
+ else {
1873
+ const dom = this.renderView(view, stack.enter(value, binds, false));
1874
+ this.pushEachEntry(r, nid, attrName, key, dom);
1875
+ this.cache.set(cachePath, cacheKey, dom);
1874
1876
  }
1875
- }, start, end);
1877
+ };
1878
+ if (keys)
1879
+ imKeysIter(seq, renderOne, keys);
1880
+ else
1881
+ getSeqInfo(seq)(seq, (key, value, attrName) => {
1882
+ if (filter.call(it, key, value, iterData))
1883
+ renderOne(key, value, attrName);
1884
+ }, start, end);
1876
1885
  return r;
1877
1886
  }
1878
1887
  renderView(view, stack) {
@@ -1908,8 +1917,17 @@ var filterAlwaysTrue = (_v, _k, _seq) => true;
1908
1917
  var nullLoopWith = (seq) => ({ iterData: { seq } });
1909
1918
  var unpackLoopResult = (result, seq) => {
1910
1919
  const r = result ?? {};
1911
- return { iterData: r.iterData ?? { seq }, start: r.start, end: r.end };
1920
+ return { iterData: r.iterData ?? { seq }, start: r.start, end: r.end, keys: r.keys };
1921
+ };
1922
+ var imKeysIter = (seq, visit, keys) => {
1923
+ const attrName = isIndexed(seq) ? "si" : "sk";
1924
+ for (const key of keys)
1925
+ visit(key, seq.get(key), attrName);
1912
1926
  };
1927
+ var makeLoopCtx = (stack, filter) => ({
1928
+ lookup: (name) => stack.lookupBind(name),
1929
+ filter: (key, value, iterData) => filter.call(stack.it, key, value, iterData)
1930
+ });
1913
1931
  var imIndexedIter = (seq, visit, start, end) => {
1914
1932
  const [s, e] = normalizeRange(start, end, seq.size);
1915
1933
  for (let i = s;i < e; i++)
@@ -2457,11 +2475,11 @@ class IterInfo {
2457
2475
  return { seq, filter, loopWith, enricher };
2458
2476
  }
2459
2477
  enrichBinds(stack, key) {
2460
- const { seq, loopWith, enricher } = this.eval(stack);
2478
+ const { seq, filter, loopWith, enricher } = this.eval(stack);
2461
2479
  const value = seq?.get ? seq.get(key, null) : null;
2462
2480
  const binds = { key, value };
2463
2481
  if (enricher) {
2464
- const { iterData } = unpackLoopResult(loopWith.call(stack.it, seq), seq);
2482
+ const { iterData } = unpackLoopResult(loopWith.call(stack.it, seq, makeLoopCtx(stack, filter)), seq);
2465
2483
  enricher.call(stack.it, binds, key, value, iterData);
2466
2484
  }
2467
2485
  return binds;
@@ -3470,7 +3488,6 @@ var RAW_TEXT_ELEMENTS = new Set([
3470
3488
  "xmp",
3471
3489
  "plaintext"
3472
3490
  ]);
3473
- var RCDATA_ELEMENTS = new Set(["textarea", "title"]);
3474
3491
  var SPECIAL_ELEMENTS = new Set([
3475
3492
  "address",
3476
3493
  "applet",
@@ -3585,7 +3602,6 @@ var SCOPE_LIST_ITEM = new Set([...DEFAULT_SCOPE_BOUNDARIES, "ol", "ul"]);
3585
3602
  var SCOPE_BUTTON = new Set([...DEFAULT_SCOPE_BOUNDARIES, "button"]);
3586
3603
  var SCOPE_DEFAULT = DEFAULT_SCOPE_BOUNDARIES;
3587
3604
  var SCOPE_TABLE = new Set(["html", "table", "template"]);
3588
- var SCOPE_SELECT = new Set;
3589
3605
  var STANDARD_SVG_CAMEL_ELEMENTS = new Set([
3590
3606
  "altGlyph",
3591
3607
  "altGlyphDef",
@@ -3737,7 +3753,6 @@ var FOREIGN_BREAKOUT_TAGS = new Set([
3737
3753
  "ul",
3738
3754
  "var"
3739
3755
  ]);
3740
- var MATHML_TEXT_INTEGRATION_POINTS = new Set(["mi", "mo", "mn", "ms", "mtext"]);
3741
3756
  var BLOCK_LEVEL_AUTO_CLOSE_P = new Set([
3742
3757
  "address",
3743
3758
  "article",
@@ -3780,7 +3795,6 @@ var BLOCK_LEVEL_AUTO_CLOSE_P = new Set([
3780
3795
  "dd",
3781
3796
  "dt"
3782
3797
  ]);
3783
- var SELECT_VALID_CHILDREN = new Set(["option", "optgroup", "hr", "script", "template"]);
3784
3798
  var SELECT_BREAKOUT_TAGS = new Set(["input", "keygen", "textarea", "select"]);
3785
3799
  var MODES = Object.freeze({
3786
3800
  inBody: "inBody",
@@ -6040,6 +6054,13 @@ function phaseOps(phase) {
6040
6054
  function resolveArgs(args, self) {
6041
6055
  return typeof args === "function" ? args(self) ?? [] : args ?? [];
6042
6056
  }
6057
+ function phaseHasBubble(phase) {
6058
+ if (!phase)
6059
+ return false;
6060
+ if (phase.bubble?.length)
6061
+ return true;
6062
+ return (phase.do ?? []).some((op) => op.type === "bubble");
6063
+ }
6043
6064
  function dispatchPhase(dispatcher, targetPath, phase, self) {
6044
6065
  if (!phase)
6045
6066
  return;
@@ -6976,6 +6997,8 @@ async function driveStack(stack, value, phase, opts = {}) {
6976
6997
  const t = info?.transaction;
6977
6998
  opts.onMessage({ kind: t?.handlerProp ?? "input", name: t?.name, args: t?.args, path: t?.path }, old, val);
6978
6999
  });
7000
+ if (phaseHasBubble(phase))
7001
+ console.warn("drive(): a `bubble` action is a no-op here — drive originates at the root and bubbles travel child→parent, so there is no ancestor to receive it (and the root's own bubble handler is skipped). To exercise a bubble handler, call it directly.");
6979
7002
  dispatchPhase(rootDispatcher(transactor), new Path([]), phase, value);
6980
7003
  await transactor.settle();
6981
7004
  return transactor.state.val;
@@ -7964,7 +7987,8 @@ class FieldSet extends Field {
7964
7987
  }
7965
7988
  function mkCompField(field, scope, args) {
7966
7989
  const Comp = scope?.lookupComponent(field.type) ?? null;
7967
- console.assert(!scope || Comp !== null, "component not found", { field });
7990
+ if (Comp === null)
7991
+ console.warn(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)`);
7968
7992
  return Comp?.make({ ...field.args, ...args }, { scope }) ?? null;
7969
7993
  }
7970
7994
 
@@ -8138,13 +8162,30 @@ function resolveAlter(Comp, name) {
8138
8162
  }
8139
8163
  return fn;
8140
8164
  }
8165
+ var seqGet = (seq, key) => Array.isArray(seq) ? seq[key] : seq.get ? seq.get(key) : seq[key];
8141
8166
  function collectIterBindings(Comp, compInstance, seq, opts = {}) {
8142
8167
  const whenFn = resolveAlter(Comp, opts.when) ?? filterAlwaysTrue;
8143
8168
  const loopWithFn = resolveAlter(Comp, opts.loopWith) ?? nullLoopWith;
8144
8169
  const enrichFn = resolveAlter(Comp, opts.enrichWith);
8170
+ const scopeEnrichFn = resolveAlter(Comp, opts.scopeEnrich);
8145
8171
  const it = compInstance;
8146
- const { iterData, start, end } = unpackLoopResult(loopWithFn.call(it, seq), seq);
8172
+ const scope = scopeEnrichFn ? scopeEnrichFn.call(it) ?? {} : opts.scope ?? {};
8173
+ const ctx = {
8174
+ lookup: (name) => scope[name],
8175
+ filter: (key, value, iterData2) => whenFn.call(it, key, value, iterData2)
8176
+ };
8177
+ const { iterData, start, end, keys } = unpackLoopResult(loopWithFn.call(it, seq, ctx), seq);
8147
8178
  const out = [];
8179
+ if (keys) {
8180
+ for (const key of keys) {
8181
+ const value = seqGet(seq, key);
8182
+ const binds = { key, value };
8183
+ if (enrichFn)
8184
+ enrichFn.call(it, binds, key, value, iterData);
8185
+ out.push(binds);
8186
+ }
8187
+ return out;
8188
+ }
8148
8189
  const iter = pickIter(seq);
8149
8190
  iter(seq, (key, value) => {
8150
8191
  if (!whenFn.call(it, key, value, iterData))
@@ -8333,20 +8374,23 @@ async function test2(opts = {}) {
8333
8374
  reportTestReportToConsole(report);
8334
8375
  return report;
8335
8376
  }
8377
+ function shadowCheckComponent(Comp) {
8378
+ const shadowViews = {};
8379
+ for (const name in Comp.views) {
8380
+ const rawView = Comp.views[name].rawView;
8381
+ const ctx = new LintParseContext;
8382
+ ANode.parse(rawView, ctx);
8383
+ ctx.compile(Comp.scope);
8384
+ shadowViews[name] = { name, ctx, rawView };
8385
+ }
8386
+ const shadowComp = Object.create(Comp);
8387
+ shadowComp.views = shadowViews;
8388
+ return checkComponent(shadowComp).reports;
8389
+ }
8336
8390
  function check(app) {
8337
8391
  const counts = { error: 0, warn: 0, hint: 0 };
8338
8392
  for (const Comp of app.comps.byId.values()) {
8339
- const shadowViews = {};
8340
- for (const name in Comp.views) {
8341
- const rawView = Comp.views[name].rawView;
8342
- const ctx = new LintParseContext;
8343
- ANode.parse(rawView, ctx);
8344
- ctx.compile(Comp.scope);
8345
- shadowViews[name] = { name, ctx, rawView };
8346
- }
8347
- const shadowComp = Object.create(Comp);
8348
- shadowComp.views = shadowViews;
8349
- const { reports } = checkComponent(shadowComp);
8393
+ const reports = shadowCheckComponent(Comp);
8350
8394
  if (reports.length === 0)
8351
8395
  continue;
8352
8396
  console.group(Comp.name);
@@ -8400,6 +8444,7 @@ export {
8400
8444
  tutuca,
8401
8445
  test2 as test,
8402
8446
  suggestionToMessage,
8447
+ shadowCheckComponent,
8403
8448
  setIn,
8404
8449
  set,
8405
8450
  runTests,
@@ -8408,6 +8453,7 @@ export {
8408
8453
  removeIn,
8409
8454
  remove,
8410
8455
  phaseOps,
8456
+ phaseHasBubble,
8411
8457
  mergeWith,
8412
8458
  mergeDeepWith,
8413
8459
  mergeDeep,
@@ -8443,6 +8489,7 @@ export {
8443
8489
  getComponentsDocs,
8444
8490
  get,
8445
8491
  fromJS,
8492
+ expect,
8446
8493
  drive,
8447
8494
  docComponents,
8448
8495
  dispatchPhase,
@@ -3376,7 +3376,6 @@ function jestMatchers(chai, utils) {
3376
3376
 
3377
3377
  // deps/chai.js
3378
3378
  use(jestMatchers);
3379
-
3380
3379
  // deps/immutable.js
3381
3380
  function invariant(condition, error) {
3382
3381
  if (!condition)
@@ -9493,37 +9492,47 @@ class Renderer {
9493
9492
  renderEach(stack, iterInfo, node, viewName) {
9494
9493
  const { seq, filter, loopWith } = iterInfo.eval(stack);
9495
9494
  const r = [];
9496
- const { iterData, start, end } = unpackLoopResult(loopWith.call(stack.it, seq), seq);
9497
- getSeqInfo(seq)(seq, (key, value, attrName) => {
9498
- if (filter.call(stack.it, key, value, iterData)) {
9499
- const dom = this.renderIt(stack.enter(value, { key }, true), node, key, viewName);
9500
- this.pushEachEntry(r, node.nodeId, attrName, key, dom);
9501
- }
9502
- }, start, end);
9495
+ const { iterData, start, end, keys } = unpackLoopResult(loopWith.call(stack.it, seq, makeLoopCtx(stack, filter)), seq);
9496
+ const renderOne = (key, value, attrName) => {
9497
+ const dom = this.renderIt(stack.enter(value, { key }, true), node, key, viewName);
9498
+ this.pushEachEntry(r, node.nodeId, attrName, key, dom);
9499
+ };
9500
+ if (keys)
9501
+ imKeysIter(seq, renderOne, keys);
9502
+ else
9503
+ getSeqInfo(seq)(seq, (key, value, attrName) => {
9504
+ if (filter.call(stack.it, key, value, iterData))
9505
+ renderOne(key, value, attrName);
9506
+ }, start, end);
9503
9507
  return r;
9504
9508
  }
9505
9509
  renderEachWhen(stack, iterInfo, view, nid) {
9506
9510
  const { seq, filter, loopWith, enricher } = iterInfo.eval(stack);
9507
9511
  const r = [];
9508
9512
  const it = stack.it;
9509
- const { iterData, start, end } = unpackLoopResult(loopWith.call(it, seq), seq);
9510
- getSeqInfo(seq)(seq, (key, value, attrName) => {
9511
- if (filter.call(it, key, value, iterData)) {
9512
- const cachePath = enricher ? [view, it, value] : [view, value];
9513
- const binds = { key, value };
9514
- const cacheKey = `${nid}-${key}`;
9515
- if (enricher)
9516
- enricher.call(it, binds, key, value, iterData);
9517
- const cachedNode = this.cache.get(cachePath, cacheKey);
9518
- if (cachedNode)
9519
- this.pushEachEntry(r, nid, attrName, key, cachedNode);
9520
- else {
9521
- const dom = this.renderView(view, stack.enter(value, binds, false));
9522
- this.pushEachEntry(r, nid, attrName, key, dom);
9523
- this.cache.set(cachePath, cacheKey, dom);
9524
- }
9513
+ const { iterData, start, end, keys } = unpackLoopResult(loopWith.call(it, seq, makeLoopCtx(stack, filter)), seq);
9514
+ const renderOne = (key, value, attrName) => {
9515
+ const cachePath = enricher ? [view, it, value] : [view, value];
9516
+ const binds = { key, value };
9517
+ const cacheKey = `${nid}-${key}`;
9518
+ if (enricher)
9519
+ enricher.call(it, binds, key, value, iterData);
9520
+ const cachedNode = this.cache.get(cachePath, cacheKey);
9521
+ if (cachedNode)
9522
+ this.pushEachEntry(r, nid, attrName, key, cachedNode);
9523
+ else {
9524
+ const dom = this.renderView(view, stack.enter(value, binds, false));
9525
+ this.pushEachEntry(r, nid, attrName, key, dom);
9526
+ this.cache.set(cachePath, cacheKey, dom);
9525
9527
  }
9526
- }, start, end);
9528
+ };
9529
+ if (keys)
9530
+ imKeysIter(seq, renderOne, keys);
9531
+ else
9532
+ getSeqInfo(seq)(seq, (key, value, attrName) => {
9533
+ if (filter.call(it, key, value, iterData))
9534
+ renderOne(key, value, attrName);
9535
+ }, start, end);
9527
9536
  return r;
9528
9537
  }
9529
9538
  renderView(view, stack) {
@@ -9559,8 +9568,17 @@ var filterAlwaysTrue = (_v, _k, _seq) => true;
9559
9568
  var nullLoopWith = (seq) => ({ iterData: { seq } });
9560
9569
  var unpackLoopResult = (result, seq) => {
9561
9570
  const r = result ?? {};
9562
- return { iterData: r.iterData ?? { seq }, start: r.start, end: r.end };
9571
+ return { iterData: r.iterData ?? { seq }, start: r.start, end: r.end, keys: r.keys };
9572
+ };
9573
+ var imKeysIter = (seq, visit, keys) => {
9574
+ const attrName = isIndexed(seq) ? "si" : "sk";
9575
+ for (const key of keys)
9576
+ visit(key, seq.get(key), attrName);
9563
9577
  };
9578
+ var makeLoopCtx = (stack, filter) => ({
9579
+ lookup: (name) => stack.lookupBind(name),
9580
+ filter: (key, value, iterData) => filter.call(stack.it, key, value, iterData)
9581
+ });
9564
9582
  var imIndexedIter = (seq, visit, start, end) => {
9565
9583
  const [s, e] = normalizeRange(start, end, seq.size);
9566
9584
  for (let i = s;i < e; i++)
@@ -10108,11 +10126,11 @@ class IterInfo {
10108
10126
  return { seq, filter, loopWith, enricher };
10109
10127
  }
10110
10128
  enrichBinds(stack, key) {
10111
- const { seq, loopWith, enricher } = this.eval(stack);
10129
+ const { seq, filter, loopWith, enricher } = this.eval(stack);
10112
10130
  const value = seq?.get ? seq.get(key, null) : null;
10113
10131
  const binds = { key, value };
10114
10132
  if (enricher) {
10115
- const { iterData } = unpackLoopResult(loopWith.call(stack.it, seq), seq);
10133
+ const { iterData } = unpackLoopResult(loopWith.call(stack.it, seq, makeLoopCtx(stack, filter)), seq);
10116
10134
  enricher.call(stack.it, binds, key, value, iterData);
10117
10135
  }
10118
10136
  return binds;
@@ -11121,7 +11139,6 @@ var RAW_TEXT_ELEMENTS = new Set([
11121
11139
  "xmp",
11122
11140
  "plaintext"
11123
11141
  ]);
11124
- var RCDATA_ELEMENTS = new Set(["textarea", "title"]);
11125
11142
  var SPECIAL_ELEMENTS = new Set([
11126
11143
  "address",
11127
11144
  "applet",
@@ -11236,7 +11253,6 @@ var SCOPE_LIST_ITEM = new Set([...DEFAULT_SCOPE_BOUNDARIES, "ol", "ul"]);
11236
11253
  var SCOPE_BUTTON = new Set([...DEFAULT_SCOPE_BOUNDARIES, "button"]);
11237
11254
  var SCOPE_DEFAULT = DEFAULT_SCOPE_BOUNDARIES;
11238
11255
  var SCOPE_TABLE = new Set(["html", "table", "template"]);
11239
- var SCOPE_SELECT = new Set;
11240
11256
  var STANDARD_SVG_CAMEL_ELEMENTS = new Set([
11241
11257
  "altGlyph",
11242
11258
  "altGlyphDef",
@@ -11388,7 +11404,6 @@ var FOREIGN_BREAKOUT_TAGS = new Set([
11388
11404
  "ul",
11389
11405
  "var"
11390
11406
  ]);
11391
- var MATHML_TEXT_INTEGRATION_POINTS = new Set(["mi", "mo", "mn", "ms", "mtext"]);
11392
11407
  var BLOCK_LEVEL_AUTO_CLOSE_P = new Set([
11393
11408
  "address",
11394
11409
  "article",
@@ -11431,7 +11446,6 @@ var BLOCK_LEVEL_AUTO_CLOSE_P = new Set([
11431
11446
  "dd",
11432
11447
  "dt"
11433
11448
  ]);
11434
- var SELECT_VALID_CHILDREN = new Set(["option", "optgroup", "hr", "script", "template"]);
11435
11449
  var SELECT_BREAKOUT_TAGS = new Set(["input", "keygen", "textarea", "select"]);
11436
11450
  var MODES = Object.freeze({
11437
11451
  inBody: "inBody",
@@ -13691,6 +13705,13 @@ function phaseOps(phase) {
13691
13705
  function resolveArgs(args, self) {
13692
13706
  return typeof args === "function" ? args(self) ?? [] : args ?? [];
13693
13707
  }
13708
+ function phaseHasBubble(phase) {
13709
+ if (!phase)
13710
+ return false;
13711
+ if (phase.bubble?.length)
13712
+ return true;
13713
+ return (phase.do ?? []).some((op) => op.type === "bubble");
13714
+ }
13694
13715
  function dispatchPhase(dispatcher, targetPath, phase, self) {
13695
13716
  if (!phase)
13696
13717
  return;
@@ -14627,6 +14648,8 @@ async function driveStack(stack, value, phase, opts = {}) {
14627
14648
  const t = info?.transaction;
14628
14649
  opts.onMessage({ kind: t?.handlerProp ?? "input", name: t?.name, args: t?.args, path: t?.path }, old, val);
14629
14650
  });
14651
+ if (phaseHasBubble(phase))
14652
+ console.warn("drive(): a `bubble` action is a no-op here — drive originates at the root and bubbles travel child→parent, so there is no ancestor to receive it (and the root's own bubble handler is skipped). To exercise a bubble handler, call it directly.");
14630
14653
  dispatchPhase(rootDispatcher(transactor), new Path([]), phase, value);
14631
14654
  await transactor.settle();
14632
14655
  return transactor.state.val;
@@ -15558,7 +15581,8 @@ class FieldSet extends Field {
15558
15581
  }
15559
15582
  function mkCompField(field, scope, args) {
15560
15583
  const Comp = scope?.lookupComponent(field.type) ?? null;
15561
- console.assert(!scope || Comp !== null, "component not found", { field });
15584
+ if (Comp === null)
15585
+ console.warn(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)`);
15562
15586
  return Comp?.make({ ...field.args, ...args }, { scope }) ?? null;
15563
15587
  }
15564
15588
 
@@ -15732,13 +15756,30 @@ function resolveAlter(Comp, name) {
15732
15756
  }
15733
15757
  return fn;
15734
15758
  }
15759
+ var seqGet = (seq, key) => Array.isArray(seq) ? seq[key] : seq.get ? seq.get(key) : seq[key];
15735
15760
  function collectIterBindings(Comp, compInstance, seq, opts = {}) {
15736
15761
  const whenFn = resolveAlter(Comp, opts.when) ?? filterAlwaysTrue;
15737
15762
  const loopWithFn = resolveAlter(Comp, opts.loopWith) ?? nullLoopWith;
15738
15763
  const enrichFn = resolveAlter(Comp, opts.enrichWith);
15764
+ const scopeEnrichFn = resolveAlter(Comp, opts.scopeEnrich);
15739
15765
  const it = compInstance;
15740
- const { iterData, start, end } = unpackLoopResult(loopWithFn.call(it, seq), seq);
15766
+ const scope = scopeEnrichFn ? scopeEnrichFn.call(it) ?? {} : opts.scope ?? {};
15767
+ const ctx = {
15768
+ lookup: (name) => scope[name],
15769
+ filter: (key, value, iterData2) => whenFn.call(it, key, value, iterData2)
15770
+ };
15771
+ const { iterData, start, end, keys } = unpackLoopResult(loopWithFn.call(it, seq, ctx), seq);
15741
15772
  const out = [];
15773
+ if (keys) {
15774
+ for (const key of keys) {
15775
+ const value = seqGet(seq, key);
15776
+ const binds = { key, value };
15777
+ if (enrichFn)
15778
+ enrichFn.call(it, binds, key, value, iterData);
15779
+ out.push(binds);
15780
+ }
15781
+ return out;
15782
+ }
15742
15783
  const iter = pickIter(seq);
15743
15784
  iter(seq, (key, value) => {
15744
15785
  if (!whenFn.call(it, key, value, iterData))
@@ -15927,20 +15968,23 @@ async function test3(opts = {}) {
15927
15968
  reportTestReportToConsole(report);
15928
15969
  return report;
15929
15970
  }
15971
+ function shadowCheckComponent(Comp) {
15972
+ const shadowViews = {};
15973
+ for (const name in Comp.views) {
15974
+ const rawView = Comp.views[name].rawView;
15975
+ const ctx = new LintParseContext;
15976
+ ANode.parse(rawView, ctx);
15977
+ ctx.compile(Comp.scope);
15978
+ shadowViews[name] = { name, ctx, rawView };
15979
+ }
15980
+ const shadowComp = Object.create(Comp);
15981
+ shadowComp.views = shadowViews;
15982
+ return checkComponent(shadowComp).reports;
15983
+ }
15930
15984
  function check(app) {
15931
15985
  const counts = { error: 0, warn: 0, hint: 0 };
15932
15986
  for (const Comp of app.comps.byId.values()) {
15933
- const shadowViews = {};
15934
- for (const name in Comp.views) {
15935
- const rawView = Comp.views[name].rawView;
15936
- const ctx = new LintParseContext;
15937
- ANode.parse(rawView, ctx);
15938
- ctx.compile(Comp.scope);
15939
- shadowViews[name] = { name, ctx, rawView };
15940
- }
15941
- const shadowComp = Object.create(Comp);
15942
- shadowComp.views = shadowViews;
15943
- const { reports } = checkComponent(shadowComp);
15987
+ const reports = shadowCheckComponent(Comp);
15944
15988
  if (reports.length === 0)
15945
15989
  continue;
15946
15990
  console.group(Comp.name);
@@ -15994,6 +16038,7 @@ export {
15994
16038
  tutuca,
15995
16039
  test3 as test,
15996
16040
  suggestionToMessage,
16041
+ shadowCheckComponent,
15997
16042
  setIn$1 as setIn,
15998
16043
  set2 as set,
15999
16044
  runTests,
@@ -16002,6 +16047,7 @@ export {
16002
16047
  removeIn,
16003
16048
  remove,
16004
16049
  phaseOps,
16050
+ phaseHasBubble,
16005
16051
  mergeWith$1 as mergeWith,
16006
16052
  mergeDeepWith$1 as mergeDeepWith,
16007
16053
  mergeDeep$1 as mergeDeep,
@@ -16037,6 +16083,7 @@ export {
16037
16083
  getComponentsDocs,
16038
16084
  get2 as get,
16039
16085
  fromJS,
16086
+ expect,
16040
16087
  drive,
16041
16088
  docComponents,
16042
16089
  dispatchPhase,