@kudzujs/core 0.8.29 → 0.8.30
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 -1
- package/README.md +1 -1
- package/RELEASES.md +30 -0
- package/docs/next-architecture/README.md +1 -1
- package/docs/next-architecture/compiler-current-architecture.md +2 -2
- package/docs/next-architecture/large-application-ai-native-roadmap.md +4 -3
- package/docs/next-architecture/versioning.md +2 -1
- package/framework/compiler/source-compiler.mjs +15 -17
- package/framework/compiler/source-graph.mjs +27 -0
- package/package.json +1 -1
package/MIGRATION_ROADMAP.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
This document is the source of truth for Kudzu's product direction, architecture invariants, and future development order. Read it before extending React-shaped syntax or browser capabilities.
|
|
4
4
|
|
|
5
|
-
The executable post-`0.8.
|
|
5
|
+
The executable post-`0.8.30` compiler and large-application sequence is maintained in [`docs/next-architecture/large-application-ai-native-roadmap.md`](./docs/next-architecture/large-application-ai-native-roadmap.md). Follow its PR dependencies for implementation work; this document remains authoritative when selecting or accepting a migration capability.
|
|
6
6
|
|
|
7
7
|
[`GOAL_A.md`](./GOAL_A.md) and [`GOAL_B.md`](./GOAL_B.md) are completed capability-validation records. Their commerce and realtime dashboard fixtures prove general lifecycle, navigation, async-workflow, and Worker capabilities; they are not separate product verticals or future priority lists.
|
|
8
8
|
|
|
@@ -282,6 +282,12 @@ This queue orders the next investigations by general migration value. Start only
|
|
|
282
282
|
- Same-named callback parameters, locals, imports, browser globals, state values, setters, reducers, observer handles, and animation-frame handles no longer alias through identifier spelling alone.
|
|
283
283
|
- Imported, specialized, and compiler-synthesized trees retain the existing conservative fallback; no public API, source syntax, ModuleIR contract, browser runtime, or capability bytes were added.
|
|
284
284
|
|
|
285
|
+
### Completed In 0.8.30
|
|
286
|
+
|
|
287
|
+
- Reachable ordinary source validates relative runtime imports and re-exports before compilation and reports unresolved edges at the original importer file, line, column, and specifier.
|
|
288
|
+
- Ordinary dynamic `import()` fails during graph discovery rather than surviving into generated `.kudzu` modules; relative, package, template, and computed forms share one source-located boundary.
|
|
289
|
+
- Ordinary and Worker graph ownership remain separate, while type-only and unreachable source stay excluded. Export-name validation, ProjectSession, runtime behavior, and public APIs remain unchanged.
|
|
290
|
+
|
|
285
291
|
## Cross-Cutting Performance Gates
|
|
286
292
|
|
|
287
293
|
Every migration feature must preserve:
|
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.30 - Graph failure diagnostics.** Reachable ordinary modules now validate relative runtime imports and re-exports and reject dynamic `import()` at the original importer location before generated module loading. Worker ownership, type-only edges, and unreachable source remain distinct. Read the [release notes](./RELEASES.md#0830---graph-failure-diagnostics), open the [release page](https://github.com/kudzujs/kudzu/releases/tag/v0.8.30), or follow the [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,35 @@
|
|
|
1
1
|
# Kudzu Releases
|
|
2
2
|
|
|
3
|
+
## 0.8.30 - Graph failure diagnostics
|
|
4
|
+
|
|
5
|
+
Kudzu 0.8.30 completes P0.3 by making ordinary source-graph failures stop at the original importer before compilation, generated module loading, or `.kudzu` paths can obscure the source error.
|
|
6
|
+
|
|
7
|
+
### Changed in 0.8.30
|
|
8
|
+
|
|
9
|
+
- Reachability validates every relative runtime import and re-export in an ordinary reachable module instead of silently dropping unresolved edges.
|
|
10
|
+
- Missing bound imports, side-effect imports, reachable helper imports, named/default forwarding, and `export *` report the importer file, line, column, and written specifier.
|
|
11
|
+
- Every ordinary dynamic `import()` form is rejected during graph discovery, including relative, package, template-literal, and computed specifiers.
|
|
12
|
+
- Ordinary and Worker traversal retain separate ownership, so Worker-only modules continue through Worker-specific graph diagnostics and cleanup rules.
|
|
13
|
+
- Type-only edges and unreachable migration source remain excluded and cannot block a build.
|
|
14
|
+
|
|
15
|
+
### Compiler Boundary
|
|
16
|
+
|
|
17
|
+
- `ordinaryRuntimeDependencies()` is the single pre-codegen validator for ordinary runtime graph edges; downstream import rewriting remains a fail-closed assertion.
|
|
18
|
+
- This release validates whether a relative runtime edge resolves to exactly one TypeScript file. Whether an existing target exports a requested name remains deferred to the planned module-symbol graph.
|
|
19
|
+
- P0.3 adds no accepted source syntax, ProjectSession, export cache, public API, browser runtime, or generated capability bytes. P0.4 async native-handler invalidation is next.
|
|
20
|
+
|
|
21
|
+
### Validation
|
|
22
|
+
|
|
23
|
+
- `npm run check`, `npm test`, `npm run test:package`, and all 189 tests pass.
|
|
24
|
+
- Focused in-memory and build fixtures cover missing page imports, reachable helper imports, re-exports, relative/package/computed dynamic imports, type-only exclusion, unreachable exclusion, and absence of generated `.kudzu` paths.
|
|
25
|
+
- Existing Worker graph diagnostics, React/Router/Zustand migrations, keyed ownership, effects, navigation, and static-route zero-JavaScript behavior remain covered.
|
|
26
|
+
|
|
27
|
+
### Upgrade
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm install @kudzujs/core@^0.8.30
|
|
31
|
+
```
|
|
32
|
+
|
|
3
33
|
## 0.8.29 - Symbol-aware descriptor discovery
|
|
4
34
|
|
|
5
35
|
Kudzu 0.8.29 completes P0.2 by moving native handler, effect, binding, and list descriptor decisions from identifier spelling onto the source-local binding index introduced in 0.8.28.
|
|
@@ -11,7 +11,7 @@ The top-level [`GOAL_A.md`](../../GOAL_A.md) and [`GOAL_B.md`](../../GOAL_B.md)
|
|
|
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 |
|
|
13
13
|
|
|
14
|
-
The active post-`0.8.
|
|
14
|
+
The active post-`0.8.30` implementation sequence is [`large-application-ai-native-roadmap.md`](./large-application-ai-native-roadmap.md). It orders compiler semantic generalization, large-application foundations, compatibility boundaries, AI tooling, and production validation without changing the invariants below.
|
|
15
15
|
|
|
16
16
|
## Required Invariants
|
|
17
17
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Current Compiler Architecture
|
|
2
2
|
|
|
3
|
-
This maps the current `0.8.
|
|
3
|
+
This maps the current `0.8.30` architecture built on the completed `0.8.23` Goal A compiler foundation. File and function names are the stable references; line numbers are intentionally omitted because later work may still move code.
|
|
4
4
|
|
|
5
5
|
## Responsibility Map
|
|
6
6
|
|
|
@@ -8,7 +8,7 @@ This maps the current `0.8.29` architecture built on the completed `0.8.23` Goal
|
|
|
8
8
|
|---|---|---|
|
|
9
9
|
| CLI entry | [`bin/kudzu.mjs`](../../bin/kudzu.mjs) | Dispatches build and development commands. |
|
|
10
10
|
| Build orchestration | [`framework/build.mjs`](../../framework/build.mjs), `build()` | Coordinates config, discovery, source compilation, RouteIR rendering, CapabilityIR projection, generator invocation, artifact emission, and `afterBuild`. |
|
|
11
|
-
| Reachability/import resolution | [`framework/compiler/source-compiler.mjs`](../../framework/compiler/source-compiler.mjs), `reachableSourceFiles()`; [`framework/compiler/source-graph.mjs`](../../framework/compiler/source-graph.mjs), `resolveSourceImport()` | Starts from page entries, follows relative runtime imports/re-exports and validated Worker references,
|
|
11
|
+
| Reachability/import resolution | [`framework/compiler/source-compiler.mjs`](../../framework/compiler/source-compiler.mjs), `reachableSourceFiles()`; [`framework/compiler/source-graph.mjs`](../../framework/compiler/source-graph.mjs), `ordinaryRuntimeDependencies()`, `resolveSourceImport()` | Starts from page entries, follows relative runtime imports/re-exports and validated Worker references, excludes unreachable migration source, and fails unresolved ordinary edges or dynamic imports at the importer source location before code generation. |
|
|
12
12
|
| Ordered normalization | [`framework/compiler/normalization-pipeline.mjs`](../../framework/compiler/normalization-pipeline.mjs), `applyNormalizationPasses()`; [`framework/compiler/source-compiler.mjs`](../../framework/compiler/source-compiler.mjs), `normalizeCompilerSource()` | Applies migration/resource passes in order and repairs TypeScript parent pointers after every structural change. Imported source uses the same pipeline. |
|
|
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. |
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Status
|
|
4
4
|
|
|
5
|
-
Active execution plan after `0.8.
|
|
5
|
+
Active execution plan after `0.8.30`. This document turns the current compiler audit into an ordered implementation program. It does not mark any planned capability as supported and does not authorize a React runtime, VDOM, hydration, retained browser component tree, generic rerenderer, public store/query/resource API, SPA router, or islands.
|
|
6
6
|
|
|
7
7
|
[`MIGRATION_ROADMAP.md`](../../MIGRATION_ROADMAP.md) remains authoritative for product invariants and fixture-driven feature selection. This plan is authoritative for the order and completion evidence of compiler generalization, large-application foundations, compatibility boundaries, AI tooling, and scale validation. If implementation evidence changes a boundary, update this document before broadening a patch.
|
|
8
8
|
|
|
@@ -131,7 +131,8 @@ This is an incremental evolution of the current repository:
|
|
|
131
131
|
|
|
132
132
|
- [x] P0.1 Source-local binding index is complete in `0.8.28`. Reactive binding capture/import discovery and lowering use the index only when the complete expression is indexed; synthesized keyed expressions retain the existing fail-safe path. Focused scope tests, a 1,000-reference guard, browser integration, all 185 tests, and packed-package smoke pass.
|
|
133
133
|
- [x] P0.2 Symbol-aware descriptor discovery is complete in `0.8.29`. Native handler, effect, remaining binding, list evaluator, optimized-command, and effect-resource discovery/lowering use the source-local binding index when it owns the complete AST; synthesized trees retain the existing fail-safe path. Focused lexical-shadow, JSON-safe IR, resource-ownership checks, all 187 tests, and packed-package smoke pass.
|
|
134
|
-
- [
|
|
134
|
+
- [x] P0.3 Graph diagnostics is complete in `0.8.30`. Reachable ordinary modules validate relative runtime imports/re-exports and reject every dynamic `import()` at the importer source location before compilation or generated module loading. Ordinary and Worker traversal retain separate ownership, type-only and unreachable edges remain excluded, focused page/helper/re-export/dynamic fixtures pass with all 189 tests and packed-package smoke, and no export-symbol graph, ProjectSession, runtime, or public API is added.
|
|
135
|
+
- [ ] P0.4 Async native handler ownership is next. Pending handlers must not write after route or DOM ownership is released.
|
|
135
136
|
|
|
136
137
|
### P0: Semantic Correctness And Compiler Foundation
|
|
137
138
|
|
|
@@ -455,4 +456,4 @@ The first comparison is Kudzu versus React + Vite using the same agent, model, t
|
|
|
455
456
|
|
|
456
457
|
The first implementation PR is **PR 1: Source-Local Binding Index**. It is compile-time only, adds no browser bytes or public API, fixes an existing correctness class, and creates the stable semantic foundation required by component graphs, state operations, cross-module analysis, compatibility adapters, structured diagnostics, and AI explanation tooling.
|
|
457
458
|
|
|
458
|
-
The next PR is **PR
|
|
459
|
+
The next PR is **PR 4: Async Native Handler Invalidation**. Do not skip directly to a store, resource, router, virtualization, or ecosystem package feature.
|
|
@@ -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.30` are completed scopes represented by package/release records.
|
|
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
|
|
|
@@ -20,6 +20,7 @@ Keep each patch behavior-preserving and independently reviewable. If a boundary
|
|
|
20
20
|
| `0.8.27` | Characterize the first Goal C browser-resource boundary and publish the ordered large-application and AI-native compiler execution plan. | The E2B-derived fixture fails with a source-located diagnostic, no resource runtime or API is added, and the next PR dependencies and completion evidence are explicit. |
|
|
21
21
|
| `0.8.28` | Add the source-local binding index and adopt it for reactive binding capture/import discovery and lowering. | Lexical shadowing is identity-based for complete indexed bindings, synthesized keyed expressions retain their fallback, the 1,000-reference guard passes, and no browser bytes or public API are added. |
|
|
22
22
|
| `0.8.29` | Move native handler, effect, remaining binding, list evaluator, optimized-command, and effect-resource discovery/lowering onto source-local lexical identity. | Shadowed imports/globals/state/resources remain distinct, HandlerIR/BindingIR round trips pass, synthesized trees retain the fallback, and no runtime or public API is added. |
|
|
23
|
+
| `0.8.30` | Validate ordinary runtime graph edges before code generation and reject dynamic imports at the importer source. | Page/helper/re-export/dynamic fixtures report original file/range/specifier without `.kudzu` paths; Worker, type-only, unreachable, output, and runtime behavior remain unchanged. |
|
|
23
24
|
|
|
24
25
|
## Sequence Rules
|
|
25
26
|
|
|
@@ -18,7 +18,7 @@ import { assetPath, relativeModulePath, withBase } from "./path-helpers.mjs"
|
|
|
18
18
|
import { createReactMigrationPass, reactMemoExpression } from "./react-migration-pass.mjs"
|
|
19
19
|
import { normalizeRenderControlFlow } from "./render-control-pass.mjs"
|
|
20
20
|
import { createRouterPass } from "./router-pass.mjs"
|
|
21
|
-
import { parseSourceFile, resolveSourceImport, runtimeModuleReference } from "./source-graph.mjs"
|
|
21
|
+
import { ordinaryRuntimeDependencies, parseSourceFile, resolveSourceImport, runtimeModuleReference } from "./source-graph.mjs"
|
|
22
22
|
import { createWorkerCompiler } from "./worker-compiler.mjs"
|
|
23
23
|
import { createZustandPass } from "./zustand-pass.mjs"
|
|
24
24
|
|
|
@@ -92,20 +92,27 @@ function emittedPackageReference(source, file, packages) {
|
|
|
92
92
|
|
|
93
93
|
export function reachableSourceFiles(entries, sourceFiles, sourceIndex) {
|
|
94
94
|
const reachable = new Set()
|
|
95
|
-
const
|
|
95
|
+
const ordinary = new Set()
|
|
96
|
+
const workers = new Set()
|
|
97
|
+
const queue = entries.map(file => ({ file, owner: "ordinary" }))
|
|
96
98
|
while (queue.length) {
|
|
97
|
-
const file = queue.pop()
|
|
98
|
-
|
|
99
|
+
const { file, owner } = queue.pop()
|
|
100
|
+
const visited = owner === "ordinary" ? ordinary : workers
|
|
101
|
+
if (visited.has(file)) continue
|
|
102
|
+
visited.add(file)
|
|
99
103
|
reachable.add(file)
|
|
100
104
|
const sourceFile = parseSourceFile(file, sourceIndex.get(file))
|
|
105
|
+
if (owner === "ordinary") for (const target of ordinaryRuntimeDependencies(file, sourceFile, sourceFiles, isStaticImport)) queue.push({ file: target, owner: target.endsWith(".worker.ts") ? "worker" : owner })
|
|
101
106
|
const visit = node => {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
107
|
+
if (owner === "worker") {
|
|
108
|
+
const specifier = (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) && runtimeModuleReference(node) && node.moduleSpecifier
|
|
109
|
+
if (specifier && ts.isStringLiteral(specifier) && specifier.text.startsWith(".") && !isStaticImport(specifier.text)) {
|
|
110
|
+
try { queue.push({ file: resolveSourceImport(file, specifier.text, sourceFiles), owner }) } catch {}
|
|
111
|
+
}
|
|
105
112
|
}
|
|
106
113
|
const worker = workerCompiler.candidate(node, sourceFile)
|
|
107
114
|
if (worker && ts.isStringLiteral(worker.url.arguments[0]) && worker.url.arguments[0].text.endsWith(".worker.ts")) {
|
|
108
|
-
try { queue.push(resolveSourceImport(file, worker.url.arguments[0].text, sourceFiles)) } catch {}
|
|
115
|
+
try { queue.push({ file: resolveSourceImport(file, worker.url.arguments[0].text, sourceFiles), owner: "worker" }) } catch {}
|
|
109
116
|
}
|
|
110
117
|
ts.forEachChild(node, visit)
|
|
111
118
|
}
|
|
@@ -2667,15 +2674,6 @@ function hasFrameworkImport(sourceFile, name) {
|
|
|
2667
2674
|
|
|
2668
2675
|
function packageImportBindings(sourceFile) {
|
|
2669
2676
|
const bindings = new Map()
|
|
2670
|
-
const rejectDynamic = node => {
|
|
2671
|
-
if (ts.isCallExpression(node) && node.expression.kind === ts.SyntaxKind.ImportKeyword) {
|
|
2672
|
-
const specifier = node.arguments.length === 1 && ts.isStringLiteralLike(node.arguments[0]) ? node.arguments[0].text : null
|
|
2673
|
-
if (specifier === null) throw sourceNodeError(node, sourceFile, "Dynamic import specifiers are not supported")
|
|
2674
|
-
if (!specifier.startsWith(".")) throw sourceNodeError(node, sourceFile, `Dynamic package import ${JSON.stringify(specifier)} is not supported`)
|
|
2675
|
-
}
|
|
2676
|
-
ts.forEachChild(node, rejectDynamic)
|
|
2677
|
-
}
|
|
2678
|
-
rejectDynamic(sourceFile)
|
|
2679
2677
|
for (const node of sourceFile.statements) {
|
|
2680
2678
|
if (!ts.isImportDeclaration(node) || !ts.isStringLiteral(node.moduleSpecifier)) continue
|
|
2681
2679
|
const target = node.moduleSpecifier.text
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { dirname, extname, join, relative, resolve } from "node:path"
|
|
2
2
|
import ts from "typescript"
|
|
3
|
+
import { sourceNodeError } from "./ast-helpers.mjs"
|
|
3
4
|
|
|
4
5
|
const root = process.cwd()
|
|
5
6
|
|
|
@@ -24,6 +25,32 @@ export function runtimeModuleReference(node) {
|
|
|
24
25
|
return clause.namedBindings?.elements.some(entry => !entry.isTypeOnly) ?? false
|
|
25
26
|
}
|
|
26
27
|
|
|
28
|
+
export function ordinaryRuntimeDependencies(file, sourceFile, sourceFiles, isStaticImport) {
|
|
29
|
+
const dependencies = []
|
|
30
|
+
const rejectDynamicImports = node => {
|
|
31
|
+
if (ts.isCallExpression(node) && node.expression.kind === ts.SyntaxKind.ImportKeyword) {
|
|
32
|
+
const argument = node.arguments[0]
|
|
33
|
+
const specifier = node.arguments.length === 1 && ts.isStringLiteralLike(argument) ? JSON.stringify(argument.text) : argument?.getText(sourceFile) ?? "<missing>"
|
|
34
|
+
throw sourceNodeError(node, sourceFile, `Dynamic import ${specifier} is not supported in ordinary source modules`)
|
|
35
|
+
}
|
|
36
|
+
ts.forEachChild(node, rejectDynamicImports)
|
|
37
|
+
}
|
|
38
|
+
rejectDynamicImports(sourceFile)
|
|
39
|
+
for (const node of sourceFile.statements) {
|
|
40
|
+
if ((!ts.isImportDeclaration(node) && !ts.isExportDeclaration(node)) || !runtimeModuleReference(node) || !node.moduleSpecifier || !ts.isStringLiteral(node.moduleSpecifier)) continue
|
|
41
|
+
const specifier = node.moduleSpecifier
|
|
42
|
+
if (!specifier.text.startsWith(".") || isStaticImport(specifier.text)) continue
|
|
43
|
+
try {
|
|
44
|
+
dependencies.push(resolveSourceImport(file, specifier.text, sourceFiles))
|
|
45
|
+
} catch (error) {
|
|
46
|
+
const detail = error.message.slice(error.message.indexOf("Relative import"))
|
|
47
|
+
const edge = ts.isExportDeclaration(node) ? "re-export" : "import"
|
|
48
|
+
throw sourceNodeError(specifier, sourceFile, detail.replace("Relative import", `Relative runtime ${edge}`))
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return dependencies
|
|
52
|
+
}
|
|
53
|
+
|
|
27
54
|
export function parseSourceFile(file, source) {
|
|
28
55
|
return ts.createSourceFile(file, source, ts.ScriptTarget.ES2022, true, file.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS)
|
|
29
56
|
}
|