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/CHANGELOG.md CHANGED
@@ -2,6 +2,46 @@
2
2
 
3
3
  All notable changes to Sygnal are listed here. Versions follow [semantic versioning](https://semver.org). Releases before 5.4.0 are described in the [GitHub releases](https://github.com/tpresley/sygnal/releases) and tags.
4
4
 
5
+ ## 6.5.0 — 2026-10-14
6
+
7
+ State paths: a child's `state`, a Switchable's `state` and a Collection's `from` reach nested state (`state="settings.rules"`, `from="board.cards"`) without a hand-written lens. Additive, except that a `state` / `from` string with a `.` or `[` now means a path (SYG428 reports a state that still has a key with a dot in its name). The first full release published by the keyless release workflow.
8
+
9
+ **Measured impact.** Size: the kanban gate goes down, (a) 42,496 B with `nativeGlobalThis: false` (was 42,527 B; budget 42,700 B): the path cell adds about 107 B, and moving the string-`from` SYG401 checks out of the core saves more than that.
10
+
11
+ **Companion packages.**
12
+ - **`sygnal-check` 0.9.0:** SYG401 follows a `from` path through the literal `initialState`; rename, definition and references treat a path's first segment as a use of that state key. Its caret range doesn't reach 0.9.0 from `^0.8.0`, so update the dev dependency.
13
+ - **`create-sygnal-app` 2.7.0:** every template depends on `sygnal` ^6.5.0 and `sygnal-check` ^0.9.0.
14
+ - **VS Code extension 0.6.0:** bundles `sygnal-check` 0.9.0. The extension itself doesn't change.
15
+ - **Claude Code plugin 0.1.4:** the `sygnal-dev` skill describes state paths.
16
+
17
+ ### Added
18
+
19
+ - **State paths.** A child's `state`, a Switchable's `state` and a Collection's (and VirtualCollection's) `from` take a path into nested state: `<RulesPanel state="settings.rules" />`, `<BoardTitle state="boards[0].title" />`, `<Collection of={Card} from="board.cards" />`. Reads follow the path; a write copies only the objects and arrays on it, so untouched branches keep their identity, as a hand-written lens would (a missing level is created as an object when an `isolatedState` child first writes). A calculated first segment is read-only (SYG409), as a calculated key is. For list items, `byId('boards', id)` stays the way to follow an item rather than a position. Typed Collections accept dotted paths to nested arrays (`ArrayPathsOf<STATE>`, three levels). There is no array form (`state={['a', 'b']}`): an array `state` / `from` is still the data passed by mistake (SYG410 / SYG412).
20
+ - **New SYG428** (warn, dev diagnostics): a `state="a.b"` or `from="a.b"` whose owner's state has a key named `"a.b"` (see Changed).
21
+
22
+ ### Changed
23
+
24
+ - **A `state` / `from` string with a `.` or `[` is now a path.** Before, `state="a.b"` meant the key named `"a.b"`; now it means `state.a.b`. A state that still has a key with a dot in its name is reported as SYG428 in development; keep it with a lens (`state={{ get: (s) => s['a.b'], set: (s, v) => ({ ...s, 'a.b': v }) }}`) or rename the key.
25
+ - **SYG401 for a string `from` is reported by the development diagnostics only** (`sygnal/diagnostics`, which `sygnal/vite` loads in dev and `renderComponent` in tests): a `from` key or path that isn't in state, or isn't an array. Production builds no longer carry or print it (D22 had the core report it in every mode); the core still reports a lens getter that returns a non-array (SYG401) and an invalid `from` (SYG412). The kanban gate goes down 31 B (42,527 → 42,496 B) with state paths included.
26
+ - **`sygnal-check`: SYG401 follows a `from` path** through the literal `initialState` (a missing key along the way names the keys of that level; it stops where a value isn't a literal), and the editor features (rename, go to definition, references) treat a path's first segment as a use of that state key, so renaming `board` edits `from="board.cards"` to `from="deck.cards"`.
27
+
28
+ ### Fixed
29
+
30
+ - **State guide:** a child bound to a property that is `undefined` renders nothing until the property exists (only an `isolatedState` child renders and creates it); the guide said the property "gets added when the child first updates".
31
+
32
+ ## VS Code extension 0.5.1 — 2026-10-14
33
+
34
+ Bundles `sygnal-check` 0.8.1 (the SYG427 fixes above); the extension's own code doesn't change. The first extension release published by the keyless release workflow: the VS Code Marketplace through Microsoft Entra ID, Open VSX through trusted publishing.
35
+
36
+ ## sygnal-check 0.8.1 — 2026-10-14
37
+
38
+ A patch for SYG427 (new in 0.8.0), reported from a real project; `sygnal` itself is unchanged (6.4.0). Projects on `sygnal-check` ^0.8.0 get it on their next install. The first release published by the keyless release workflow (npm trusted publishing, with provenance).
39
+
40
+ ### Fixed
41
+
42
+ - **SYG427 is filed under the component that has the mistake.** It was labelled with the imported component (`RuleForm: RuleForm is imported from …`), which may not exist at all (the import is `undefined`), while every other finding in the file, and the runtime SYG427 for the same mistake, names the component whose view or intent uses it. It now names that component (`RulesPanel: …`), or the file outside any component; the imported name stays in the message and `data.name`.
43
+ - **SYG427's fix says how the module does export the component.** A named import of a module that only has a default export (`import { RuleForm } from './RuleForm.jsx'` for `export default RuleForm`) now gets `'./RuleForm.jsx' exports a default: import RuleForm from './RuleForm.jsx'`, and a default import of a named export the reverse, instead of "export it from …". The remaining case reads `export it from '…' with export function X, or fix the name`, without the parenthetical that nested inside the formatter's parentheses.
44
+
5
45
  ## 6.4.0 — 2026-10-14
6
46
 
7
47
  Fixes for issues an agent hit while building a real app on 6.3.0, and a step-by-step chat tutorial in the AI showcase. Additive: an `event()` payload function may now return `ABORT`, `makeServiceWorkerDriver` takes `enabled`, and a new diagnostic code (SYG427) reports a `CHILD.select()` of something that isn't a component. Dev-time checks get fewer false positives (SYG103, SYG223).
@@ -2893,8 +2893,9 @@ const keyOf = (it, i) => (isObj(it) && it.id != null ? '' + it.id : '\0' + i);
2893
2893
  *
2894
2894
  * It stands where the `<Collection>` marker was in its owner's template and renders the items
2895
2895
  * inside the owner's render: no stream of its own, no pickCombine.
2896
- * - `of`: a component function (D163: no names). `from`: a state key (SYG409 on a calculated
2897
- * one), a `{ get, set }` lens (SYG412 without get(); SYG401 for a non-array) or none (the
2896
+ * - `of`: a component function (D163: no names). `from`: a state key or path ('board.cards';
2897
+ * SYG409 on a calculated first segment; SYG401 when it isn't an array: the dev entry's), a
2898
+ * `{ get, set }` lens (SYG412 without get(); SYG401 for a non-array) or none (the
2898
2899
  * owner's state is the array).
2899
2900
  * - Items are keyed by `id`, an id-less item by its raw index (D169); one key -> index map per
2900
2901
  * array identity serves every item (cell.ts indexer). A duplicate key renders its first element