sygnal 6.4.0 → 6.5.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.
package/dist/index.cjs.js CHANGED
@@ -787,6 +787,8 @@ const DEV_CODE_SEVERITY = {
787
787
  SYG426: 'warn',
788
788
  // checks/next.ts: CHILD.select(undefined), usually a missing export
789
789
  SYG427: 'error',
790
+ // checks/next.ts: a path designator that 6.4 read as one key with a dot
791
+ SYG428: 'warn',
790
792
  // PLAN-9 (checks/next.ts): D470 key identity, two children with one identity
791
793
  SYG453: 'warn',
792
794
  SYG612: 'error',
@@ -1413,18 +1415,45 @@ function localCell(app, parent) {
1413
1415
  return { local: true, get: () => (own ? v : parent.get()), set: (n) => { v = n; own = true; app.commit(); } };
1414
1416
  }
1415
1417
  /**
1416
- * state="key". `owner`: the parent's name when `k` is one of its calculated fields (SYG409:
1417
- * writes ignored; `what` names the writer in the message). `dflt`: an isolated child's
1418
- * initialState, read while the slice is undefined. `has()`: the slice itself is defined (D174).
1418
+ * SPIKE (state paths): a state designator as segments. A plain key is one segment; 'a.b.0' and
1419
+ * 'a[0].b' are paths into nested objects and arrays. No array form: an array `from` / `state` is
1420
+ * the data passed by mistake (SYG410 / SYG412), and ['x', 'y'] would be ambiguous.
1421
+ */
1422
+ const pathOf$1 = (p) => p.replace(/\[(\d+)\]/g, '.$1').split('.');
1423
+ const getIn$1 = (o, ks) => { for (const k of ks) {
1424
+ if (o == null)
1425
+ return undefined;
1426
+ o = o[k];
1427
+ } return o; };
1428
+ /** `o` with the value at `ks` replaced; only the levels on the path are copied (a missing level becomes {}) */
1429
+ function setIn$1(o, ks, i, v) {
1430
+ if (i == ks.length)
1431
+ return v;
1432
+ const k = ks[i], cur = o?.[k], n = setIn$1(cur, ks, i + 1, v);
1433
+ if (n === cur && o != null)
1434
+ return o;
1435
+ if (Array.isArray(o)) {
1436
+ const c = o.slice();
1437
+ c[k] = n;
1438
+ return c;
1439
+ }
1440
+ return { ...o, [k]: n };
1441
+ }
1442
+ /**
1443
+ * state="key" (SPIKE: or a path, 'a.b' / 'a[0].b'). `owner`: the parent's name when the first
1444
+ * segment is one of its calculated fields (SYG409: writes ignored; `what` names the writer in
1445
+ * the message). `dflt`: an isolated child's initialState, read while the slice is undefined.
1446
+ * `has()`: the slice itself is defined (D174).
1419
1447
  */
1420
1448
  function keyCell(parent, k, owner, dflt, what = 'Sub-component') {
1449
+ const ks = pathOf$1(k);
1421
1450
  let lp = {}, lv;
1422
1451
  return {
1423
1452
  get() {
1424
1453
  const p = parent.get();
1425
1454
  if (p !== lp) {
1426
1455
  lp = p;
1427
- lv = p == null ? undefined : p[k];
1456
+ lv = getIn$1(p, ks);
1428
1457
  if (lv === undefined)
1429
1458
  lv = dflt;
1430
1459
  }
@@ -1432,12 +1461,12 @@ function keyCell(parent, k, owner, dflt, what = 'Sub-component') {
1432
1461
  },
1433
1462
  set(v) {
1434
1463
  if (owner)
1435
- return warn('SYG409', owner, `${what} tried to update calculated field '${k}'; ignored`, 'Bind it to a non-calculated field');
1464
+ return warn('SYG409', owner, `${what} tried to update calculated field '${ks[0]}'; ignored`, 'Bind it to a non-calculated field');
1436
1465
  const p = parent.get();
1437
- if (p?.[k] !== v)
1438
- parent.set({ ...p, [k]: v });
1466
+ if (getIn$1(p, ks) !== v)
1467
+ parent.set(setIn$1(p, ks, 0, v));
1439
1468
  },
1440
- has: () => parent.get()?.[k] !== undefined,
1469
+ has: () => getIn$1(parent.get(), ks) !== undefined,
1441
1470
  };
1442
1471
  }
1443
1472
  /**
@@ -2783,7 +2812,7 @@ class Inst {
2783
2812
  fail$2('SYG405', def.name, 'Sub-component initialState replaces the state its parent passes in', 'Remove initialState, or set isolatedState = true');
2784
2813
  }
2785
2814
  const dflt = def.isolated ? def.initialState : undefined;
2786
- const cell = typeof st == 'string' ? keyCell(this.cell, st, calcOf?.has(st) && this.def.name, dflt)
2815
+ const cell = typeof st == 'string' ? keyCell(this.cell, st, calcOf?.has(pathOf$1(st)[0]) && this.def.name, dflt)
2787
2816
  : st !== undefined ? lensCell(this.cell, st, this.def.name, (e) => app.appError(this, e, 'view'), dflt)
2788
2817
  : def.isolated ? localCell(app, this.cell) : this.cell;
2789
2818
  const scope = app.scope();
@@ -2865,8 +2894,9 @@ class Inst {
2865
2894
  *
2866
2895
  * It stands where the `<Collection>` marker was in its owner's template and renders the items
2867
2896
  * inside the owner's render: no stream of its own, no pickCombine.
2868
- * - `of`: a component function (D163: no names). `from`: a state key (SYG409 on a calculated
2869
- * one), a `{ get, set }` lens (SYG412 without get(); SYG401 for a non-array) or none (the
2897
+ * - `of`: a component function (D163: no names). `from`: a state key or path ('board.cards';
2898
+ * SYG409 on a calculated first segment; SYG401 when it isn't an array: the dev entry's), a
2899
+ * `{ get, set }` lens (SYG412 without get(); SYG401 for a non-array) or none (the
2870
2900
  * owner's state is the array).
2871
2901
  * - Items are keyed by `id`, an id-less item by its raw index (D169); one key -> index map per
2872
2902
  * array identity serves every item (cell.ts indexer). A duplicate key renders its first element
@@ -2948,16 +2978,9 @@ function arrayCell(owner, from) {
2948
2978
  set: (v) => oc.set(v),
2949
2979
  };
2950
2980
  }
2951
- if (typeof from == 'string') {
2952
- const cs = oc.get(), calc = owner.def.calcNames?.has(from);
2953
- if (isObj$2(cs) && !(from in cs) && !calc) {
2954
- const arrays = Object.keys(cs).filter(k => Array.isArray(cs[k]));
2955
- warn('SYG401', name, `Collection from="${from}" is not in state${arrays.length ? ` (array fields: '${arrays.join("', '")}')` : ''}; it renders nothing until it exists`, 'Set it to an array in initialState');
2956
- }
2957
- else if (isObj$2(cs) && !Array.isArray(cs[from]))
2958
- warn('SYG401', name, `Collection 'from' field '${from}' is not an array; it renders nothing`, 'Set it to an array in initialState');
2959
- return keyCell(oc, from, calc && name, undefined, 'Collection');
2960
- }
2981
+ // a key or a path ('board.cards'); SYG401 for one that isn't an array is the dev entry's (checks/collections.ts)
2982
+ if (typeof from == 'string')
2983
+ return keyCell(oc, from, owner.def.calcNames?.has(pathOf$1(from)[0]) && name, undefined, 'Collection');
2961
2984
  if (isObj$2(from) && typeof from.get == 'function') {
2962
2985
  let lp = {}, lv;
2963
2986
  return {
@@ -4166,7 +4189,7 @@ class SwitchableHost {
4166
4189
  this.lr = true;
4167
4190
  this.kids = [];
4168
4191
  check$3(owner, props);
4169
- const st = props.state, calc = typeof st == 'string' && owner.def.calcNames?.has(st);
4192
+ const st = props.state, calc = typeof st == 'string' && owner.def.calcNames?.has(pathOf$1(st)[0]);
4170
4193
  this.cell = typeof st == 'string' ? keyCell(owner.cell, st, calc && owner.def.name, undefined, 'Switchable sub-component')
4171
4194
  : st !== undefined ? lensCell(owner.cell, st, owner.def.name, (e) => owner.app.appError(owner, e, 'view'))
4172
4195
  : owner.cell;