@kudzujs/core 0.16.24 → 0.16.26

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 (29) hide show
  1. package/README.md +47 -5
  2. package/framework/compiler/effect-private-ref-pass.mjs +2 -0
  3. package/framework/compiler/source-compiler.mjs +6 -1
  4. package/package.json +2 -7
  5. package/GOAL_A.md +0 -116
  6. package/GOAL_B.md +0 -121
  7. package/MIGRATION_ROADMAP.md +0 -457
  8. package/PERFORMANCE.md +0 -2200
  9. package/RELEASES.md +0 -4653
  10. package/docs/next-architecture/0.9-baseline.md +0 -1199
  11. package/docs/next-architecture/0.9-benchmark-contracts.md +0 -507
  12. package/docs/next-architecture/0.9-component-property-contract.md +0 -89
  13. package/docs/next-architecture/0.9-compression-ledger.md +0 -227
  14. package/docs/next-architecture/0.9-final-proof-audit.md +0 -176
  15. package/docs/next-architecture/0.9-implementation-plan.md +0 -1819
  16. package/docs/next-architecture/0.9-resource-lifecycle.md +0 -118
  17. package/docs/next-architecture/0.9-semantic-compression.md +0 -384
  18. package/docs/next-architecture/1.0-large-application-compatibility-audit.md +0 -372
  19. package/docs/next-architecture/README.md +0 -56
  20. package/docs/next-architecture/application-capability-release-plan.md +0 -2358
  21. package/docs/next-architecture/compiler-current-architecture.md +0 -95
  22. package/docs/next-architecture/goal-a-compiler-foundation.md +0 -151
  23. package/docs/next-architecture/goal-b-optimization-benchmarks.md +0 -86
  24. package/docs/next-architecture/goal-c-state-resource-research.md +0 -88
  25. package/docs/next-architecture/goal-d-routing-compatibility-decisions.md +0 -52
  26. package/docs/next-architecture/large-application-ai-native-roadmap.md +0 -486
  27. package/docs/next-architecture/performance-gates.md +0 -50
  28. package/docs/next-architecture/versioning.md +0 -91
  29. package/framework/README.md +0 -105
package/README.md CHANGED
@@ -14,16 +14,14 @@ Kudzu compiles ordinary React-shaped TypeScript and TSX into complete static HTM
14
14
 
15
15
  > Experimental `0.16.x`: the compiler API and supported TSX surface may change.
16
16
 
17
- **Latest release: 0.16.24 - imported article search and benchmark integrity.** Ordinary imported search aliases and counts compile through existing semantics with byte-identical JavaScript to the inlined control. Revision-4 benchmark protocols preserve partial evidence and enforce setup-inclusive deadlines for future runs; no fresh AI performance result is claimed, and `1.0.0` remains blocked. Read the [release notes](./RELEASES.md#01624---imported-article-search-and-benchmark-integrity), open the [release page](https://github.com/kudzujs/kudzu/releases/tag/v0.16.24), or follow the [architecture packet](./docs/next-architecture/README.md).
17
+ **Current release: [0.16.26](https://github.com/kudzujs/kudzu/releases/tag/v0.16.26).** Write reusable components, native event handlers, and pure collection expressions; Kudzu specializes supported source into static content and direct browser updates.
18
18
 
19
19
  - [Documentation](https://kudzujs.cloud/docs)
20
20
  - [Installation guide](https://kudzujs.cloud/docs#install)
21
21
  - [Components and migration support](https://kudzujs.cloud/docs#components)
22
22
  - [Current limits](https://kudzujs.cloud/docs#limits)
23
23
  - [Benchmarks](https://kudzujs.cloud/docs#benchmarks)
24
- - [Raw performance records](https://github.com/kudzujs/kudzu/blob/main/PERFORMANCE.md)
25
- - [React migration roadmap](https://github.com/kudzujs/kudzu/blob/main/MIGRATION_ROADMAP.md)
26
- - [Release history](./RELEASES.md)
24
+ - [Release history](https://github.com/kudzujs/kudzu/releases)
27
25
 
28
26
  ## Quick Start
29
27
 
@@ -88,6 +86,50 @@ npm run dev
88
86
  npm run build
89
87
  ```
90
88
 
89
+ ## Authoring
90
+
91
+ Use native HTML controls and events. Read the control through `event.currentTarget`
92
+ inside the handler and update state with its setter; Kudzu does not use React
93
+ synthetic events. Setters update logical state immediately and batch DOM writes.
94
+
95
+ Keep derived values pure: top-level `const` locals can normalize primitive state,
96
+ filter an immutable collection, and reuse its `.length` in JSX. Render ordinary
97
+ child components with stable keys rather than manually rebuilding DOM rows.
98
+ For example, with `items` exported as a JSON-safe immutable array from `../data`
99
+ and `Item` as a relative component rendering one item:
100
+
101
+ ```tsx
102
+ import { useState } from "@kudzujs/core"
103
+ import { items } from "../data"
104
+ import { Item } from "../Item"
105
+
106
+ export default function ItemsPage() {
107
+ const [query, setQuery] = useState("")
108
+ const normalized = query.trim().toLowerCase()
109
+ const visible = items.filter(item => item.name.toLowerCase().includes(normalized))
110
+ const count = visible.length
111
+
112
+ return <main>
113
+ <label htmlFor="item-query">Find items</label>
114
+ <input id="item-query" type="search" value={query}
115
+ onInput={event => setQuery(event.currentTarget.value)} />
116
+ <p aria-live="polite">Matches: {count}</p>
117
+ <ul>{visible.map(item => <Item key={item.id} item={item} />)}</ul>
118
+ </main>
119
+ }
120
+ ```
121
+
122
+ Collection aliases must stay within supported collection/count uses; arbitrary
123
+ calls, mutation, and escaping reactive collections are not supported. Use the
124
+ build's source-located diagnostic and [current limits](https://kudzujs.cloud/docs#limits)
125
+ to identify the boundary rather than assuming arbitrary React code will compile.
126
+
127
+ Keep interactions in the routes that need them. Build-known direct imported
128
+ maps and pure static filters can emit complete HTML without list JavaScript.
129
+ A static sibling outside an enhanced-navigation group ships no JavaScript merely
130
+ because another page is interactive. Shared layout effects or explicit navigation
131
+ groups have their own lifetime; native anchors remain the default.
132
+
91
133
  ## How It Works
92
134
 
93
135
  ```text
@@ -155,7 +197,7 @@ npm run check
155
197
  npm test
156
198
  ```
157
199
 
158
- Read [AGENTS.md](https://github.com/kudzujs/kudzu/blob/main/AGENTS.md) and the [migration roadmap](https://github.com/kudzujs/kudzu/blob/main/MIGRATION_ROADMAP.md) before extending migration syntax or browser capabilities.
200
+ Contributor instructions live in the [repository](https://github.com/kudzujs/kudzu).
159
201
 
160
202
  ## License
161
203
 
@@ -72,6 +72,8 @@ export function normalizeEffectPrivateRefs(sourceFile, factory, context) {
72
72
  if (frameAssignments.length && invalidReference) throw sourceNodeError(invalidReference, sourceFile, "Animation frame refs may only use direct .current reads and assignments")
73
73
  if (frameAssignments.length && !topLevelConst) throw sourceNodeError(node, sourceFile, "Animation frame refs must be one top-level component const")
74
74
  if (attachedToJsx && mutations.length) throw sourceNodeError(mutations[0], sourceFile, "JSX object refs may not assign to ref.current")
75
+ const renderWrite = mutations.find(access => nearestFunction(access) === owner)
76
+ if (renderWrite) throw sourceNodeError(renderWrite, sourceFile, "Mutable refs cannot be assigned during render; use component state for values retained across effect replacements, or an effect-private ref with cleanup for invocation-local values")
75
77
  if (!topLevelConst || invalidReference || !accesses.length) return
76
78
  const effectCalls = owner.body.statements.flatMap(statement => hasUseEffectImport && ts.isExpressionStatement(statement) && ts.isCallExpression(statement.expression) && ts.isIdentifier(statement.expression.expression) && statement.expression.expression.text === "useEffect" && !isShadowedIdentifier(statement.expression.expression, sourceFile) ? [statement.expression] : [])
77
79
  const effects = effectCalls.filter(effect => {
@@ -1709,7 +1709,10 @@ function createKudzuTransformer({ semantic, handlerUrl, file, sourceFiles, sourc
1709
1709
  collectionLengthDeclarations.add(current)
1710
1710
  return false
1711
1711
  }
1712
- if (ts.isJsxExpression(current) && current.initializer === undefined) return false
1712
+ if (ts.isJsxExpression(current) && current.initializer === undefined) {
1713
+ resolveReactiveJsxExpression(reference.parent, owner, settersForNode(reference, settersByFunction), collectionValueDeclarations)
1714
+ return false
1715
+ }
1713
1716
  }
1714
1717
  return true
1715
1718
  })
@@ -2464,6 +2467,8 @@ function keyedListParts(expression, setters, declarations, fail, aliases = new S
2464
2467
  const field = keyExpression && directProperty(keyExpression, parameters.item)
2465
2468
  const positional = Boolean(keyExpression && parameters.index && ts.isIdentifier(unwrapExpression(keyExpression)) && unwrapExpression(keyExpression).text === parameters.index)
2466
2469
  if (!field && !positional) fail(key ?? root, `Keyed list root must have key={${parameters.item}.<field>} or key={${parameters.index ?? "index"}}`)
2470
+ // Direct build-known imports can execute their map without keyed browser ownership.
2471
+ if (collection.static && !collection.localStatic && !collection.selectorStates.size && !collection.aliasDeclarations?.length) return undefined
2467
2472
  return { ...collection, static: collection.static && (!collection.localStatic || collection.selector.length > 0), callback, root, item: parameters.item, index: parameters.index, indexed: Boolean(parameters.index), keyField: positional ? null : field }
2468
2473
  }
2469
2474
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kudzujs/core",
3
- "version": "0.16.24",
3
+ "version": "0.16.26",
4
4
  "description": "HTML-first TSX framework with synchronous state semantics and no virtual DOM",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -23,13 +23,8 @@
23
23
  },
24
24
  "files": [
25
25
  "bin/",
26
- "docs/next-architecture/",
27
26
  "framework/",
28
- "GOAL_A.md",
29
- "GOAL_B.md",
30
- "MIGRATION_ROADMAP.md",
31
- "PERFORMANCE.md",
32
- "RELEASES.md",
27
+ "!framework/README.md",
33
28
  "README.md",
34
29
  "LICENSE"
35
30
  ],
package/GOAL_A.md DELETED
@@ -1,116 +0,0 @@
1
- # Goal A: Static Application Lifecycles And Opt-In Navigation
2
-
3
- Goal A is a completed compiler-capability milestone for general React-to-static migration. It proves that ordinary React-shaped applications can retain shared layouts, route lifetimes, asynchronous workflows, and optional same-document navigation while every route remains a complete static document.
4
-
5
- The six-route commerce journey is one executable validation fixture. It is not Kudzu's product scope, a commerce API, or the priority model for future development. [`MIGRATION_ROADMAP.md`](./MIGRATION_ROADMAP.md) is the source of truth for product direction and future fixture-driven work.
6
-
7
- ## Status
8
-
9
- Goal A is complete for explicitly configured emitted-route groups with shared layouts. Implemented capabilities include:
10
-
11
- - complete standalone documents for exact and runtime-parameter routes;
12
- - native navigation fallback and opt-in same-document navigation;
13
- - persistent layout state and effects with disposable route state and effects;
14
- - conditional and keyed DOM ownership within layout and route lifetimes;
15
- - validated finite prefetch caching for eligible links;
16
- - optimistic success, rejection, rollback, and stale-write suppression;
17
- - multiple independent shared-layout groups with overlap diagnostics.
18
-
19
- Future migration features do not extend Goal A as a product vertical. They return to the migration roadmap and begin with a failing conventional React fixture.
20
-
21
- ## Capability Contract
22
-
23
- A migrated application may use familiar function components, props, children, JSX, hooks, conditions, collections, and handlers while Kudzu emits:
24
-
25
- ```text
26
- complete static document
27
- -> optional persistent layout range
28
- -> replaceable route range
29
- -> only the route-specific ESM capabilities used
30
- ```
31
-
32
- The capability must preserve:
33
-
34
- - complete indexable HTML for every route;
35
- - direct entry, reload, back, forward, query strings, and base paths;
36
- - URL, route, and shared-layout state with explicit lifetimes;
37
- - async loading, empty, error, retry, cancellation, and stale-result handling;
38
- - optimistic updates, rejection, rollback, and accessible status output;
39
- - focus, title, scroll, and announcement behavior after enhanced navigation;
40
- - ordinary document navigation when JavaScript is absent, late, or fails.
41
-
42
- ## Invariants
43
-
44
- - Native `<a>` navigation is the default.
45
- - Navigation enhancement is explicit per emitted route group.
46
- - Every enhanced route also exists as a complete document.
47
- - Static routes emit zero client JavaScript.
48
- - Interactive routes emit only the capabilities they use.
49
- - React, a VDOM, hydration, retained browser components, and browser component rerenders remain forbidden.
50
- - External, download, modified-click, reload, malformed, unsupported, and ungrouped links keep native behavior.
51
- - A failed or superseded transition cannot commit stale route state.
52
- - No separate fragment protocol, router API, cache, or scheduler is added without a measured fixture requirement.
53
-
54
- ## Ownership Model
55
-
56
- Goal A adds explicit ownership, not a state library or application runtime.
57
-
58
- | Owner | Lifetime | General examples |
59
- |---|---|---|
60
- | Document | Full document | global listeners and document-exit cleanup |
61
- | Layout | Enhanced navigation session | user summary, navigation state, shared resource |
62
- | Route | Current route range | filters, requests, subscriptions, pending work |
63
- | DOM range | Conditional or keyed item | listener, effect, ref, imperative child resource |
64
-
65
- Removing an owner disposes its effects, listeners, pending work, and descendant registrations exactly once. A non-persisted document exit cleans route ownership before layout ownership. A BFCache-persisted document retains live ownership for restoration.
66
-
67
- ## Validation Fixture
68
-
69
- The reduced commerce journey remains a useful integration fixture because it exercises the neutral capability contract in one flow:
70
-
71
- ```text
72
- home -> category -> product -> cart -> checkout -> account
73
- ```
74
-
75
- Its product filters prove URL state, variants prove route state, cart/session data proves layout state, rejected updates prove rollback, and product-to-cart transitions prove enhanced navigation. These nouns belong to the fixture only; Kudzu must not add commerce-specific APIs or architecture.
76
-
77
- Other applications should validate the same capabilities with domain-appropriate fixtures such as documentation, content, administration, forms, and dashboards.
78
-
79
- ## Performance Protocol
80
-
81
- Matched comparisons may include React/Vite, static exports from established frameworks, and hand-written HTML/DOM code as a lower bound. Every target must provide the same initial content, behavior, errors, navigation semantics, and accessibility before results are compared directly.
82
-
83
- Record at least:
84
-
85
- - deploy bytes and initial raw/gzip JavaScript;
86
- - HTML, CSS, media, and route transfer bytes;
87
- - clean build median;
88
- - cold and warm LCP, CLS, INP, startup work, and heap;
89
- - state update, optimistic rejection, rollback, and route transition latency;
90
- - repeated-navigation listener, request, state, DOM, and heap ownership.
91
-
92
- Production builds receive one warm-up and at least seven interleaved runs. Browser comparisons use rotating fresh profiles and additional runs when ranges overlap. A repeatable browser median change above 5% is material; deterministic byte growth is always reviewed.
93
-
94
- ## Regression Gates
95
-
96
- - Static routes still emit zero JavaScript.
97
- - Routes outside configured groups remain unaffected by navigation support.
98
- - No hydration task or retained component tree is introduced.
99
- - Repeated navigation leaves no growing ownership.
100
- - Material regressions against Kudzu's previous path are explained and fixed or recorded as explicit tradeoffs.
101
- - Competitor comparisons disclose unequal rendering architecture and fixture limitations.
102
- - `npm run check`, `npm test`, and applicable browser checks pass.
103
-
104
- ## Historical Validation Record
105
-
106
- The completed commerce and lifecycle measurements remain dated evidence, not current product requirements. The latest retained records include complete desktop/mobile navigation runs, zero cold/warm CLS, exact cleanup counters, capability byte deltas, and matched framework comparisons. Release notes and repository history retain version-specific numbers; new measurements must record their source revision, fixture, browser, hardware, raw arrays, and limitations.
107
-
108
- ## Non-Goals
109
-
110
- - A default SPA router.
111
- - A commerce framework or reusable commerce package.
112
- - Arbitrary React package compatibility.
113
- - Runtime component registration, hydration, or client component rendering.
114
- - Request-time SSR, server actions, or a hidden application server.
115
- - Charting, mapping, telemetry, virtual-grid, or editor engines.
116
- - Winning synthetic metrics by omitting equivalent content, behavior, accessibility, or fallback.
package/GOAL_B.md DELETED
@@ -1,121 +0,0 @@
1
- # Goal B: Relative TypeScript Worker Capability Proof
2
-
3
- This historical capability milestone is distinct from the active [Goal B optimization program](./docs/next-architecture/goal-b-optimization-benchmarks.md).
4
-
5
- Goal B is a completed cross-application compiler-capability proof for one browser-only pattern used by realtime React-shaped applications: a route-owned relative TypeScript module Worker created and cleaned up from an inline `useEffect`.
6
-
7
- The realtime dashboard is a stress and conformance fixture. It is not a Kudzu product vertical, dashboard API, stream runtime, widget framework, server platform, or claim of ThingsBoard compatibility. [`MIGRATION_ROADMAP.md`](./MIGRATION_ROADMAP.md) remains the source of truth for future fixture-driven migration work.
8
-
9
- ## Status
10
-
11
- The exact relative TypeScript Worker capability is implemented and verified. Kudzu recognizes one statically analyzable constructor form, emits its validated module graph separately, rewrites the URL for the configured base, ties creation and termination to effect ownership, and adds no Worker bytes to routes that do not use it.
12
-
13
- Further Worker, transport, effect, or React compatibility work must begin with a reduced conventional React migration fixture that fails.
14
-
15
- ## Capability Target
16
-
17
- The focused proof uses one Worker-enabled route, one plain companion route, and one unrelated static route:
18
-
19
- ```text
20
- plain route <-> Worker-enabled route
21
- ```
22
-
23
- The stress fixture generates a logical 1,000 samples per second, keeps bounded history in a module Worker, downsamples it, and updates one imperative chart. Telemetry and chart details validate Worker isolation, throughput, and ownership; they are not Kudzu product features or advice to rewrite ordinary declarative UI imperatively.
24
-
25
- ## Supported Form
26
-
27
- The Worker must be constructed directly inside a compiled inline effect:
28
-
29
- ```tsx
30
- useEffect(() => {
31
- const worker = new Worker(
32
- new URL("../telemetry.worker.ts", import.meta.url),
33
- { type: "module" },
34
- )
35
-
36
- const onMessage = (event: MessageEvent<Frame>) => resource.render(event.data)
37
- worker.addEventListener("message", onMessage)
38
-
39
- return () => {
40
- worker.removeEventListener("message", onMessage)
41
- worker.terminate()
42
- resource.dispose()
43
- }
44
- }, [])
45
- ```
46
-
47
- Compiler requirements:
48
-
49
- - accept only an unshadowed `Worker` with `new URL(relativeLiteral, import.meta.url)` and literal `{ type: "module" }`;
50
- - resolve one `.worker.ts` entry under project source and bundle its relative TypeScript graph separately from window code;
51
- - emit deterministic content-hashed ESM under `assets/workers` and rewrite the constructor to the base-aware emitted URL;
52
- - reject package imports, JSX, import-equals declarations, dynamic imports, `require()`, paths outside source, malformed options, and unsupported Worker forms with source locations;
53
- - reject ordinary runtime imports or re-exports of `.worker.ts`; type-only imports may erase normally;
54
- - never mark Worker files as document capability scripts or import them into the window;
55
- - create the Worker only when its owning effect mounts;
56
- - preserve zero-cost exclusion for builds without relative TypeScript Workers;
57
- - reject generated/public asset collisions.
58
-
59
- Worker construction in imported helpers or imported keyed-row effects, `SharedWorker`, classic workers, Blob workers, arbitrary dynamic URLs, and package runtime graphs remain outside this completed capability.
60
-
61
- ## Ownership
62
-
63
- | Owner | Lifetime | Capability responsibility |
64
- |---|---|---|
65
- | Document | Full document | global diagnostics and document-exit cleanup |
66
- | Layout | Enhanced navigation session | explicitly shared browser resource |
67
- | Route | Current route range | Worker, subscription, request cancellation |
68
- | DOM range | Connected conditional/keyed range | imperative resource and animation work |
69
- | Worker | Explicit owner cleanup | parsing, bounded buffering, aggregation |
70
-
71
- On an enhanced same-document transition, route cleanup removes listeners, stops imperative work, terminates its Worker, and invalidates stale UI writes before the next route mounts. Non-persisted document exit performs cleanup; a BFCache-persisted document retains live ownership for restoration.
72
-
73
- ## Fixture Contract
74
-
75
- The capability fixture proves:
76
-
77
- - one complete Worker-enabled document and one complete plain document in an opt-in navigation group;
78
- - one unrelated static route with zero JavaScript;
79
- - a relative TypeScript Worker importing at least one relative helper;
80
- - bounded deterministic buffering and batched sample generation;
81
- - bounded frames delivered no faster than display cadence;
82
- - one imperative resource updated without sample-level Kudzu setters;
83
- - direct load, enhanced navigation, back/forward, and repeated cached revisits;
84
- - exact starts, terminations, messages, renders, listeners, disposal, and stale-write counters;
85
- - native document fallback when JavaScript or Worker creation fails.
86
-
87
- ## Acceptance And Performance Gates
88
-
89
- - The Worker graph is absent from static and plain route HTML and fetched only after its effect mounts.
90
- - Two unchanged builds emit identical Worker names and bytes; source changes alter the content hash.
91
- - Base-prefixed output constructs a valid same-origin Worker URL.
92
- - Repeated route cycles create and terminate exactly one route Worker each with no growing ownership.
93
- - Messages after cleanup cannot update removed route DOM.
94
- - Worker memory remains bounded by declared capacity.
95
- - High-frequency ingestion does not create one main-thread task or Kudzu state commit per sample.
96
- - Imperative rendering is batched to its declared cadence.
97
- - Builds without this capability remain unaffected.
98
- - Raw/gzip output, build time, throughput, cadence, and lifecycle counters are recorded.
99
- - `npm run check`, `npm test`, package dry-run, and applicable browser checks pass.
100
-
101
- ## Historical Validation Record
102
-
103
- The focused fixture emitted a 907 B raw / 477 B gzip Worker graph and an 11,388 B raw / 5,148 B gzip window graph. Seven clean minified builds measured a 463.5 ms median. Thirty route cycles produced exactly 30 starts and terminations, balanced message/error listener registration, bounded 128-sample history, no retained chart ownership, no stale post-cleanup render, deterministic unchanged builds, and a changed hash after a controlled Worker source edit.
104
-
105
- These numbers are dated conformance evidence. They do not define a dashboard product target.
106
-
107
- ## Historical 0.7.12 Rerun
108
-
109
- At commit `05e5cc2` on Apple M3 / macOS 26.5.2 / Node 25.6.1, `npm run benchmark` measured clean build times of 404.2, 401.3, 408.2, 404.4, 399.9, 408.8, and 402.0 ms after one warm-up, for a 404.2 ms median. That rerun's Worker graph was 907 B raw / 475 B gzip; its complete dashboard window graph was 11,960 B raw / 5,365 B aggregate gzip.
110
-
111
- Chrome 150.0.7871.187 passed the tracked throughput, cadence, stale-write, bounded-history, and 30-cycle start/termination checks through the focused Worker browser test. Those rerun values differ from the historical completion snapshot because shared window capabilities and the local toolchain changed; both sets remain release provenance, not current artifact claims.
112
-
113
- ## Non-Goals
114
-
115
- - Device, alarm, tenant, transport, chart, map, or widget product features.
116
- - A general stream, observable, scheduler, state, or plugin runtime.
117
- - Storing high-frequency samples in Kudzu component state.
118
- - Retaining a browser component tree.
119
- - Request-time SSR, server actions, or a hidden server.
120
- - Arbitrary third-party React widgets.
121
- - Treating Worker isolation as a security sandbox.