@kudzujs/core 0.16.32 → 0.16.34
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/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.16.x`: the compiler API and supported TSX surface may change.
|
|
16
16
|
|
|
17
|
-
**Current release: [0.16.
|
|
17
|
+
**Current release: [0.16.34](https://github.com/kudzujs/kudzu/releases/tag/v0.16.34).** Adds optional AI authoring instructions and local developer tools through `create-kudzu --ai`, preserving the 0.16.33 compiler and runtime. Document lookup and check execution provide bounded responses with full logs retained. AI-token savings are unmeasured; AI-cost and 1.0 gates remain blocked.
|
|
18
18
|
|
|
19
19
|
- [Documentation](https://kudzujs.cloud/docs)
|
|
20
20
|
- [Installation guide](https://kudzujs.cloud/docs#install)
|
|
@@ -36,6 +36,13 @@ npm run dev
|
|
|
36
36
|
|
|
37
37
|
The generated project includes reusable components, an interactive state example, a zero-JavaScript static route, metadata, and responsive CSS.
|
|
38
38
|
|
|
39
|
+
For optional AI authoring guidance and local developer tools, use
|
|
40
|
+
`npm create kudzu@latest my-app -- --ai`. The generated `AGENTS.md` describes
|
|
41
|
+
`npm run ai -- docs` for installed documentation and `npm run ai -- check` for
|
|
42
|
+
typecheck/build execution with bounded output and full retained logs. These tools
|
|
43
|
+
stay outside default browser output. AI-token savings have not been measured.
|
|
44
|
+
See the [generator guide](https://github.com/kudzujs/kudzu/tree/main/packages/create-kudzu#optional-ai-authoring-guidance).
|
|
45
|
+
|
|
39
46
|
To add Kudzu to an existing project:
|
|
40
47
|
|
|
41
48
|
```bash
|
|
@@ -131,7 +131,7 @@ function mountConditions(root) {
|
|
|
131
131
|
const truthy = globalThis.__KUDZU_SVG_CONDITIONS__ && descriptor.svg ? start.dataset.kSvgTrue : start.content.querySelector("template[data-k-true]")
|
|
132
132
|
const falsy = globalThis.__KUDZU_SVG_CONDITIONS__ && descriptor.svg ? start.dataset.kSvgFalse : start.content.querySelector("template[data-k-false]")
|
|
133
133
|
if (!end || !truthy || !falsy) continue
|
|
134
|
-
const condition = { start, end, truthy, falsy, svg: globalThis.__KUDZU_SVG_CONDITIONS__ && descriptor.svg, kind: descriptor.kind, current: conditionKey(descriptor.kind, descriptor.initial), mount: descriptor.mount, owned: globalThis.__KUDZU_CONDITION_STATE__ !== false && descriptor.owned }
|
|
134
|
+
const condition = { start, end, truthy, falsy, svg: globalThis.__KUDZU_SVG_CONDITIONS__ && descriptor.svg, kind: descriptor.kind, current: conditionKey(descriptor.kind, descriptor.initial), mount: globalThis.__KUDZU_CONDITION_MOUNTS__ !== false && descriptor.mount, owned: globalThis.__KUDZU_CONDITION_STATE__ !== false && descriptor.owned }
|
|
135
135
|
if (globalThis.__KUDZU_CONDITION_STATE__ !== false) mountConditionStates(condition, Boolean(descriptor.initial), false)
|
|
136
136
|
const mount = evaluator => {
|
|
137
137
|
if (!start.isConnected) return
|
|
@@ -163,11 +163,11 @@ function updateCondition(condition) {
|
|
|
163
163
|
: globalThis.__KUDZU_SVG_CONDITIONS__ && condition.svg
|
|
164
164
|
? svgFragment(condition.start, truthy ? condition.truthy : condition.falsy)
|
|
165
165
|
: (truthy ? condition.truthy : condition.falsy).content.cloneNode(true)
|
|
166
|
-
const nodes = condition.mount ? [...fragment.childNodes] : undefined
|
|
166
|
+
const nodes = globalThis.__KUDZU_CONDITION_MOUNTS__ !== false && condition.mount ? [...fragment.childNodes] : undefined
|
|
167
167
|
if (globalThis.__KUDZU_CONDITION_STATE__ !== false) mountConditionStates(condition, truthy, true)
|
|
168
168
|
condition.end.parentNode.insertBefore(fragment, condition.end)
|
|
169
169
|
condition.current = next
|
|
170
|
-
if (condition.mount) for (const node of nodes) mountDom(node)
|
|
170
|
+
if (globalThis.__KUDZU_CONDITION_MOUNTS__ !== false && condition.mount) for (const node of nodes) mountDom(node)
|
|
171
171
|
const select = globalThis.__KUDZU_VALUE_BINDINGS__ !== false && condition.start.closest("select[data-k-bind-value]")
|
|
172
172
|
if (select) {
|
|
173
173
|
for (const binding of new Set((bindingRegistrations.get(select) ?? []).map(([, entry]) => entry))) {
|
|
@@ -232,7 +232,7 @@ function removeConditionRange(start, end, mount) {
|
|
|
232
232
|
const range = start.ownerDocument.createRange()
|
|
233
233
|
range.setStartAfter(start)
|
|
234
234
|
range.setEndBefore(end)
|
|
235
|
-
if (mount) {
|
|
235
|
+
if (globalThis.__KUDZU_CONDITION_MOUNTS__ !== false && mount) {
|
|
236
236
|
const root = range.commonAncestorContainer
|
|
237
237
|
const nodes = matching(root, "*").filter(node => range.comparePoint(node, 0) === 0)
|
|
238
238
|
for (const node of nodes) if (!nodes.some(parent => parent !== node && parent.contains(node))) unmountDom(node)
|
|
@@ -15,7 +15,7 @@ export function planRouteCapabilities(records, { navigationRouteCount = 0 } = {}
|
|
|
15
15
|
for (const plan of plans) assertRouteIR(plan, { concrete: true })
|
|
16
16
|
const commandEvents = new Set()
|
|
17
17
|
const nativeEvents = new Set()
|
|
18
|
-
const bindings = { count: 0, text: false, style: false, conditions: false, conditionState: false, svgConditions: false }
|
|
18
|
+
const bindings = { count: 0, text: false, style: false, conditions: false, conditionState: false, conditionMounts: false, svgConditions: false }
|
|
19
19
|
const lists = {
|
|
20
20
|
count: 0,
|
|
21
21
|
styleCount: 0,
|
|
@@ -55,6 +55,7 @@ export function planRouteCapabilities(records, { navigationRouteCount = 0 } = {}
|
|
|
55
55
|
bindings.style ||= plan.bindings.some(binding => binding.target === "style")
|
|
56
56
|
bindings.conditions ||= plan.conditions.length > 0
|
|
57
57
|
bindings.conditionState ||= plan.conditions.some(condition => Object.values(condition.owned ?? {}).some(states => states.length > 0))
|
|
58
|
+
bindings.conditionMounts ||= plan.conditions.some(condition => condition.mount)
|
|
58
59
|
bindings.svgConditions ||= plan.conditions.some(condition => condition.svg)
|
|
59
60
|
effects.any ||= plan.effects.length > 0
|
|
60
61
|
effects.derivedDependencies ||= plan.effects.some(effect => effect.dependencyExpressions?.length)
|
|
@@ -126,8 +127,9 @@ export function assertCapabilityIR(capabilityIR, records, options = {}) {
|
|
|
126
127
|
if (!sections.every(name => isRecord(capabilityIR[name]))) throw new Error("Invalid CapabilityIR v1 structure")
|
|
127
128
|
if (!["behaviors", "regularBehaviors", "regularStateSeeds", "dependencyStateSeeds"].every(name => isCount(capabilityIR.routes[name]))) throw new Error("Invalid CapabilityIR v1 route counts")
|
|
128
129
|
if (!["command", "native"].every(name => Array.isArray(capabilityIR.events[name]) && capabilityIR.events[name].every(event => typeof event === "string")) || typeof capabilityIR.events.hasNativeHandlers !== "boolean") throw new Error("Invalid CapabilityIR v1 events")
|
|
129
|
-
if (!isCount(capabilityIR.bindings.count) || !["text", "style", "conditions", "conditionState", "svgConditions", "attributes"].every(name => typeof capabilityIR.bindings[name] === "boolean")) throw new Error("Invalid CapabilityIR v1 bindings")
|
|
130
|
+
if (!isCount(capabilityIR.bindings.count) || !["text", "style", "conditions", "conditionState", "conditionMounts", "svgConditions", "attributes"].every(name => typeof capabilityIR.bindings[name] === "boolean")) throw new Error("Invalid CapabilityIR v1 bindings")
|
|
130
131
|
if (capabilityIR.bindings.conditionState && !capabilityIR.bindings.conditions) throw new Error("CapabilityIR conditional state requires conditions")
|
|
132
|
+
if (capabilityIR.bindings.conditionMounts && !capabilityIR.bindings.conditions) throw new Error("CapabilityIR conditional mounts require conditions")
|
|
131
133
|
if (!Array.isArray(capabilityIR.bindings.properties) || capabilityIR.bindings.properties.some(target => !propertyBindings.includes(target)) || new Set(capabilityIR.bindings.properties).size !== capabilityIR.bindings.properties.length) throw new Error("Invalid CapabilityIR v1 binding properties")
|
|
132
134
|
if (capabilityIR.bindings.style !== capabilityIR.bindings.properties.includes("style")) throw new Error("CapabilityIR binding style flag does not match its properties")
|
|
133
135
|
const listFlags = ["conditions", "svg", "deepConditions", "textRanges", "attributes", "events", "expressions", "expressionAttributes", "seeds", "effects", "rowHooks", "rowRefs", "complexRowState", "nested", "selectors", "calculated", "static", "indexes", "stableFastPaths", "generalRowHooks", "asyncParts", "mounts"]
|
|
@@ -30,6 +30,7 @@ export function generateBindingRuntime(source, capabilityIR, navigable) {
|
|
|
30
30
|
const { properties, attributes } = capabilityIR.bindings
|
|
31
31
|
let runtime = replaceRequired(source, '"./shared-runtime.js"', '"./kudzu.js"', "shared runtime import", "binding-runtime.js")
|
|
32
32
|
runtime = replaceRequired(runtime, '"./serialization.js"', '"./kudzu-serialization.js"', "serialization import", "binding-runtime.js")
|
|
33
|
+
if (!capabilityIR.bindings.conditionMounts) runtime = replaceRequired(runtime, ", unmountDom }", " }", "unused conditional unmount import", "binding-runtime.js")
|
|
33
34
|
runtime = replaceRequired(runtime, /const bindingTypes = \[[^\n]+\]/, `const bindingTypes = ${JSON.stringify(properties)}`, "binding properties", "binding-runtime.js")
|
|
34
35
|
const selectors = [...properties.map(target => `[data-k-bind-${target}]`), ...(attributes ? ["[data-k-bind-attrs]"] : [])]
|
|
35
36
|
// The existing generic selector is smaller when all five property kinds are used.
|
|
@@ -54,6 +55,7 @@ export function generateBindingRuntime(source, capabilityIR, navigable) {
|
|
|
54
55
|
"globalThis.__KUDZU_VALUE_BINDINGS__": String(properties.includes("value")),
|
|
55
56
|
"globalThis.__KUDZU_CONDITIONS__": String(capabilityIR.bindings.conditions),
|
|
56
57
|
"globalThis.__KUDZU_CONDITION_STATE__": String(capabilityIR.bindings.conditionState),
|
|
58
|
+
"globalThis.__KUDZU_CONDITION_MOUNTS__": String(capabilityIR.bindings.conditionMounts),
|
|
57
59
|
"globalThis.__KUDZU_SVG_CONDITIONS__": String(capabilityIR.bindings.svgConditions),
|
|
58
60
|
"globalThis.__KUDZU_CAPTURE_STATE__": String(capabilityIR.captures.nestedState)
|
|
59
61
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kudzujs/core",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.34",
|
|
4
4
|
"description": "HTML-first TSX framework with synchronous state semantics and no virtual DOM",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"check": "tsc --noEmit && tsc -p test/fixtures/tsconfig.json --noEmit && node ./bin/kudzu.mjs build",
|
|
51
51
|
"test": "node --test test/project-application.test.mjs && node --test --test-skip-pattern='^establishes the 0\\.17\\.0 notification WebSocket ownership contract$' test/*.test.mjs",
|
|
52
52
|
"test:endurance": "node test/endurance.mjs",
|
|
53
|
-
"test:package": "node test/package-smoke.mjs",
|
|
53
|
+
"test:package": "node test/package-smoke.mjs && node test/create-kudzu-smoke.mjs",
|
|
54
54
|
"benchmark": "node test/performance.mjs",
|
|
55
55
|
"benchmark:keyed": "node test/keyed-performance.mjs",
|
|
56
56
|
"benchmark:commerce": "node test/commerce-build-performance.mjs",
|