sygnal 6.4.0 → 6.6.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.
Files changed (65) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/dist/astro/index.cjs.js +398 -25
  3. package/dist/astro/index.cjs.js.map +1 -1
  4. package/dist/astro/index.mjs +398 -25
  5. package/dist/astro/index.mjs.map +1 -1
  6. package/dist/astro/server.cjs.js +3 -2
  7. package/dist/astro/server.cjs.js.map +1 -1
  8. package/dist/astro/server.mjs +3 -2
  9. package/dist/astro/server.mjs.map +1 -1
  10. package/dist/devtools.cjs.js +141 -3
  11. package/dist/devtools.cjs.js.map +1 -1
  12. package/dist/devtools.esm.js +141 -4
  13. package/dist/devtools.esm.js.map +1 -1
  14. package/dist/diagnostics.cjs.js +140 -21
  15. package/dist/diagnostics.cjs.js.map +1 -1
  16. package/dist/diagnostics.esm.js +140 -21
  17. package/dist/diagnostics.esm.js.map +1 -1
  18. package/dist/index.cjs.js +54 -24
  19. package/dist/index.cjs.js.map +1 -1
  20. package/dist/index.d.ts +139 -16
  21. package/dist/index.esm.js +54 -24
  22. package/dist/index.esm.js.map +1 -1
  23. package/dist/sygnal.min.js +1 -1
  24. package/dist/sygnal.min.js.map +1 -1
  25. package/dist/vike/config/package.json +1 -1
  26. package/dist/vike/onRenderClient.cjs.js +63 -43
  27. package/dist/vike/onRenderClient.cjs.js.map +1 -1
  28. package/dist/vike/onRenderClient.mjs +63 -43
  29. package/dist/vike/onRenderClient.mjs.map +1 -1
  30. package/dist/vike/onRenderHtml.cjs.js +21 -25
  31. package/dist/vike/onRenderHtml.cjs.js.map +1 -1
  32. package/dist/vike/onRenderHtml.mjs +21 -25
  33. package/dist/vike/onRenderHtml.mjs.map +1 -1
  34. package/dist/vite/plugin.cjs.js +398 -25
  35. package/dist/vite/plugin.cjs.js.map +1 -1
  36. package/dist/vite/plugin.mjs +398 -25
  37. package/dist/vite/plugin.mjs.map +1 -1
  38. package/llms.txt +3 -3
  39. package/package.json +1 -1
  40. package/src/core/cell.ts +25 -7
  41. package/src/core/hooks.ts +6 -0
  42. package/src/core/hosts/collection.ts +6 -11
  43. package/src/core/hosts/switchable.ts +2 -2
  44. package/src/core/instance.ts +2 -2
  45. package/src/core/view.ts +2 -0
  46. package/src/cycle/dom/utils.ts +4 -2
  47. package/src/devtools.d.ts +13 -0
  48. package/src/devtools.ts +3 -0
  49. package/src/extra/devGraph.ts +111 -0
  50. package/src/extra/devMcp.ts +1 -1
  51. package/src/extra/devtools.ts +18 -0
  52. package/src/extra/diagnostics/checks/collections.ts +31 -25
  53. package/src/extra/diagnostics/checks/index.ts +1 -1
  54. package/src/extra/diagnostics/checks/inspect.ts +68 -6
  55. package/src/extra/diagnostics/checks/next.ts +22 -0
  56. package/src/extra/diagnostics/checks/public.d.ts +121 -12
  57. package/src/extra/diagnostics/codes.ts +10 -0
  58. package/src/index.d.ts +19 -3
  59. package/src/vike/onRenderClient.ts +44 -46
  60. package/src/vike/onRenderHtml.ts +5 -26
  61. package/src/vike/shell.ts +33 -0
  62. package/src/vite/graph.ts +247 -0
  63. package/src/vite/mcp.ts +3 -3
  64. package/src/vite/plugin.d.ts +12 -0
  65. package/src/vite/plugin.ts +136 -22
package/dist/index.cjs.js CHANGED
@@ -721,6 +721,9 @@ const DEV_CODE_SEVERITY = {
721
721
  SYG128: 'error',
722
722
  // PLAN-4 4-G2: static only (sygnal-check); listed so the entry knows its title
723
723
  SYG129: 'warn',
724
+ // PLAN-10 X-1: static only (sygnal-check)
725
+ SYG170: 'warn',
726
+ SYG171: 'warn',
724
727
  SYG221: 'error',
725
728
  // PLAN-4 GS-4 (state.ts)
726
729
  SYG222: 'warn',
@@ -787,6 +790,8 @@ const DEV_CODE_SEVERITY = {
787
790
  SYG426: 'warn',
788
791
  // checks/next.ts: CHILD.select(undefined), usually a missing export
789
792
  SYG427: 'error',
793
+ // checks/next.ts: a path designator that 6.4 read as one key with a dot
794
+ SYG428: 'warn',
790
795
  // PLAN-9 (checks/next.ts): D470 key identity, two children with one identity
791
796
  SYG453: 'warn',
792
797
  SYG612: 'error',
@@ -1413,18 +1418,45 @@ function localCell(app, parent) {
1413
1418
  return { local: true, get: () => (own ? v : parent.get()), set: (n) => { v = n; own = true; app.commit(); } };
1414
1419
  }
1415
1420
  /**
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).
1421
+ * SPIKE (state paths): a state designator as segments. A plain key is one segment; 'a.b.0' and
1422
+ * 'a[0].b' are paths into nested objects and arrays. No array form: an array `from` / `state` is
1423
+ * the data passed by mistake (SYG410 / SYG412), and ['x', 'y'] would be ambiguous.
1424
+ */
1425
+ const pathOf$1 = (p) => p.replace(/\[(\d+)\]/g, '.$1').split('.');
1426
+ const getIn$1 = (o, ks) => { for (const k of ks) {
1427
+ if (o == null)
1428
+ return undefined;
1429
+ o = o[k];
1430
+ } return o; };
1431
+ /** `o` with the value at `ks` replaced; only the levels on the path are copied (a missing level becomes {}) */
1432
+ function setIn$1(o, ks, i, v) {
1433
+ if (i == ks.length)
1434
+ return v;
1435
+ const k = ks[i], cur = o?.[k], n = setIn$1(cur, ks, i + 1, v);
1436
+ if (n === cur && o != null)
1437
+ return o;
1438
+ if (Array.isArray(o)) {
1439
+ const c = o.slice();
1440
+ c[k] = n;
1441
+ return c;
1442
+ }
1443
+ return { ...o, [k]: n };
1444
+ }
1445
+ /**
1446
+ * state="key" (SPIKE: or a path, 'a.b' / 'a[0].b'). `owner`: the parent's name when the first
1447
+ * segment is one of its calculated fields (SYG409: writes ignored; `what` names the writer in
1448
+ * the message). `dflt`: an isolated child's initialState, read while the slice is undefined.
1449
+ * `has()`: the slice itself is defined (D174).
1419
1450
  */
1420
1451
  function keyCell(parent, k, owner, dflt, what = 'Sub-component') {
1452
+ const ks = pathOf$1(k);
1421
1453
  let lp = {}, lv;
1422
1454
  return {
1423
1455
  get() {
1424
1456
  const p = parent.get();
1425
1457
  if (p !== lp) {
1426
1458
  lp = p;
1427
- lv = p == null ? undefined : p[k];
1459
+ lv = getIn$1(p, ks);
1428
1460
  if (lv === undefined)
1429
1461
  lv = dflt;
1430
1462
  }
@@ -1432,12 +1464,12 @@ function keyCell(parent, k, owner, dflt, what = 'Sub-component') {
1432
1464
  },
1433
1465
  set(v) {
1434
1466
  if (owner)
1435
- return warn('SYG409', owner, `${what} tried to update calculated field '${k}'; ignored`, 'Bind it to a non-calculated field');
1467
+ return warn('SYG409', owner, `${what} tried to update calculated field '${ks[0]}'; ignored`, 'Bind it to a non-calculated field');
1436
1468
  const p = parent.get();
1437
- if (p?.[k] !== v)
1438
- parent.set({ ...p, [k]: v });
1469
+ if (getIn$1(p, ks) !== v)
1470
+ parent.set(setIn$1(p, ks, 0, v));
1439
1471
  },
1440
- has: () => parent.get()?.[k] !== undefined,
1472
+ has: () => getIn$1(parent.get(), ks) !== undefined,
1441
1473
  };
1442
1474
  }
1443
1475
  /**
@@ -1672,6 +1704,8 @@ class View {
1672
1704
  get state() { return this.i.cell.get(); }
1673
1705
  get props() { return this.i.props; }
1674
1706
  get context() { return this.i.context(); }
1707
+ /** D530: the context keys the last render's view read (null: none rendered, or no context) */
1708
+ get reads() { return this.i.keys; }
1675
1709
  get isRoot() { return !this.i.parent; }
1676
1710
  get kind() { return this.i.kind; }
1677
1711
  /** false on a hidden Switchable page and below it */
@@ -2057,9 +2091,11 @@ function isEqualNamespace(a, b) {
2057
2091
  return true;
2058
2092
  }
2059
2093
  // G-261: a DOM change Sygnal makes outside a patch (a Transition's leave, a Portal mounted late)
2060
- // re-emits the DOM source of the app whose root contains `el` (makeDOMDriver listens on its root)
2094
+ // re-emits the DOM source of the app whose root contains `el` (makeDOMDriver listens on its root).
2095
+ // The event comes from the element's own window: jsdom refuses an `Event` from another realm (a
2096
+ // Transition's leave timer that fires after a jsdom test environment was torn down)
2061
2097
  const POKE = 'sygnal-dom';
2062
- const pokeDOM = (el) => el?.dispatchEvent(new Event(POKE, { bubbles: true }));
2098
+ const pokeDOM = (el) => el?.dispatchEvent(new (el.ownerDocument?.defaultView?.Event || Event)(POKE, { bubbles: true }));
2063
2099
  const obj = (o) => o !== null && typeof o == 'object' && !Array.isArray(o);
2064
2100
  /**
2065
2101
  * P46-P: two vnodes' data are the same for the DOM modules: the same keys, each value identical
@@ -2783,7 +2819,7 @@ class Inst {
2783
2819
  fail$2('SYG405', def.name, 'Sub-component initialState replaces the state its parent passes in', 'Remove initialState, or set isolatedState = true');
2784
2820
  }
2785
2821
  const dflt = def.isolated ? def.initialState : undefined;
2786
- const cell = typeof st == 'string' ? keyCell(this.cell, st, calcOf?.has(st) && this.def.name, dflt)
2822
+ const cell = typeof st == 'string' ? keyCell(this.cell, st, calcOf?.has(pathOf$1(st)[0]) && this.def.name, dflt)
2787
2823
  : st !== undefined ? lensCell(this.cell, st, this.def.name, (e) => app.appError(this, e, 'view'), dflt)
2788
2824
  : def.isolated ? localCell(app, this.cell) : this.cell;
2789
2825
  const scope = app.scope();
@@ -2865,8 +2901,9 @@ class Inst {
2865
2901
  *
2866
2902
  * It stands where the `<Collection>` marker was in its owner's template and renders the items
2867
2903
  * 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
2904
+ * - `of`: a component function (D163: no names). `from`: a state key or path ('board.cards';
2905
+ * SYG409 on a calculated first segment; SYG401 when it isn't an array: the dev entry's), a
2906
+ * `{ get, set }` lens (SYG412 without get(); SYG401 for a non-array) or none (the
2870
2907
  * owner's state is the array).
2871
2908
  * - Items are keyed by `id`, an id-less item by its raw index (D169); one key -> index map per
2872
2909
  * array identity serves every item (cell.ts indexer). A duplicate key renders its first element
@@ -2948,16 +2985,9 @@ function arrayCell(owner, from) {
2948
2985
  set: (v) => oc.set(v),
2949
2986
  };
2950
2987
  }
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
- }
2988
+ // a key or a path ('board.cards'); SYG401 for one that isn't an array is the dev entry's (checks/collections.ts)
2989
+ if (typeof from == 'string')
2990
+ return keyCell(oc, from, owner.def.calcNames?.has(pathOf$1(from)[0]) && name, undefined, 'Collection');
2961
2991
  if (isObj$2(from) && typeof from.get == 'function') {
2962
2992
  let lp = {}, lv;
2963
2993
  return {
@@ -4166,7 +4196,7 @@ class SwitchableHost {
4166
4196
  this.lr = true;
4167
4197
  this.kids = [];
4168
4198
  check$3(owner, props);
4169
- const st = props.state, calc = typeof st == 'string' && owner.def.calcNames?.has(st);
4199
+ const st = props.state, calc = typeof st == 'string' && owner.def.calcNames?.has(pathOf$1(st)[0]);
4170
4200
  this.cell = typeof st == 'string' ? keyCell(owner.cell, st, calc && owner.def.name, undefined, 'Switchable sub-component')
4171
4201
  : st !== undefined ? lensCell(owner.cell, st, owner.def.name, (e) => owner.app.appError(owner, e, 'view'))
4172
4202
  : owner.cell;