@kudzujs/core 0.8.19 → 0.8.21
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/MIGRATION_ROADMAP.md +7 -0
- package/PERFORMANCE.md +66 -0
- package/README.md +1 -1
- package/RELEASES.md +67 -0
- package/docs/next-architecture/README.md +1 -1
- package/docs/next-architecture/compiler-current-architecture.md +6 -5
- package/docs/next-architecture/goal-a-compiler-foundation.md +5 -5
- package/docs/next-architecture/versioning.md +1 -1
- package/framework/README.md +4 -3
- package/framework/build.mjs +176 -160
- package/framework/compiler/descriptor-session.mjs +33 -16
- package/framework/compiler/effect-analysis.mjs +89 -0
- package/framework/compiler/ir/module-ir.mjs +13 -1
- package/framework/compiler/worker-compiler.mjs +12 -6
- package/framework/core.d.ts +67 -2
- package/package.json +1 -1
package/MIGRATION_ROADMAP.md
CHANGED
|
@@ -216,6 +216,13 @@ This queue orders the next investigations by general migration value. Start only
|
|
|
216
216
|
- Existing tagged collection expressions and selectors are canonical DerivedIR for rendered lists and derived effect dependencies; transformed source embeds the registered records rather than parallel analyzer values.
|
|
217
217
|
- AST, `Map`, and `Set` callback descriptors remain private only until source-local lowering completes. Handler codegen now performs no TypeScript traversal or state/capture/reducer/import discovery, while command-only routes retain zero handler ESM.
|
|
218
218
|
|
|
219
|
+
### Completed In 0.8.20
|
|
220
|
+
|
|
221
|
+
- Every rendered keyed collection now finalizes into JSON-safe KeyedBlockIR with deterministic slots, explicit parent/child links, collection and selector ownership, key/index policy, source provenance, and complete component-specialization membership.
|
|
222
|
+
- Keyed row states and refs retain their declaration source and specialization owner. Command, native, effect, list-expression, list-conditional, and calculated-collection records link back to their owning keyed block.
|
|
223
|
+
- Previous transformer-wide keyed value, condition, event, nested-list, effect, and rendered-list AST side tables were removed. AST remains private only inside immediate source-local validation and lowering.
|
|
224
|
+
- `core.mjs` remains authoritative for final list IDs, key paths, route descriptors, complete HTML, DOM identity, and exact state/effect/ref release; accepted syntax and browser output are unchanged.
|
|
225
|
+
|
|
219
226
|
## Cross-Cutting Performance Gates
|
|
220
227
|
|
|
221
228
|
Every migration feature must preserve:
|
package/PERFORMANCE.md
CHANGED
|
@@ -1,5 +1,71 @@
|
|
|
1
1
|
# Performance Records
|
|
2
2
|
|
|
3
|
+
## 0.8.21 Explicit Effect Ownership
|
|
4
|
+
|
|
5
|
+
Measured UTC 2026-08-09 on Apple M3, 8 logical CPUs, 8 GiB RAM, macOS 26.5.2 / Darwin 25.5.0, Node 25.6.1, and npm 11.18.0. Baseline tag `v0.8.20` at `7fb6e37` and the current `0.8.21` compiler candidate used the same local volume and identical installed dependencies.
|
|
6
|
+
|
|
7
|
+
The candidate implementation patch over `v0.8.20` had SHA-256 `ac0b1921bbbfb72f45d9b53338bec96bf9ab3d1680446148dfd8548b871bcbe4`, produced by:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
git diff --binary v0.8.20 -- framework/build.mjs framework/compiler/descriptor-session.mjs framework/compiler/effect-analysis.mjs framework/compiler/ir/module-ir.mjs framework/compiler/worker-compiler.mjs framework/core.d.ts | shasum -a 256
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Both targets received one warm-up followed by seven clean `worker-effects` production builds in alternating round-robin order. Cleanup remained outside timing. The distributions overlap; the 1.02% lower candidate median does not establish a material change.
|
|
14
|
+
|
|
15
|
+
| Target | Build median | Worker raw / gzip | Window raw / gzip |
|
|
16
|
+
|---|---:|---:|---:|
|
|
17
|
+
| 0.8.20 baseline | 255.6 ms | 907 B / 475 B | 12,148 B / 5,427 B |
|
|
18
|
+
| 0.8.21 candidate | 253.0 ms | 907 B / 475 B | 12,148 B / 5,427 B |
|
|
19
|
+
|
|
20
|
+
```text
|
|
21
|
+
0.8.20: [253.2,263.4,276.5,255.6,251.3,252.1,266.1]
|
|
22
|
+
0.8.21: [253.7,249.7,260.4,253.0,251.1,250.1,265.7]
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The complete site `dist` and the `effect-dependencies`, `keyed-effects`, and `worker-effects` fixture output trees had identical file lists and bytes before release-content updates. The Worker graph and every window graph file were byte-identical, including the content-hashed Worker name. This measurement covers compiler clean-build startup and generated artifact size; lifecycle behavior remains covered by the complete effect, Worker, conditional, keyed, and navigation integration tests.
|
|
26
|
+
|
|
27
|
+
## 0.8.20 Explicit Keyed Ownership
|
|
28
|
+
|
|
29
|
+
Measured UTC 2026-08-09 on Apple M3, 8 logical CPUs, 8 GiB RAM, macOS 26.5.2 / Darwin 25.5.0, Node 25.6.1, and npm 11.18.0. Baseline `0.8.19` commit `c516173` and the current `0.8.20` compiler candidate used the same local volume and identical installed dependencies.
|
|
30
|
+
|
|
31
|
+
The candidate implementation patch over `c516173` had SHA-256 `137f68090f6024374077f46cb61767f48dff27a193d33c9e92409b8dd7bb7d21`, produced by:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
git diff --binary c516173 -- framework/build.mjs framework/compiler/descriptor-session.mjs framework/compiler/ir/module-ir.mjs framework/core.d.ts | shasum -a 256
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Both targets received one warm-up followed by 21 clean `keyed-row-hooks` production builds in round-robin alternating order. Cleanup remained outside timing. The distributions overlap; the candidate median was 0.52% lower and does not establish a material change.
|
|
38
|
+
|
|
39
|
+
| Target | Build median | List runtime raw / gzip |
|
|
40
|
+
|---|---:|---:|
|
|
41
|
+
| 0.8.19 baseline | 266.8 ms | 21,831 B / 6,930 B |
|
|
42
|
+
| 0.8.20 candidate | 265.4 ms | 21,831 B / 6,930 B |
|
|
43
|
+
|
|
44
|
+
```text
|
|
45
|
+
0.8.19: [272.5,269.7,262.6,267.3,262.9,265.2,268.0,264.7,262.0,268.3,267.1,262.5,263.7,266.8,263.2,267.5,263.3,268.8,266.7,266.9,271.4]
|
|
46
|
+
0.8.20: [262.5,267.4,266.2,261.7,265.1,262.9,269.9,264.1,275.0,268.2,263.4,263.7,265.4,268.7,263.8,266.1,265.4,265.3,267.2,270.1,263.2]
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The recorded cleanup, warm-up, timing, median, and runtime-size measurement is reproducible with:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
BASELINE_ROOT="/var/folders/bt/3r_ntp5x65j81brs6_p93rl00000gn/T/opencode/kudzu-0820-baseline" CANDIDATE_ROOT="/Users/songchibong/Documents/GitHub/kudzu" node --input-type=module -e 'import { spawnSync } from "node:child_process"; import { rmSync,readFileSync } from "node:fs"; import { gzipSync } from "node:zlib"; import { performance } from "node:perf_hooks"; import { resolve } from "node:path"; const roots={baseline:process.env.BASELINE_ROOT,candidate:process.env.CANDIDATE_ROOT}; const runs={baseline:[],candidate:[]}; const fixture="keyed-row-hooks"; const build=name=>{const root=roots[name],cwd=resolve(root,"test/fixtures",fixture); rmSync(resolve(cwd,"dist"),{recursive:true,force:true}); rmSync(resolve(cwd,".kudzu"),{recursive:true,force:true}); const start=performance.now(); const result=spawnSync(process.execPath,[resolve(root,"bin/kudzu.mjs"),"build"],{cwd,encoding:"utf8"}); if(result.status) throw new Error(result.stderr||result.stdout); return Number((performance.now()-start).toFixed(1));}; build("baseline"); build("candidate"); for(let index=0;index<21;index++) for(const name of index%2?["candidate","baseline"]:["baseline","candidate"]) runs[name].push(build(name)); const median=values=>[...values].sort((a,b)=>a-b)[Math.floor(values.length/2)]; const sizes={}; for(const [name,root] of Object.entries(roots)){const file=readFileSync(resolve(root,"test/fixtures",fixture,"dist/assets/kudzu-list.js")); sizes[name]=[file.length,gzipSync(file).length];} console.log(JSON.stringify({runs,medians:{baseline:median(runs.baseline),candidate:median(runs.candidate)},sizes}));'
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Before release-content updates, the complete site `dist` was byte-identical. Seven representative keyed fixtures retained identical file lists and SHA-256 content; `.kudzu` comparison replaced only each worktree's absolute root in existing source-location strings. The complete compared lists were:
|
|
56
|
+
|
|
57
|
+
```text
|
|
58
|
+
lists: dist/assets/handlers/pages/index.js, dist/assets/kudzu-list.js, dist/assets/kudzu-native.js, dist/assets/kudzu-serialization.js, dist/assets/kudzu-style.js, dist/assets/kudzu.js, dist/assets/native/index.js, dist/index.html, .kudzu/kudzu-plan.json, .kudzu/pages/index.mjs
|
|
59
|
+
nested-lists: dist/assets/effects/index.js, dist/assets/handlers/pages/index.js, dist/assets/kudzu-effect.js, dist/assets/kudzu-list.js, dist/assets/kudzu-native.js, dist/assets/kudzu-serialization.js, dist/assets/kudzu.js, dist/assets/native/index.js, dist/index.html, .kudzu/kudzu-plan.json, .kudzu/pages/index.mjs
|
|
60
|
+
keyed-row-hooks: dist/assets/effects/index.js, dist/assets/handlers/pages/index.js, dist/assets/kudzu-binding.js, dist/assets/kudzu-effect.js, dist/assets/kudzu-list.js, dist/assets/kudzu-native.js, dist/assets/kudzu-serialization.js, dist/assets/kudzu-style.js, dist/assets/kudzu.js, dist/assets/native/index.js, dist/index.html, .kudzu/HookRow.mjs, .kudzu/kudzu-plan.json, .kudzu/pages/index.mjs
|
|
61
|
+
svg-structures: dist/assets/handlers/pages/index.js, dist/assets/kudzu-binding.js, dist/assets/kudzu-list.js, dist/assets/kudzu-native.js, dist/assets/kudzu-serialization.js, dist/assets/kudzu-style.js, dist/assets/kudzu.js, dist/assets/native/index.js, dist/index.html, .kudzu/kudzu-plan.json, .kudzu/pages/index.mjs
|
|
62
|
+
calculated-collections: dist/assets/handlers/pages/index.js, dist/assets/handlers/pages/ordinary.js, dist/assets/kudzu-binding.js, dist/assets/kudzu-list.js, dist/assets/kudzu-native.js, dist/assets/kudzu-serialization.js, dist/assets/kudzu-style.js, dist/assets/kudzu.js, dist/assets/native/index.js, dist/assets/native/ordinary/index.js, dist/index.html, dist/ordinary/index.html, dist/static/index.html, .kudzu/calculate.mjs, .kudzu/kudzu-plan.json, .kudzu/pages/index.mjs, .kudzu/pages/ordinary.mjs, .kudzu/pages/static.mjs
|
|
63
|
+
rendered-collections: dist/assets/handlers/pages/index.js, dist/assets/kudzu-list.js, dist/assets/kudzu-native.js, dist/assets/kudzu-serialization.js, dist/assets/kudzu.js, dist/assets/native/index.js, dist/index.html, .kudzu/kudzu-plan.json, .kudzu/pages/index.mjs, .kudzu/selectVisible.mjs
|
|
64
|
+
keyed-effects: dist/assets/effects/index.js, dist/assets/effects/item-only/index.js, dist/assets/effects/state-only/index.js, dist/assets/handlers/pages/index.js, dist/assets/handlers/pages/item-only.js, dist/assets/handlers/pages/state-only.js, dist/assets/kudzu-binding.js, dist/assets/kudzu-effect.js, dist/assets/kudzu-list.js, dist/assets/kudzu-native.js, dist/assets/kudzu-serialization.js, dist/assets/kudzu-style.js, dist/assets/kudzu.js, dist/assets/native/index.js, dist/index.html, dist/item-only/index.html, dist/state-only/index.html, .kudzu/EffectRow.mjs, .kudzu/kudzu-plan.json, .kudzu/pages/index.mjs, .kudzu/pages/item-only.mjs, .kudzu/pages/state-only.mjs
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
This measurement covers compiler clean-build startup and generated list-runtime size, not browser reconciliation latency. Browser behavior remains covered by the existing insert/update/reorder/remove/nested/SVG/state/effect/ref integration checks.
|
|
68
|
+
|
|
3
69
|
## 0.8.19 Handler, Binding, And Derived IR
|
|
4
70
|
|
|
5
71
|
Measured UTC 2026-08-08 on Apple M3, 8 logical CPUs, 8 GiB RAM, macOS 26.5.2 / Darwin 25.5.0, Node 25.6.1, and npm 11.18.0. Baseline `0.8.18` tag `3598be0` and the `0.8.19` compiler-only candidate used detached worktrees on the same temporary volume with identical installed dependencies.
|
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ Kudzu compiles ordinary React-shaped TypeScript and TSX into complete static HTM
|
|
|
14
14
|
|
|
15
15
|
> Experimental `0.8.x`: the compiler API and supported TSX surface may change.
|
|
16
16
|
|
|
17
|
-
**Latest release: 0.8.
|
|
17
|
+
**Latest release: 0.8.21 - Explicit effect ownership.** Effects now retain deterministic JSON-safe setup, cleanup, dependency, component/keyed ownership, source, and Worker-edge records while final route lifecycle allocation remains unchanged. Read the [release notes](./RELEASES.md#0821---explicit-effect-ownership), open the [release page](https://kudzujs.cloud/releases/0.8.21), or follow the [next architecture packet](./docs/next-architecture/README.md).
|
|
18
18
|
|
|
19
19
|
- [Documentation](https://kudzujs.cloud/docs)
|
|
20
20
|
- [Installation guide](https://kudzujs.cloud/docs#install)
|
package/RELEASES.md
CHANGED
|
@@ -1,5 +1,72 @@
|
|
|
1
1
|
# Kudzu Releases
|
|
2
2
|
|
|
3
|
+
## 0.8.21 - Explicit effect ownership
|
|
4
|
+
|
|
5
|
+
Kudzu 0.8.21 completes the next Goal A source-analysis seam: every supported effect now registers deterministic JSON-safe setup, cleanup, dependency, ownership, source, and Worker-edge data before existing build-time rendering allocates concrete lifecycle IDs.
|
|
6
|
+
|
|
7
|
+
### Changed in 0.8.21
|
|
8
|
+
|
|
9
|
+
- EffectIR links setup to finalized HandlerIR and records cleanup, ordered signal and DerivedIR dependencies, subscriptions, dependency state snapshots, and keyed-item fields.
|
|
10
|
+
- Component and keyed ownership retain lexical component provenance and KeyedBlockIR slots, including specialized imported rows.
|
|
11
|
+
- Relative TypeScript Worker rewriting returns functional callback and edge results; rendered Worker emission derives only from EffectIR rather than a build-wide mutable reference array.
|
|
12
|
+
- Transformed effect calls consume the registered EffectIR dependency and ownership record before final setup HandlerIR slot resolution.
|
|
13
|
+
- Effect dependency classification and cleanup-owned browser resource validation moved to `compiler/effect-analysis.mjs`; transformer-wide component and keyed effect AST side tables were removed.
|
|
14
|
+
- Mixed direct and derived dependencies create DerivedIR only for derived expressions while preserving authored dependency order.
|
|
15
|
+
|
|
16
|
+
### Goal A boundary
|
|
17
|
+
|
|
18
|
+
- `core.mjs` and the existing route plan remain authoritative for concrete route/layout/conditional/keyed effect IDs, mounting, stale-write invalidation, and cleanup order; ModuleIR does not duplicate RouteIR.
|
|
19
|
+
- EffectIR owns source-analysis facts and Worker graph edges. Route-specific effect codegen continues to consume rendered descriptors without rediscovering TSX semantics.
|
|
20
|
+
- No accepted syntax, public API, browser capability, VDOM, hydration, component rerender, or retained browser component tree was added.
|
|
21
|
+
- Goal A continues with the `0.8.22` RouteIR, CapabilityIR, numeric-slot, and final architecture/output audit.
|
|
22
|
+
|
|
23
|
+
### Validation
|
|
24
|
+
|
|
25
|
+
- The complete suite passes 170/170 tests, including EffectIR JSON round-trip, mixed dependencies, imported keyed provenance, Worker rendered exclusion and `about:blank` replacement, conditional/navigation ownership, stale-write isolation, and cleanup.
|
|
26
|
+
- `npm run check`, focused Node 22 compiler tests, and a Node 22 complete-site build pass.
|
|
27
|
+
- Before release-content updates, the complete 135-page site plus `effect-dependencies`, `keyed-effects`, and `worker-effects` output trees were byte-identical to `v0.8.20`.
|
|
28
|
+
- Worker and window graph files remain byte-identical. Seven interleaved clean builds measured a 253.0 ms candidate median against 255.6 ms for `v0.8.20`; raw arrays and provenance are recorded in `PERFORMANCE.md`.
|
|
29
|
+
- A release-blocking architecture audit found no implementation or runtime-correctness blockers.
|
|
30
|
+
- `create-kudzu` remains 0.1.101 because its unchanged template already accepts `@kudzujs/core@^0.8.15`.
|
|
31
|
+
|
|
32
|
+
### Upgrade
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm install @kudzujs/core@^0.8.21
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## 0.8.20 - Explicit keyed ownership
|
|
39
|
+
|
|
40
|
+
Kudzu 0.8.20 completes the next Goal A source-analysis boundary: keyed collection sites now finalize into deterministic JSON-safe ownership records before the existing build-time renderer allocates DOM identity and lifecycle state.
|
|
41
|
+
|
|
42
|
+
### Changed in 0.8.20
|
|
43
|
+
|
|
44
|
+
- KeyedBlockIR records parent/child slots, collection signal or calculated binding, key/index policy, owner field, selector reference and states, source provenance, and static status.
|
|
45
|
+
- Recursive same-file and imported row expansion records every component-specialization slot, including stateless intermediate components.
|
|
46
|
+
- Row states and refs retain their specialization owner and declaration source.
|
|
47
|
+
- Command, native, effect, list-expression, list-conditional, and calculated-collection HandlerIR/BindingIR records link to their owning keyed block.
|
|
48
|
+
- Transformer-wide keyed value, condition, event, nested-list, effect, rendered-list, and alias AST side tables were removed; temporary AST stays inside immediate source-local validation and lowering.
|
|
49
|
+
- The existing route list descriptor now has an explicit TypeScript shape without changing its serialized data.
|
|
50
|
+
|
|
51
|
+
### Goal A boundary
|
|
52
|
+
|
|
53
|
+
- `core.mjs` remains authoritative for final list IDs, row key paths, route descriptors, complete HTML, SVG context, state/ref/effect allocation, and exact release.
|
|
54
|
+
- Effect setup, cleanup, dependency, Worker, and lifetime ownership remains on the existing path until EffectIR in `0.8.21`.
|
|
55
|
+
- No accepted syntax, public API, browser capability, VDOM, hydration, component rerender, or retained browser component tree was added.
|
|
56
|
+
|
|
57
|
+
### Validation
|
|
58
|
+
|
|
59
|
+
- The complete suite passes 168/168 tests, including deterministic KeyedBlockIR JSON round-trip and calculated, nested, recursive-component, selector, state, ref, handler, binding, effect, and SVG ownership.
|
|
60
|
+
- Before release-content updates, the complete site `dist` and seven representative keyed fixture output trees matched `v0.8.19`; detached-worktree roots were normalized only in existing `.kudzu` source strings.
|
|
61
|
+
- The keyed list runtime remains byte-identical at 21,831 B raw / 6,930 B gzip. A same-volume 21-run interleaved comparison measured a 0.52% lower candidate median; raw arrays and provenance are recorded in `PERFORMANCE.md`.
|
|
62
|
+
- `create-kudzu` remains 0.1.101 because its unchanged template already accepts `@kudzujs/core@^0.8.15`.
|
|
63
|
+
|
|
64
|
+
### Upgrade
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
npm install @kudzujs/core@^0.8.20
|
|
68
|
+
```
|
|
69
|
+
|
|
3
70
|
## 0.8.19 - Handler, binding, and derived IR
|
|
4
71
|
|
|
5
72
|
Kudzu 0.8.19 completes the next Goal A source-analysis boundary: native callbacks, reactive bindings, list evaluators, imports, and pure derived expressions now finalize into JSON-safe ModuleIR before mechanical artifact codegen.
|
|
@@ -6,7 +6,7 @@ The top-level [`GOAL_A.md`](../../GOAL_A.md) and [`GOAL_B.md`](../../GOAL_B.md)
|
|
|
6
6
|
|
|
7
7
|
| Goal | Decision | Start condition |
|
|
8
8
|
|---|---|---|
|
|
9
|
-
| A: compiler foundation | `0.8.
|
|
9
|
+
| A: compiler foundation | `0.8.21` EffectIR source-analysis seam complete | Continue with `0.8.22` RouteIR, CapabilityIR, and the architecture/output audit after the release boundary. |
|
|
10
10
|
| B: optimization benchmarks | Deferred | Goal A complete and its output baseline recorded |
|
|
11
11
|
| C: state/resource model | Research only | Reduced fixtures expose a limitation |
|
|
12
12
|
| D: routing compatibility | Current behavior preserved | Revisit only with migration evidence and invariant review |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Current Compiler Architecture
|
|
2
2
|
|
|
3
|
-
This maps the
|
|
3
|
+
This maps the EffectIR boundary prepared for `0.8.21`. File and function names are the stable references; line numbers are intentionally omitted because Goal A moves code.
|
|
4
4
|
|
|
5
5
|
## Responsibility Map
|
|
6
6
|
|
|
@@ -13,14 +13,15 @@ This maps the completed `0.8.19` handler, binding, and derived IR boundary. File
|
|
|
13
13
|
| Focused normalization passes | [`framework/compiler/`](../../framework/compiler/) | React, Router, browser signals, animation-frame refs, custom-hook timers, Zustand, and render control each validate and lower a narrow source shape. |
|
|
14
14
|
| Shared AST/scope helpers | [`framework/compiler/ast-helpers.mjs`](../../framework/compiler/ast-helpers.mjs) | Binding, scope, reference, effect-return, and source-location analysis. |
|
|
15
15
|
| Pure collection language | [`framework/compiler/collection-analysis.mjs`](../../framework/compiler/collection-analysis.mjs) | Analyzes collection roots/selectors and serializes the allowed pure expression language used by lists and derived dependencies. |
|
|
16
|
-
| Main semantic analysis | `framework/build.mjs`, `createKudzuTransformer()` | Produces transformed source plus explicit component, handler, binding,
|
|
16
|
+
| Main semantic analysis | `framework/build.mjs`, `createKudzuTransformer()` | Produces transformed source plus explicit component, handler, binding, derived, keyed, and effect ownership results. |
|
|
17
17
|
| Component ownership analysis | [`framework/compiler/analysis/component-analysis.mjs`](../../framework/compiler/analysis/component-analysis.mjs) | Retains ordered JSON-safe owner and specialization records for state, setters, props, refs, IDs, direct signal links, and source provenance; AST identity remains private to its source-local session. |
|
|
18
|
-
| Per-source descriptor registration | [`framework/compiler/descriptor-session.mjs`](../../framework/compiler/descriptor-session.mjs), `createSemanticArtifact()`, `createDescriptorSession()` | Keeps AST descriptors private during analysis, then finalizes deterministic JSON-safe HandlerIR, BindingIR, DerivedIR, imports, and client roots into ModuleIR. |
|
|
18
|
+
| Per-source descriptor registration | [`framework/compiler/descriptor-session.mjs`](../../framework/compiler/descriptor-session.mjs), `createSemanticArtifact()`, `createDescriptorSession()` | Keeps AST descriptors private during analysis, then finalizes deterministic JSON-safe HandlerIR, BindingIR, DerivedIR, KeyedBlockIR, EffectIR, imports, and client roots into ModuleIR. |
|
|
19
19
|
| Command IR and codegen | [`framework/compiler/optimize/command-specialization.mjs`](../../framework/compiler/optimize/command-specialization.mjs), [`framework/compiler/ir/module-ir.mjs`](../../framework/compiler/ir/module-ir.mjs), [`framework/compiler/codegen/command-codegen.mjs`](../../framework/compiler/codegen/command-codegen.mjs) | Supported command handlers specialize to JSON-safe ModuleIR, then emit the existing `__kBehavior` AST without changing route plans. |
|
|
20
20
|
| Build module generation | `framework/build.mjs`, `compile()` | Runs TypeScript with the Kudzu transformer, writes build-executable modules to `.kudzu`, rejects surviving React/Router runtime references, and generates handler source when descriptors exist. |
|
|
21
21
|
| Handler/evaluator lowering | [`framework/compiler/handler-lowering.mjs`](../../framework/compiler/handler-lowering.mjs) | Completes source-local callback/binding/list AST rewriting and diagnostics before the JSON-safe IR boundary. |
|
|
22
22
|
| Handler module codegen | [`framework/compiler/handler-codegen.mjs`](../../framework/compiler/handler-codegen.mjs) | Renders finalized ordered imports and concatenates generated module-export source without TypeScript AST or semantic discovery. |
|
|
23
|
-
|
|
|
23
|
+
| Effect analysis | [`framework/compiler/effect-analysis.mjs`](../../framework/compiler/effect-analysis.mjs) | Classifies ordered signal, derived, and keyed-item dependencies and validates cleanup-owned browser resources before EffectIR registration. |
|
|
24
|
+
| Worker graph | [`framework/compiler/worker-compiler.mjs`](../../framework/compiler/worker-compiler.mjs) | Returns functional Worker rewrite results and JSON-safe EffectIR edges, validates relative graphs, emits content-hashed ESM, and resolves placeholders only for rendered effects. |
|
|
24
25
|
| Build-time JSX execution | [`framework/core.mjs`](../../framework/core.mjs), `renderPage()` | Executes compiled pages/layouts, allocates deterministic route/layout ownership IDs, emits complete HTML, and returns the serializable route plan and capability booleans. |
|
|
25
26
|
| Route capability projection | [`framework/compiler/route-capability-planner.mjs`](../../framework/compiler/route-capability-planner.mjs), `planRouteCapabilities()` | Purely folds rendered route plans and route facts into aggregate runtime/artifact requirements. |
|
|
26
27
|
| Effect entry generation | [`framework/compiler/effect-codegen.mjs`](../../framework/compiler/effect-codegen.mjs) | Generates ordinary, dependency, owned, and navigable effect entries from rendered descriptors. |
|
|
@@ -58,7 +59,7 @@ The browser consumes static HTML first. State seeds and descriptors in that HTML
|
|
|
58
59
|
## Current Coupling To Remove
|
|
59
60
|
|
|
60
61
|
- `createKudzuTransformer()` combines discovery, validation, specialization, descriptor registration, and transformed-source emission.
|
|
61
|
-
-
|
|
62
|
+
- Transient component rewrite indexes remain source-local AST indexes; handler, binding, derived, keyed, effect, and component ownership now have explicit JSON-safe source results.
|
|
62
63
|
- `build()` destructures a broad capability manifest into many booleans and performs artifact-specific source surgery.
|
|
63
64
|
- Runtime specialization relies on exact source-string and regular-expression replacements in `framework/build.mjs`.
|
|
64
65
|
- Route facts, rendered plans, artifact requirements, and emitted-file decisions are represented at adjacent but not fully explicit boundaries.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Status
|
|
4
4
|
|
|
5
|
-
The `0.8.
|
|
5
|
+
The `0.8.21` EffectIR source-analysis seam is complete. Goal A continues with the planned `0.8.22` RouteIR, CapabilityIR, and architecture/output audit while preserving accepted React-shaped syntax, diagnostics, complete HTML, emitted capability behavior, and current public APIs.
|
|
6
6
|
|
|
7
7
|
## Target Boundaries
|
|
8
8
|
|
|
@@ -49,7 +49,7 @@ Existing representations are promoted rather than copied:
|
|
|
49
49
|
| `HandlerIR` | Plain command data or a stable generated-module export reference. |
|
|
50
50
|
| `BindingIR` | Promote existing binding descriptors. |
|
|
51
51
|
| `DerivedIR` | Reuse the existing tagged Collection Expression IR. |
|
|
52
|
-
| `EffectIR` |
|
|
52
|
+
| `EffectIR` | Records setup HandlerIR, cleanup, ordered signal/DerivedIR dependencies and subscriptions, component/keyed ownership, source provenance, and Worker edges. |
|
|
53
53
|
| `KeyedBlockIR` | Promote the existing list descriptor after ownership analysis is explicit. |
|
|
54
54
|
| `CapabilityIR` | Reuse the current pure route capability manifest. |
|
|
55
55
|
|
|
@@ -77,7 +77,7 @@ Analysis produces plain data:
|
|
|
77
77
|
}
|
|
78
78
|
```
|
|
79
79
|
|
|
80
|
-
The `0.8.
|
|
80
|
+
The `0.8.21` source result adds deterministic EffectIR setup HandlerIR links, cleanup, ordered dependencies and subscriptions, DerivedIR references, component/keyed ownership, source provenance, and Worker edges beside the existing command, component, handler, binding, derived, and KeyedBlockIR results. Source-local effect AST analysis is consumed during lowering and does not cross this boundary. Final route/layout/conditional/keyed effect IDs and lifetime allocation remain authoritative in `core.mjs`; the existing route plan is not duplicated in ModuleIR.
|
|
81
81
|
|
|
82
82
|
Source codegen lowers that data through the existing build ABI:
|
|
83
83
|
|
|
@@ -89,7 +89,7 @@ __kBehavior([["add", count, 1]])
|
|
|
89
89
|
|
|
90
90
|
### Source Result
|
|
91
91
|
|
|
92
|
-
One source-local result owns transformed source plus the sparse ModuleIR, generated handler/effect/binding/list evaluator source, client imports,
|
|
92
|
+
One source-local result owns transformed source plus the sparse ModuleIR, generated handler/effect/binding/list evaluator source, client imports, and explicit pass metadata. Worker ownership is recorded as EffectIR edges; AST-bearing data is consumed inside analysis/lowering and does not become IR or cross-build state.
|
|
93
93
|
|
|
94
94
|
### Route Result
|
|
95
95
|
|
|
@@ -117,7 +117,7 @@ No generator may analyze TSX, invent runtime component abstractions, or broaden
|
|
|
117
117
|
|
|
118
118
|
- One patch, one boundary, with no migration feature mixed in.
|
|
119
119
|
- Extract only code whose callers and outputs are understood.
|
|
120
|
-
- Replace AST side tables only when an explicit
|
|
120
|
+
- Replace AST side tables only when an explicit feature result can preserve ownership and source diagnostics.
|
|
121
121
|
- Keep `build()` as orchestration; do not replace it with a service container or plugin framework.
|
|
122
122
|
- Preserve current runtime files until their corresponding generator has artifact parity.
|
|
123
123
|
- Treat deterministic byte changes as review items even when tests pass.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Planned Version Sequence
|
|
2
2
|
|
|
3
|
-
This is an execution sequence, not release history. `0.8.16` through `0.8.
|
|
3
|
+
This is an execution sequence, not release history. `0.8.16` through `0.8.21` are completed scopes represented by package/release records; later rows remain planned until their package version and release record exist.
|
|
4
4
|
|
|
5
5
|
Keep each patch behavior-preserving and independently reviewable. If a boundary proves inseparable, revise this plan before combining releases; do not silently broaden a patch.
|
|
6
6
|
|
package/framework/README.md
CHANGED
|
@@ -36,12 +36,13 @@ Reduced Zustand migration stores lower to one ordinary layout-lifetime state slo
|
|
|
36
36
|
- `compiler/animation-frame-pass.mjs`: effect-owned animation-frame ref validation and plain mutable effect-scope lowering.
|
|
37
37
|
- `compiler/browser-signal-passes.mjs`: static media-query external-store and navigator capability-condition normalization.
|
|
38
38
|
- `compiler/collection-analysis.mjs`: pure collection expression IR, selector pipeline, alias, and imported-transform analysis.
|
|
39
|
-
- `compiler/descriptor-session.mjs`: private source-local descriptor registration and deterministic JSON-safe HandlerIR, BindingIR, DerivedIR, import, and client-root finalization.
|
|
39
|
+
- `compiler/descriptor-session.mjs`: private source-local descriptor registration and deterministic JSON-safe HandlerIR, BindingIR, DerivedIR, KeyedBlockIR, EffectIR, import, and client-root finalization.
|
|
40
|
+
- `compiler/effect-analysis.mjs`: ordered effect dependency classification and cleanup-owned browser resource validation before EffectIR registration.
|
|
40
41
|
- `compiler/normalization-pipeline.mjs`: ordered source normalization with parent-pointer repair after every compiler pass.
|
|
41
42
|
- `compiler/react-migration-pass.mjs`: React import, memo, callback, `forwardRef`, and `useId` migration validation and lowering.
|
|
42
43
|
- `compiler/custom-hook-timer-pass.mjs`: private custom-hook timeout-ref validation and compiler-owned timer-state lowering.
|
|
43
44
|
- `compiler/effect-codegen.mjs`: route-specific ordinary, owned, and navigable effect entry generation.
|
|
44
|
-
- `compiler/optimize/command-specialization.mjs`, `compiler/ir/module-ir.mjs`, and `compiler/codegen/command-codegen.mjs`: JSON-safe command
|
|
45
|
+
- `compiler/optimize/command-specialization.mjs`, `compiler/ir/module-ir.mjs`, and `compiler/codegen/command-codegen.mjs`: JSON-safe command, keyed, and effect ownership registration, sparse per-source ModuleIR, and source-analysis-free existing behavior-call generation.
|
|
45
46
|
- `compiler/handler-lowering.mjs`: source-local native/effect callback, reducer, Context, Zustand, reactive-binding, and list-evaluator AST lowering before IR finalization.
|
|
46
47
|
- `compiler/handler-codegen.mjs`: AST-free ordered import rendering and finalized handler/binding export-source assembly.
|
|
47
48
|
- `compiler/render-control-pass.mjs`: render-function early-return and exhaustive adjacent-assignment normalization.
|
|
@@ -64,7 +65,7 @@ Reduced Zustand migration stores lower to one ordinary layout-lifetime state slo
|
|
|
64
65
|
- `dev-state.js`: dev-only, short-lived logical-state snapshot validation and restoration.
|
|
65
66
|
- `*.d.ts`: public TypeScript and JSX declarations.
|
|
66
67
|
|
|
67
|
-
Compiler ownership follows four explicit stages. `build.mjs` owns project discovery, route planning, and artifact emission. `compiler/normalization-pipeline.mjs` owns pass order and repairs parent pointers after every source transform; migration passes keep per-file state local and return additional metadata explicitly. The main transformer analyzes normalized source while `compiler/descriptor-session.mjs` owns one per-source semantic artifact containing
|
|
68
|
+
Compiler ownership follows four explicit stages. `build.mjs` owns project discovery, route planning, and artifact emission. `compiler/normalization-pipeline.mjs` owns pass order and repairs parent pointers after every source transform; migration passes keep per-file state local and return additional metadata explicitly. The main transformer analyzes normalized source while `compiler/descriptor-session.mjs` owns one per-source semantic artifact containing HandlerIR, BindingIR, DerivedIR, KeyedBlockIR, EffectIR, and client imports. Keyed blocks link deterministic parent/child sites, component specializations, row states/refs, and generated handlers/bindings without replacing `core.mjs` final DOM ownership. Effects link setup handlers, dependencies, cleanup, lexical/keyed ownership, provenance, and Worker edges without duplicating the rendered route plan. `compiler/collection-analysis.mjs` owns the shared pure collection language used by React migration, reactive expressions, effects, and keyed lists. After build-time rendering, `compiler/route-capability-planner.mjs` projects serializable route plans into one capability manifest consumed by runtime specialization and artifact emission. Codegen modules turn descriptors into route-specific ESM without participating in source analysis. The versioned continuation plan lives in `docs/next-architecture`; it adds no runtime or accepted syntax by itself.
|
|
68
69
|
|
|
69
70
|
New syntax support belongs in an existing pass or a focused new pass only when a reduced migration fixture proves it. Passes must preserve source-located diagnostics, avoid module-global analysis state, and expose metadata through return values rather than AST-identity side channels. Build orchestration stays in `build.mjs`; feature-specific graph validation or code generation moves under `compiler/` when it has a stable input/output boundary.
|
|
70
71
|
|