@zenithbuild/compiler 1.0.2
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/LICENSE +21 -0
- package/README.md +30 -0
- package/dist/build-analyzer.d.ts +44 -0
- package/dist/build-analyzer.js +87 -0
- package/dist/bundler.d.ts +31 -0
- package/dist/bundler.js +86 -0
- package/dist/core/components/index.d.ts +9 -0
- package/dist/core/components/index.js +13 -0
- package/dist/core/config/index.d.ts +11 -0
- package/dist/core/config/index.js +10 -0
- package/dist/core/config/loader.d.ts +17 -0
- package/dist/core/config/loader.js +60 -0
- package/dist/core/config/types.d.ts +98 -0
- package/dist/core/config/types.js +32 -0
- package/dist/core/index.d.ts +7 -0
- package/dist/core/index.js +6 -0
- package/dist/core/lifecycle/index.d.ts +16 -0
- package/dist/core/lifecycle/index.js +19 -0
- package/dist/core/lifecycle/zen-mount.d.ts +66 -0
- package/dist/core/lifecycle/zen-mount.js +151 -0
- package/dist/core/lifecycle/zen-unmount.d.ts +54 -0
- package/dist/core/lifecycle/zen-unmount.js +76 -0
- package/dist/core/plugins/bridge.d.ts +116 -0
- package/dist/core/plugins/bridge.js +121 -0
- package/dist/core/plugins/index.d.ts +6 -0
- package/dist/core/plugins/index.js +6 -0
- package/dist/core/plugins/registry.d.ts +67 -0
- package/dist/core/plugins/registry.js +113 -0
- package/dist/core/reactivity/index.d.ts +30 -0
- package/dist/core/reactivity/index.js +33 -0
- package/dist/core/reactivity/tracking.d.ts +74 -0
- package/dist/core/reactivity/tracking.js +136 -0
- package/dist/core/reactivity/zen-batch.d.ts +45 -0
- package/dist/core/reactivity/zen-batch.js +54 -0
- package/dist/core/reactivity/zen-effect.d.ts +48 -0
- package/dist/core/reactivity/zen-effect.js +98 -0
- package/dist/core/reactivity/zen-memo.d.ts +43 -0
- package/dist/core/reactivity/zen-memo.js +100 -0
- package/dist/core/reactivity/zen-ref.d.ts +44 -0
- package/dist/core/reactivity/zen-ref.js +34 -0
- package/dist/core/reactivity/zen-signal.d.ts +48 -0
- package/dist/core/reactivity/zen-signal.js +84 -0
- package/dist/core/reactivity/zen-state.d.ts +35 -0
- package/dist/core/reactivity/zen-state.js +147 -0
- package/dist/core/reactivity/zen-untrack.d.ts +38 -0
- package/dist/core/reactivity/zen-untrack.js +41 -0
- package/dist/css/index.d.ts +73 -0
- package/dist/css/index.js +246 -0
- package/dist/discovery/componentDiscovery.d.ts +42 -0
- package/dist/discovery/componentDiscovery.js +56 -0
- package/dist/discovery/layouts.d.ts +13 -0
- package/dist/discovery/layouts.js +41 -0
- package/dist/errors/compilerError.d.ts +31 -0
- package/dist/errors/compilerError.js +51 -0
- package/dist/finalize/finalizeOutput.d.ts +32 -0
- package/dist/finalize/finalizeOutput.js +62 -0
- package/dist/finalize/generateFinalBundle.d.ts +24 -0
- package/dist/finalize/generateFinalBundle.js +68 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.js +51 -0
- package/dist/ir/types.d.ts +181 -0
- package/dist/ir/types.js +8 -0
- package/dist/output/types.d.ts +30 -0
- package/dist/output/types.js +6 -0
- package/dist/parse/detectMapExpressions.d.ts +45 -0
- package/dist/parse/detectMapExpressions.js +77 -0
- package/dist/parse/parseScript.d.ts +8 -0
- package/dist/parse/parseScript.js +36 -0
- package/dist/parse/parseTemplate.d.ts +11 -0
- package/dist/parse/parseTemplate.js +487 -0
- package/dist/parse/parseZenFile.d.ts +11 -0
- package/dist/parse/parseZenFile.js +50 -0
- package/dist/parse/scriptAnalysis.d.ts +25 -0
- package/dist/parse/scriptAnalysis.js +60 -0
- package/dist/parse/trackLoopContext.d.ts +20 -0
- package/dist/parse/trackLoopContext.js +62 -0
- package/dist/parseZenFile.d.ts +10 -0
- package/dist/parseZenFile.js +55 -0
- package/dist/runtime/analyzeAndEmit.d.ts +20 -0
- package/dist/runtime/analyzeAndEmit.js +70 -0
- package/dist/runtime/build.d.ts +6 -0
- package/dist/runtime/build.js +13 -0
- package/dist/runtime/bundle-generator.d.ts +27 -0
- package/dist/runtime/bundle-generator.js +1263 -0
- package/dist/runtime/client-runtime.d.ts +41 -0
- package/dist/runtime/client-runtime.js +397 -0
- package/dist/runtime/dataExposure.d.ts +52 -0
- package/dist/runtime/dataExposure.js +227 -0
- package/dist/runtime/generateDOM.d.ts +21 -0
- package/dist/runtime/generateDOM.js +194 -0
- package/dist/runtime/generateHydrationBundle.d.ts +15 -0
- package/dist/runtime/generateHydrationBundle.js +399 -0
- package/dist/runtime/hydration.d.ts +53 -0
- package/dist/runtime/hydration.js +271 -0
- package/dist/runtime/navigation.d.ts +58 -0
- package/dist/runtime/navigation.js +372 -0
- package/dist/runtime/serve.d.ts +13 -0
- package/dist/runtime/serve.js +76 -0
- package/dist/runtime/thinRuntime.d.ts +23 -0
- package/dist/runtime/thinRuntime.js +158 -0
- package/dist/runtime/transformIR.d.ts +19 -0
- package/dist/runtime/transformIR.js +285 -0
- package/dist/runtime/wrapExpression.d.ts +24 -0
- package/dist/runtime/wrapExpression.js +76 -0
- package/dist/runtime/wrapExpressionWithLoop.d.ts +17 -0
- package/dist/runtime/wrapExpressionWithLoop.js +75 -0
- package/dist/spa-build.d.ts +26 -0
- package/dist/spa-build.js +866 -0
- package/dist/ssg-build.d.ts +32 -0
- package/dist/ssg-build.js +408 -0
- package/dist/test/analyze-emit.test.d.ts +1 -0
- package/dist/test/analyze-emit.test.js +88 -0
- package/dist/test/bundler-contract.test.d.ts +1 -0
- package/dist/test/bundler-contract.test.js +137 -0
- package/dist/test/compiler-authority.test.d.ts +1 -0
- package/dist/test/compiler-authority.test.js +90 -0
- package/dist/test/component-instance-test.d.ts +1 -0
- package/dist/test/component-instance-test.js +115 -0
- package/dist/test/error-native-bridge.test.d.ts +1 -0
- package/dist/test/error-native-bridge.test.js +51 -0
- package/dist/test/error-serialization.test.d.ts +1 -0
- package/dist/test/error-serialization.test.js +38 -0
- package/dist/test/macro-inlining.test.d.ts +1 -0
- package/dist/test/macro-inlining.test.js +178 -0
- package/dist/test/validate-test.d.ts +6 -0
- package/dist/test/validate-test.js +95 -0
- package/dist/transform/classifyExpression.d.ts +46 -0
- package/dist/transform/classifyExpression.js +354 -0
- package/dist/transform/componentResolver.d.ts +15 -0
- package/dist/transform/componentResolver.js +30 -0
- package/dist/transform/expressionTransformer.d.ts +19 -0
- package/dist/transform/expressionTransformer.js +333 -0
- package/dist/transform/fragmentLowering.d.ts +25 -0
- package/dist/transform/fragmentLowering.js +468 -0
- package/dist/transform/layoutProcessor.d.ts +5 -0
- package/dist/transform/layoutProcessor.js +34 -0
- package/dist/transform/transformTemplate.d.ts +11 -0
- package/dist/transform/transformTemplate.js +33 -0
- package/dist/validate/invariants.d.ts +23 -0
- package/dist/validate/invariants.js +55 -0
- package/native/compiler-native/compiler-native.node +0 -0
- package/native/compiler-native/index.d.ts +113 -0
- package/native/compiler-native/index.js +19 -0
- package/native/compiler-native/package.json +19 -0
- package/package.json +49 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zenith Client Runtime - Final Canonical Implementation
|
|
3
|
+
* Satisfies strict reactivity requirements:
|
|
4
|
+
* - Signals are functions (get/set)
|
|
5
|
+
* - State is a Proxy
|
|
6
|
+
* - Effects support cleanup/debounce
|
|
7
|
+
* - Memos are computed signals
|
|
8
|
+
* - Direct DOM updates via fine-grained reactivity
|
|
9
|
+
*/
|
|
10
|
+
export declare function zenSignal<T>(initialValue: T): {
|
|
11
|
+
(newValue?: T): T;
|
|
12
|
+
_isSignal: boolean;
|
|
13
|
+
toString(): string;
|
|
14
|
+
valueOf(): T;
|
|
15
|
+
};
|
|
16
|
+
export declare function zenState<T extends object>(initialObj: T): T;
|
|
17
|
+
export declare function zenEffect(fn: () => void | (() => void), options?: {
|
|
18
|
+
debounce?: number;
|
|
19
|
+
defer?: boolean;
|
|
20
|
+
}): () => void;
|
|
21
|
+
export declare function zenMemo<T>(fn: () => T): {
|
|
22
|
+
(): T;
|
|
23
|
+
_isSignal: boolean;
|
|
24
|
+
};
|
|
25
|
+
export declare function zenRef<T>(initial?: T): {
|
|
26
|
+
current: NonNullable<T> | null;
|
|
27
|
+
};
|
|
28
|
+
export declare function zenBatch(fn: () => void): void;
|
|
29
|
+
export declare function zenUntrack<T>(fn: () => T): T;
|
|
30
|
+
export interface ComponentInstance {
|
|
31
|
+
mountHooks: Array<() => void | (() => void)>;
|
|
32
|
+
}
|
|
33
|
+
export declare function setActiveInstance(inst: ComponentInstance | null): void;
|
|
34
|
+
export declare function zenOnMount(cb: any): void;
|
|
35
|
+
export declare function zenOnUnmount(cb: any): void;
|
|
36
|
+
export declare function triggerMount(inst: ComponentInstance): void;
|
|
37
|
+
export declare function h(tag: string, props: any, ...children: any[]): Element;
|
|
38
|
+
export declare function fragment(children: any): DocumentFragment;
|
|
39
|
+
export declare function zenLoop(sourceFn: () => any[], itemFn: (item: any, idx: number) => Node): DocumentFragment;
|
|
40
|
+
export declare function zenithHydrate(state: any, container?: Element | Document): void;
|
|
41
|
+
export declare function setup(): void;
|
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zenith Client Runtime - Final Canonical Implementation
|
|
3
|
+
* Satisfies strict reactivity requirements:
|
|
4
|
+
* - Signals are functions (get/set)
|
|
5
|
+
* - State is a Proxy
|
|
6
|
+
* - Effects support cleanup/debounce
|
|
7
|
+
* - Memos are computed signals
|
|
8
|
+
* - Direct DOM updates via fine-grained reactivity
|
|
9
|
+
*/
|
|
10
|
+
let currentEffect = null;
|
|
11
|
+
const contextStack = [];
|
|
12
|
+
let batchDepth = 0;
|
|
13
|
+
const pendingEffects = new Set();
|
|
14
|
+
function pushContext(effect) {
|
|
15
|
+
contextStack.push(currentEffect);
|
|
16
|
+
currentEffect = effect;
|
|
17
|
+
}
|
|
18
|
+
function popContext() {
|
|
19
|
+
currentEffect = contextStack.pop();
|
|
20
|
+
}
|
|
21
|
+
function trackDependency(subscribers) {
|
|
22
|
+
if (currentEffect) {
|
|
23
|
+
subscribers.add(currentEffect);
|
|
24
|
+
currentEffect.dependencies.add(subscribers);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function notifySubscribers(subscribers) {
|
|
28
|
+
const effects = Array.from(subscribers);
|
|
29
|
+
for (const effect of effects) {
|
|
30
|
+
if (batchDepth > 0) {
|
|
31
|
+
pendingEffects.add(effect);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
effect.run();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function cleanupEffect(effect) {
|
|
39
|
+
for (const dependency of effect.dependencies) {
|
|
40
|
+
dependency.delete(effect);
|
|
41
|
+
}
|
|
42
|
+
effect.dependencies.clear();
|
|
43
|
+
}
|
|
44
|
+
// === zenSignal ===
|
|
45
|
+
export function zenSignal(initialValue) {
|
|
46
|
+
let value = initialValue;
|
|
47
|
+
const subscribers = new Set();
|
|
48
|
+
function signal(newValue) {
|
|
49
|
+
if (arguments.length === 0) {
|
|
50
|
+
trackDependency(subscribers);
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
if (newValue !== value) {
|
|
54
|
+
value = newValue;
|
|
55
|
+
notifySubscribers(subscribers);
|
|
56
|
+
}
|
|
57
|
+
return value;
|
|
58
|
+
}
|
|
59
|
+
signal._isSignal = true;
|
|
60
|
+
signal.toString = () => String(value);
|
|
61
|
+
signal.valueOf = () => value;
|
|
62
|
+
// .value getter for convenience/compat
|
|
63
|
+
Object.defineProperty(signal, 'value', {
|
|
64
|
+
get: () => signal(),
|
|
65
|
+
set: (v) => signal(v)
|
|
66
|
+
});
|
|
67
|
+
return signal;
|
|
68
|
+
}
|
|
69
|
+
// === zenState ===
|
|
70
|
+
export function zenState(initialObj) {
|
|
71
|
+
const subscribers = new Map();
|
|
72
|
+
function getSubscribers(path) {
|
|
73
|
+
if (!subscribers.has(path)) {
|
|
74
|
+
subscribers.set(path, new Set());
|
|
75
|
+
}
|
|
76
|
+
return subscribers.get(path);
|
|
77
|
+
}
|
|
78
|
+
function createProxy(obj, parentPath = '') {
|
|
79
|
+
if (obj === null || typeof obj !== 'object' || obj._isSignal)
|
|
80
|
+
return obj;
|
|
81
|
+
return new Proxy(obj, {
|
|
82
|
+
get(target, prop) {
|
|
83
|
+
if (typeof prop === 'symbol')
|
|
84
|
+
return target[prop];
|
|
85
|
+
const path = parentPath ? `${parentPath}.${String(prop)}` : String(prop);
|
|
86
|
+
trackDependency(getSubscribers(path));
|
|
87
|
+
const value = target[prop];
|
|
88
|
+
if (value !== null && typeof value === 'object' && !value._isSignal) {
|
|
89
|
+
return createProxy(value, path);
|
|
90
|
+
}
|
|
91
|
+
return value;
|
|
92
|
+
},
|
|
93
|
+
set(target, prop, newValue) {
|
|
94
|
+
if (typeof prop === 'symbol') {
|
|
95
|
+
target[prop] = newValue;
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
const path = parentPath ? `${parentPath}.${String(prop)}` : String(prop);
|
|
99
|
+
const oldValue = target[prop];
|
|
100
|
+
if (oldValue && typeof oldValue === 'function' && oldValue._isSignal) {
|
|
101
|
+
oldValue(newValue);
|
|
102
|
+
}
|
|
103
|
+
else if (oldValue !== newValue) {
|
|
104
|
+
target[prop] = newValue;
|
|
105
|
+
notifySubscribers(getSubscribers(path));
|
|
106
|
+
// Bubble up
|
|
107
|
+
const parts = path.split('.');
|
|
108
|
+
for (let i = parts.length - 1; i >= 0; i--) {
|
|
109
|
+
const pp = parts.slice(0, i).join('.');
|
|
110
|
+
if (pp)
|
|
111
|
+
notifySubscribers(getSubscribers(pp));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return createProxy(initialObj);
|
|
119
|
+
}
|
|
120
|
+
// === zenEffect ===
|
|
121
|
+
export function zenEffect(fn, options = {}) {
|
|
122
|
+
let cleanup;
|
|
123
|
+
let timeout;
|
|
124
|
+
const effect = {
|
|
125
|
+
dependencies: new Set(),
|
|
126
|
+
run: () => {
|
|
127
|
+
if (options.debounce) {
|
|
128
|
+
if (timeout)
|
|
129
|
+
clearTimeout(timeout);
|
|
130
|
+
timeout = setTimeout(execute, options.debounce);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
execute();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
function execute() {
|
|
138
|
+
cleanupEffect(effect);
|
|
139
|
+
pushContext(effect);
|
|
140
|
+
try {
|
|
141
|
+
if (cleanup)
|
|
142
|
+
cleanup();
|
|
143
|
+
cleanup = fn();
|
|
144
|
+
}
|
|
145
|
+
finally {
|
|
146
|
+
popContext();
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (!options.defer)
|
|
150
|
+
execute();
|
|
151
|
+
return () => {
|
|
152
|
+
cleanupEffect(effect);
|
|
153
|
+
if (cleanup)
|
|
154
|
+
cleanup();
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
// === zenMemo ===
|
|
158
|
+
export function zenMemo(fn) {
|
|
159
|
+
const signal = zenSignal(undefined);
|
|
160
|
+
zenEffect(() => { signal(fn()); });
|
|
161
|
+
const memo = () => signal();
|
|
162
|
+
memo._isSignal = true;
|
|
163
|
+
return memo;
|
|
164
|
+
}
|
|
165
|
+
// === zenRef ===
|
|
166
|
+
export function zenRef(initial) {
|
|
167
|
+
return { current: initial || null };
|
|
168
|
+
}
|
|
169
|
+
// === zenBatch ===
|
|
170
|
+
export function zenBatch(fn) {
|
|
171
|
+
batchDepth++;
|
|
172
|
+
try {
|
|
173
|
+
fn();
|
|
174
|
+
}
|
|
175
|
+
finally {
|
|
176
|
+
batchDepth--;
|
|
177
|
+
if (batchDepth === 0) {
|
|
178
|
+
const effects = Array.from(pendingEffects);
|
|
179
|
+
pendingEffects.clear();
|
|
180
|
+
effects.forEach(e => e.run());
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
export function zenUntrack(fn) {
|
|
185
|
+
pushContext(null);
|
|
186
|
+
try {
|
|
187
|
+
return fn();
|
|
188
|
+
}
|
|
189
|
+
finally {
|
|
190
|
+
popContext();
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
let activeInstance = null;
|
|
194
|
+
export function setActiveInstance(inst) { activeInstance = inst; }
|
|
195
|
+
export function zenOnMount(cb) {
|
|
196
|
+
if (activeInstance)
|
|
197
|
+
activeInstance.mountHooks.push(cb);
|
|
198
|
+
// Fallback: if no active instance (e.g. top level), run immediately?
|
|
199
|
+
// Better to strict scope it, but for safety in simple usages:
|
|
200
|
+
else if (typeof window !== 'undefined' && document.readyState === 'complete') {
|
|
201
|
+
// cb(); // Uncomment if lax behavior desired
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
export function zenOnUnmount(cb) {
|
|
205
|
+
// Placeholder: requires unmount hooks in instance
|
|
206
|
+
}
|
|
207
|
+
export function triggerMount(inst) {
|
|
208
|
+
if (inst && inst.mountHooks) {
|
|
209
|
+
inst.mountHooks.forEach(cb => {
|
|
210
|
+
const cleanup = cb();
|
|
211
|
+
// TODO: Store cleanup for unmount
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
// === Rendering & Hydration ===
|
|
216
|
+
const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
|
|
217
|
+
const SVG_TAGS = new Set([
|
|
218
|
+
'svg', 'path', 'circle', 'ellipse', 'line', 'polyline', 'polygon', 'rect',
|
|
219
|
+
'g', 'defs', 'use', 'symbol', 'clipPath', 'mask', 'pattern', 'marker',
|
|
220
|
+
'linearGradient', 'radialGradient', 'stop', 'filter', 'feGaussianBlur',
|
|
221
|
+
'feOffset', 'feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite',
|
|
222
|
+
'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feFlood',
|
|
223
|
+
'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feImage', 'feMerge', 'feMergeNode',
|
|
224
|
+
'feMorphology', 'fePointLight', 'feSpotLight', 'feSpecularLighting', 'feTile',
|
|
225
|
+
'feTurbulence', 'foreignObject', 'image', 'switch', 'text', 'tspan', 'textPath',
|
|
226
|
+
'title', 'desc', 'metadata', 'a', 'view', 'animate', 'animateMotion',
|
|
227
|
+
'animateTransform', 'set', 'mpath'
|
|
228
|
+
]);
|
|
229
|
+
// Track current namespace context for nested elements
|
|
230
|
+
let currentNamespace = null;
|
|
231
|
+
export function h(tag, props, ...children) {
|
|
232
|
+
// Determine if this element should be in SVG namespace
|
|
233
|
+
const isSvgTag = SVG_TAGS.has(tag) || SVG_TAGS.has(tag.toLowerCase());
|
|
234
|
+
const useSvgNamespace = isSvgTag || currentNamespace === SVG_NAMESPACE;
|
|
235
|
+
// Create element with correct namespace
|
|
236
|
+
const el = useSvgNamespace
|
|
237
|
+
? document.createElementNS(SVG_NAMESPACE, tag)
|
|
238
|
+
: document.createElement(tag);
|
|
239
|
+
// Track namespace context for children
|
|
240
|
+
const previousNamespace = currentNamespace;
|
|
241
|
+
if (tag === 'svg' || tag === 'SVG') {
|
|
242
|
+
currentNamespace = SVG_NAMESPACE;
|
|
243
|
+
}
|
|
244
|
+
if (props) {
|
|
245
|
+
for (const [key, val] of Object.entries(props)) {
|
|
246
|
+
if (key === 'ref') {
|
|
247
|
+
if (val && typeof val === 'object' && 'current' in val)
|
|
248
|
+
val.current = el;
|
|
249
|
+
else if (typeof val === 'string') {
|
|
250
|
+
const state = window.__ZENITH_STATE__;
|
|
251
|
+
if (state && state[val] && typeof state[val] === 'object' && 'current' in state[val])
|
|
252
|
+
state[val].current = el;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
else if (key.startsWith('on') && typeof val === 'function') {
|
|
256
|
+
el.addEventListener(key.slice(2).toLowerCase(), (e) => {
|
|
257
|
+
// Check if val returns a function (expression wrapper) or is the handler
|
|
258
|
+
const res = val(e, el);
|
|
259
|
+
if (typeof res === 'function')
|
|
260
|
+
res(e, el);
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
else if (typeof val === 'function') {
|
|
264
|
+
zenEffect(() => { updateAttr(el, key, val()); });
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
updateAttr(el, key, val);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
const spread = (items) => items.reduce((acc, v) => acc.concat(Array.isArray(v) ? spread(v) : v), []);
|
|
272
|
+
spread(children).forEach(child => {
|
|
273
|
+
if (typeof child === 'function') {
|
|
274
|
+
// For reactive expressions, we need a placeholder that can be updated
|
|
275
|
+
// The placeholder is a comment node that marks where content should go
|
|
276
|
+
const placeholder = document.createComment('expr');
|
|
277
|
+
el.appendChild(placeholder);
|
|
278
|
+
let currentNodes = [];
|
|
279
|
+
zenEffect(() => {
|
|
280
|
+
const result = child();
|
|
281
|
+
// Remove old nodes
|
|
282
|
+
currentNodes.forEach(n => { if (n.parentNode)
|
|
283
|
+
n.parentNode.removeChild(n); });
|
|
284
|
+
currentNodes = [];
|
|
285
|
+
if (result == null) {
|
|
286
|
+
// null/undefined - render nothing
|
|
287
|
+
}
|
|
288
|
+
else if (result instanceof Node) {
|
|
289
|
+
// DOM node - insert it
|
|
290
|
+
placeholder.before(result);
|
|
291
|
+
currentNodes = [result];
|
|
292
|
+
}
|
|
293
|
+
else if (Array.isArray(result)) {
|
|
294
|
+
// Array of nodes/strings
|
|
295
|
+
result.forEach(item => {
|
|
296
|
+
const node = item instanceof Node ? item : document.createTextNode(String(item));
|
|
297
|
+
placeholder.before(node);
|
|
298
|
+
currentNodes.push(node);
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
// Primitive (string, number) - create text node
|
|
303
|
+
const textNode = document.createTextNode(String(result));
|
|
304
|
+
placeholder.before(textNode);
|
|
305
|
+
currentNodes = [textNode];
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
else {
|
|
310
|
+
el.appendChild(child instanceof Node ? child : document.createTextNode(String(child)));
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
// Restore previous namespace context
|
|
314
|
+
currentNamespace = previousNamespace;
|
|
315
|
+
return el;
|
|
316
|
+
}
|
|
317
|
+
function updateAttr(el, key, val) {
|
|
318
|
+
if (key === 'class' || key === 'className') {
|
|
319
|
+
// SVG uses className.baseVal, HTML uses className directly
|
|
320
|
+
if ('className' in el && typeof el.className === 'object') {
|
|
321
|
+
el.className.baseVal = String(val || '');
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
el.className = String(val || '');
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
else if (key === 'style' && typeof val === 'object')
|
|
328
|
+
Object.assign(el.style, val);
|
|
329
|
+
else if (val == null || val === false)
|
|
330
|
+
el.removeAttribute(key);
|
|
331
|
+
else
|
|
332
|
+
el.setAttribute(key, String(val));
|
|
333
|
+
}
|
|
334
|
+
export function fragment(children) {
|
|
335
|
+
const frag = document.createDocumentFragment();
|
|
336
|
+
const items = typeof children === 'function' ? children() : children;
|
|
337
|
+
const spread = (its) => its.reduce((acc, v) => acc.concat(Array.isArray(v) ? spread(v) : v), []);
|
|
338
|
+
spread(Array.isArray(items) ? items : [items]).forEach(item => {
|
|
339
|
+
frag.appendChild(item instanceof Node ? item : document.createTextNode(String(item)));
|
|
340
|
+
});
|
|
341
|
+
return frag;
|
|
342
|
+
}
|
|
343
|
+
export function zenLoop(sourceFn, itemFn) {
|
|
344
|
+
const start = document.createComment('loop:start');
|
|
345
|
+
const end = document.createComment('loop:end');
|
|
346
|
+
const frag = document.createDocumentFragment();
|
|
347
|
+
frag.append(start, end);
|
|
348
|
+
zenEffect(() => {
|
|
349
|
+
const items = sourceFn() || [];
|
|
350
|
+
let curr = start.nextSibling;
|
|
351
|
+
while (curr && curr !== end) {
|
|
352
|
+
const next = curr.nextSibling;
|
|
353
|
+
curr.remove();
|
|
354
|
+
curr = next;
|
|
355
|
+
}
|
|
356
|
+
items.forEach((item, i) => end.before(itemFn(item, i)));
|
|
357
|
+
});
|
|
358
|
+
return frag;
|
|
359
|
+
}
|
|
360
|
+
export function zenithHydrate(state, container = document) {
|
|
361
|
+
const ir = window.canonicalIR;
|
|
362
|
+
if (!ir)
|
|
363
|
+
return;
|
|
364
|
+
window.__ZENITH_STATE__ = state;
|
|
365
|
+
const nodes = ir(state);
|
|
366
|
+
const mount = container === document ? document.body : container;
|
|
367
|
+
mount.innerHTML = '';
|
|
368
|
+
const arr = Array.isArray(nodes) ? nodes : [nodes];
|
|
369
|
+
arr.forEach(n => {
|
|
370
|
+
if (n == null || n === false)
|
|
371
|
+
return;
|
|
372
|
+
// If it's a full <html> node, we might need to be more careful,
|
|
373
|
+
// but for now let's just avoid stringifying nulls.
|
|
374
|
+
mount.appendChild(n instanceof Node ? n : document.createTextNode(String(n)));
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
// === Global Setup ===
|
|
378
|
+
export function setup() {
|
|
379
|
+
if (typeof window === 'undefined')
|
|
380
|
+
return;
|
|
381
|
+
const w = window;
|
|
382
|
+
w.__zenith = { h, fragment, loop: zenLoop, state: zenState, signal: zenSignal, effect: zenEffect, memo: zenMemo, ref: zenRef, batch: zenBatch, onMount: zenOnMount, setActiveInstance, triggerMount, spread_children: (a) => a };
|
|
383
|
+
w.zenithHydrate = zenithHydrate;
|
|
384
|
+
// Expose globals for imported usage
|
|
385
|
+
w.zenSignal = zenSignal;
|
|
386
|
+
w.zenState = zenState;
|
|
387
|
+
w.zenEffect = zenEffect;
|
|
388
|
+
w.zenMemo = zenMemo;
|
|
389
|
+
w.zenRef = zenRef;
|
|
390
|
+
w.zenBatch = zenBatch;
|
|
391
|
+
w.zenUntrack = zenUntrack;
|
|
392
|
+
w.zenOnMount = zenOnMount;
|
|
393
|
+
// [ZENITH-NATIVE] zenOrder: Scheduling primitive
|
|
394
|
+
w.zenOrder = (fn) => { if (typeof fn === 'function')
|
|
395
|
+
fn(); };
|
|
396
|
+
}
|
|
397
|
+
setup();
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Explicit Data Exposure Analysis
|
|
3
|
+
*
|
|
4
|
+
* Phase 6: Analyzes expressions to detect data dependencies and ensure
|
|
5
|
+
* all data references are explicit (loader, props, stores) rather than implicit globals
|
|
6
|
+
*/
|
|
7
|
+
import type { ExpressionIR } from '../ir/types';
|
|
8
|
+
/**
|
|
9
|
+
* Data dependency information for an expression
|
|
10
|
+
*/
|
|
11
|
+
export interface ExpressionDataDependencies {
|
|
12
|
+
expressionId: string;
|
|
13
|
+
usesLoaderData: boolean;
|
|
14
|
+
usesProps: boolean;
|
|
15
|
+
usesStores: boolean;
|
|
16
|
+
usesState: boolean;
|
|
17
|
+
loaderProperties: string[];
|
|
18
|
+
propNames: string[];
|
|
19
|
+
storeNames: string[];
|
|
20
|
+
stateProperties: string[];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Analyze an expression to detect its data dependencies
|
|
24
|
+
*
|
|
25
|
+
* This is a simple heuristic-based analyzer that looks for patterns like:
|
|
26
|
+
* - user.name, user.email → loader data
|
|
27
|
+
* - props.title, props.showWelcome → props
|
|
28
|
+
* - stores.cart, stores.notifications → stores
|
|
29
|
+
* - count, isLoading → state (top-level properties)
|
|
30
|
+
*/
|
|
31
|
+
export declare function analyzeExpressionDependencies(expr: ExpressionIR, declaredLoaderProps?: string[], declaredProps?: string[], declaredStores?: string[]): ExpressionDataDependencies;
|
|
32
|
+
/**
|
|
33
|
+
* Validate that all referenced data exists
|
|
34
|
+
*/
|
|
35
|
+
export declare function validateDataDependencies(dependencies: ExpressionDataDependencies, filePath: string, declaredLoaderProps?: string[], declaredProps?: string[], declaredStores?: string[]): void;
|
|
36
|
+
/**
|
|
37
|
+
* Transform expression code to use explicit data arguments
|
|
38
|
+
*
|
|
39
|
+
* Converts patterns like:
|
|
40
|
+
* - user.name → loaderData.user.name
|
|
41
|
+
* - title → props.title (if declared as prop)
|
|
42
|
+
* - cart.items → stores.cart.items
|
|
43
|
+
*/
|
|
44
|
+
export declare function transformExpressionCode(code: string, dependencies: ExpressionDataDependencies, declaredProps?: string[]): string;
|
|
45
|
+
/**
|
|
46
|
+
* Generate expression wrapper with explicit data arguments
|
|
47
|
+
*/
|
|
48
|
+
export declare function generateExplicitExpressionWrapper(expr: ExpressionIR, dependencies: ExpressionDataDependencies): string;
|
|
49
|
+
/**
|
|
50
|
+
* Analyze all expressions in a template
|
|
51
|
+
*/
|
|
52
|
+
export declare function analyzeAllExpressions(expressions: ExpressionIR[], filePath: string, declaredLoaderProps?: string[], declaredProps?: string[], declaredStores?: string[]): ExpressionDataDependencies[];
|