@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,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zenith CSS Compiler Module
|
|
3
|
+
*
|
|
4
|
+
* Compiler-owned CSS processing that integrates Tailwind CSS v4 JIT
|
|
5
|
+
* at compile time. This module ensures:
|
|
6
|
+
*
|
|
7
|
+
* 1. All CSS is processed at build time (no runtime generation)
|
|
8
|
+
* 2. Tailwind sees all .zen templates for class scanning
|
|
9
|
+
* 3. HMR support for instant CSS updates in dev mode
|
|
10
|
+
* 4. Deterministic, cacheable output for production
|
|
11
|
+
*
|
|
12
|
+
* Per Zenith CSS Directive: The compiler owns styles.
|
|
13
|
+
*/
|
|
14
|
+
import { spawn, spawnSync } from 'child_process';
|
|
15
|
+
import path from 'path';
|
|
16
|
+
import fs from 'fs';
|
|
17
|
+
// ============================================
|
|
18
|
+
// CSS Compilation
|
|
19
|
+
// ============================================
|
|
20
|
+
/**
|
|
21
|
+
* Compile CSS using Tailwind CSS v4 CLI
|
|
22
|
+
*
|
|
23
|
+
* This function synchronously compiles CSS for use in:
|
|
24
|
+
* - Dev server startup
|
|
25
|
+
* - SSG build
|
|
26
|
+
* - On-demand recompilation
|
|
27
|
+
*
|
|
28
|
+
* @param options Compilation options
|
|
29
|
+
* @returns Compiled CSS result
|
|
30
|
+
*/
|
|
31
|
+
export function compileCss(options) {
|
|
32
|
+
const startTime = performance.now();
|
|
33
|
+
const { input, output, minify = false } = options;
|
|
34
|
+
// Validate input exists
|
|
35
|
+
if (!fs.existsSync(input)) {
|
|
36
|
+
return {
|
|
37
|
+
css: '',
|
|
38
|
+
duration: 0,
|
|
39
|
+
success: false,
|
|
40
|
+
error: `CSS input file not found: ${input}`
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
// Build Tailwind CLI arguments
|
|
45
|
+
const args = [
|
|
46
|
+
'@tailwindcss/cli',
|
|
47
|
+
'-i', input
|
|
48
|
+
];
|
|
49
|
+
// For in-memory compilation, use stdout
|
|
50
|
+
const useStdout = output === ':memory:';
|
|
51
|
+
if (!useStdout) {
|
|
52
|
+
args.push('-o', output);
|
|
53
|
+
}
|
|
54
|
+
if (minify) {
|
|
55
|
+
args.push('--minify');
|
|
56
|
+
}
|
|
57
|
+
// Execute Tailwind CLI synchronously
|
|
58
|
+
const result = spawnSync('bunx', args, {
|
|
59
|
+
cwd: path.dirname(input),
|
|
60
|
+
encoding: 'utf-8',
|
|
61
|
+
stdio: useStdout ? ['pipe', 'pipe', 'pipe'] : ['pipe', 'inherit', 'pipe'],
|
|
62
|
+
env: { ...process.env }
|
|
63
|
+
});
|
|
64
|
+
const duration = Math.round(performance.now() - startTime);
|
|
65
|
+
if (result.status !== 0) {
|
|
66
|
+
const errorMsg = result.stderr?.toString() || 'Unknown compilation error';
|
|
67
|
+
return {
|
|
68
|
+
css: '',
|
|
69
|
+
duration,
|
|
70
|
+
success: false,
|
|
71
|
+
error: `Tailwind compilation failed: ${errorMsg}`
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
// Get CSS content
|
|
75
|
+
let css = '';
|
|
76
|
+
if (useStdout) {
|
|
77
|
+
css = result.stdout?.toString() || '';
|
|
78
|
+
}
|
|
79
|
+
else if (fs.existsSync(output)) {
|
|
80
|
+
css = fs.readFileSync(output, 'utf-8');
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
css,
|
|
84
|
+
duration,
|
|
85
|
+
success: true
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
return {
|
|
90
|
+
css: '',
|
|
91
|
+
duration: Math.round(performance.now() - startTime),
|
|
92
|
+
success: false,
|
|
93
|
+
error: error.message
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Compile CSS asynchronously (non-blocking)
|
|
99
|
+
*
|
|
100
|
+
* Used for HMR updates where we don't want to block the main thread.
|
|
101
|
+
*/
|
|
102
|
+
export async function compileCssAsync(options) {
|
|
103
|
+
return new Promise((resolve) => {
|
|
104
|
+
const startTime = performance.now();
|
|
105
|
+
const { input, output, minify = false } = options;
|
|
106
|
+
if (!fs.existsSync(input)) {
|
|
107
|
+
resolve({
|
|
108
|
+
css: '',
|
|
109
|
+
duration: 0,
|
|
110
|
+
success: false,
|
|
111
|
+
error: `CSS input file not found: ${input}`
|
|
112
|
+
});
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const args = ['@tailwindcss/cli', '-i', input];
|
|
116
|
+
const useStdout = output === ':memory:';
|
|
117
|
+
if (!useStdout) {
|
|
118
|
+
args.push('-o', output);
|
|
119
|
+
}
|
|
120
|
+
if (minify) {
|
|
121
|
+
args.push('--minify');
|
|
122
|
+
}
|
|
123
|
+
const child = spawn('bunx', args, {
|
|
124
|
+
cwd: path.dirname(input),
|
|
125
|
+
stdio: useStdout ? ['pipe', 'pipe', 'pipe'] : ['pipe', 'inherit', 'pipe'],
|
|
126
|
+
env: { ...process.env }
|
|
127
|
+
});
|
|
128
|
+
let stdout = '';
|
|
129
|
+
let stderr = '';
|
|
130
|
+
if (useStdout && child.stdout) {
|
|
131
|
+
child.stdout.on('data', (data) => { stdout += data.toString(); });
|
|
132
|
+
}
|
|
133
|
+
if (child.stderr) {
|
|
134
|
+
child.stderr.on('data', (data) => { stderr += data.toString(); });
|
|
135
|
+
}
|
|
136
|
+
child.on('close', (code) => {
|
|
137
|
+
const duration = Math.round(performance.now() - startTime);
|
|
138
|
+
if (code !== 0) {
|
|
139
|
+
resolve({
|
|
140
|
+
css: '',
|
|
141
|
+
duration,
|
|
142
|
+
success: false,
|
|
143
|
+
error: `Tailwind compilation failed: ${stderr}`
|
|
144
|
+
});
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
let css = '';
|
|
148
|
+
if (useStdout) {
|
|
149
|
+
css = stdout;
|
|
150
|
+
}
|
|
151
|
+
else if (fs.existsSync(output)) {
|
|
152
|
+
css = fs.readFileSync(output, 'utf-8');
|
|
153
|
+
}
|
|
154
|
+
resolve({
|
|
155
|
+
css,
|
|
156
|
+
duration,
|
|
157
|
+
success: true
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
child.on('error', (err) => {
|
|
161
|
+
resolve({
|
|
162
|
+
css: '',
|
|
163
|
+
duration: Math.round(performance.now() - startTime),
|
|
164
|
+
success: false,
|
|
165
|
+
error: err.message
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Watch CSS and source files for changes, recompile on change
|
|
172
|
+
*
|
|
173
|
+
* This is used by the dev server for HMR support.
|
|
174
|
+
* It watches both the CSS entry point AND all .zen files
|
|
175
|
+
* that Tailwind scans for class names.
|
|
176
|
+
*/
|
|
177
|
+
export function watchCss(options) {
|
|
178
|
+
const { input, output, minify, onChange, debounce = 100 } = options;
|
|
179
|
+
let timeout = null;
|
|
180
|
+
let isCompiling = false;
|
|
181
|
+
const recompile = async () => {
|
|
182
|
+
if (isCompiling)
|
|
183
|
+
return;
|
|
184
|
+
isCompiling = true;
|
|
185
|
+
const result = await compileCssAsync({ input, output, minify });
|
|
186
|
+
onChange(result);
|
|
187
|
+
isCompiling = false;
|
|
188
|
+
};
|
|
189
|
+
const debouncedRecompile = () => {
|
|
190
|
+
if (timeout)
|
|
191
|
+
clearTimeout(timeout);
|
|
192
|
+
timeout = setTimeout(recompile, debounce);
|
|
193
|
+
};
|
|
194
|
+
// Watch the styles directory
|
|
195
|
+
const stylesDir = path.dirname(input);
|
|
196
|
+
const stylesWatcher = fs.watch(stylesDir, { recursive: true }, (event, filename) => {
|
|
197
|
+
if (filename?.endsWith('.css')) {
|
|
198
|
+
debouncedRecompile();
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
// Watch source files that Tailwind scans (for class changes)
|
|
202
|
+
// This assumes standard Zenith structure: src/pages, src/components, src/layouts
|
|
203
|
+
const srcDir = path.resolve(stylesDir, '..');
|
|
204
|
+
let srcWatcher = null;
|
|
205
|
+
if (fs.existsSync(srcDir)) {
|
|
206
|
+
srcWatcher = fs.watch(srcDir, { recursive: true }, (event, filename) => {
|
|
207
|
+
if (filename?.endsWith('.zen') || filename?.endsWith('.tsx') || filename?.endsWith('.jsx')) {
|
|
208
|
+
debouncedRecompile();
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
// Return cleanup function
|
|
213
|
+
return () => {
|
|
214
|
+
if (timeout)
|
|
215
|
+
clearTimeout(timeout);
|
|
216
|
+
stylesWatcher.close();
|
|
217
|
+
srcWatcher?.close();
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
// ============================================
|
|
221
|
+
// Path Utilities
|
|
222
|
+
// ============================================
|
|
223
|
+
/**
|
|
224
|
+
* Resolve the canonical globals.css path for a Zenith project
|
|
225
|
+
*/
|
|
226
|
+
export function resolveGlobalsCss(projectRoot) {
|
|
227
|
+
// Check for globals.css (canonical)
|
|
228
|
+
const globalsPath = path.join(projectRoot, 'src', 'styles', 'globals.css');
|
|
229
|
+
if (fs.existsSync(globalsPath))
|
|
230
|
+
return globalsPath;
|
|
231
|
+
// Check for global.css (legacy)
|
|
232
|
+
const globalPath = path.join(projectRoot, 'src', 'styles', 'global.css');
|
|
233
|
+
if (fs.existsSync(globalPath))
|
|
234
|
+
return globalPath;
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Get the output path for compiled CSS
|
|
239
|
+
*/
|
|
240
|
+
export function getCompiledCssPath(projectRoot, mode) {
|
|
241
|
+
if (mode === 'build') {
|
|
242
|
+
return path.join(projectRoot, 'dist', 'assets', 'styles.css');
|
|
243
|
+
}
|
|
244
|
+
// In dev mode, we use in-memory compilation
|
|
245
|
+
return ':memory:';
|
|
246
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component Discovery
|
|
3
|
+
*
|
|
4
|
+
* Discovers and catalogs components in a Zenith project
|
|
5
|
+
* Similar to layout discovery but for reusable components
|
|
6
|
+
*/
|
|
7
|
+
import type { TemplateNode, ExpressionIR } from '../ir/types';
|
|
8
|
+
export interface SlotDefinition {
|
|
9
|
+
name: string | null;
|
|
10
|
+
location: {
|
|
11
|
+
line: number;
|
|
12
|
+
column: number;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export interface ComponentMetadata {
|
|
16
|
+
name: string;
|
|
17
|
+
path: string;
|
|
18
|
+
template: string;
|
|
19
|
+
nodes: TemplateNode[];
|
|
20
|
+
expressions: ExpressionIR[];
|
|
21
|
+
slots: SlotDefinition[];
|
|
22
|
+
props: string[];
|
|
23
|
+
styles: string[];
|
|
24
|
+
script: string | null;
|
|
25
|
+
scriptAttributes: Record<string, string> | null;
|
|
26
|
+
hasScript: boolean;
|
|
27
|
+
hasStyles: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Discover all components in a directory
|
|
31
|
+
* @param baseDir - Base directory to search (e.g., src/components)
|
|
32
|
+
* @returns Map of component name to metadata
|
|
33
|
+
*/
|
|
34
|
+
export declare function discoverComponents(baseDir: string): Map<string, ComponentMetadata>;
|
|
35
|
+
/**
|
|
36
|
+
* Use native bridge for tag name checks
|
|
37
|
+
*/
|
|
38
|
+
export declare function isComponentTag(tagName: string): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Get component metadata by name
|
|
41
|
+
*/
|
|
42
|
+
export declare function getComponent(components: Map<string, ComponentMetadata>, name: string): ComponentMetadata | undefined;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component Discovery
|
|
3
|
+
*
|
|
4
|
+
* Discovers and catalogs components in a Zenith project
|
|
5
|
+
* Similar to layout discovery but for reusable components
|
|
6
|
+
*/
|
|
7
|
+
let native;
|
|
8
|
+
try {
|
|
9
|
+
try {
|
|
10
|
+
native = require('../../native/compiler-native');
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
native = require('../../native/compiler-native/index.js');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
catch (e) {
|
|
17
|
+
// Bridge load handled elsewhere
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Discover all components in a directory
|
|
21
|
+
* @param baseDir - Base directory to search (e.g., src/components)
|
|
22
|
+
* @returns Map of component name to metadata
|
|
23
|
+
*/
|
|
24
|
+
export function discoverComponents(baseDir) {
|
|
25
|
+
if (native && native.discoverComponentsNative) {
|
|
26
|
+
try {
|
|
27
|
+
const raw = native.discoverComponentsNative(baseDir);
|
|
28
|
+
// The native function returns a Map-like object or Record
|
|
29
|
+
const components = new Map();
|
|
30
|
+
for (const [name, metadata] of Object.entries(raw)) {
|
|
31
|
+
components.set(name, metadata);
|
|
32
|
+
}
|
|
33
|
+
return components;
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
console.warn(`[Zenith Native] Discovery failed for ${baseDir}: ${error.message}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Fallback or empty if native fails (bridge is required for performance)
|
|
40
|
+
return new Map();
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Use native bridge for tag name checks
|
|
44
|
+
*/
|
|
45
|
+
export function isComponentTag(tagName) {
|
|
46
|
+
if (native && native.isComponentTagNative) {
|
|
47
|
+
return native.isComponentTagNative(tagName);
|
|
48
|
+
}
|
|
49
|
+
return tagName.length > 0 && tagName[0] === tagName[0]?.toUpperCase();
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Get component metadata by name
|
|
53
|
+
*/
|
|
54
|
+
export function getComponent(components, name) {
|
|
55
|
+
return components.get(name);
|
|
56
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface LayoutMetadata {
|
|
2
|
+
name: string;
|
|
3
|
+
filePath: string;
|
|
4
|
+
props: string[];
|
|
5
|
+
states: Map<string, string>;
|
|
6
|
+
html: string;
|
|
7
|
+
scripts: string[];
|
|
8
|
+
styles: string[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Discover layouts in a directory
|
|
12
|
+
*/
|
|
13
|
+
export declare function discoverLayouts(layoutsDir: string): Map<string, LayoutMetadata>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
let native;
|
|
2
|
+
try {
|
|
3
|
+
try {
|
|
4
|
+
native = require('../../native/compiler-native');
|
|
5
|
+
}
|
|
6
|
+
catch {
|
|
7
|
+
native = require('../../native/compiler-native/index.js');
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
catch (e) {
|
|
11
|
+
// Bridge load handled elsewhere
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Discover layouts in a directory
|
|
15
|
+
*/
|
|
16
|
+
export function discoverLayouts(layoutsDir) {
|
|
17
|
+
if (native && native.discoverLayoutsNative) {
|
|
18
|
+
try {
|
|
19
|
+
const raw = native.discoverLayoutsNative(layoutsDir);
|
|
20
|
+
const layouts = new Map();
|
|
21
|
+
for (const [name, metadata] of Object.entries(raw)) {
|
|
22
|
+
// Adjust for Rust's camelCase vs Map mapping if needed
|
|
23
|
+
const meta = metadata;
|
|
24
|
+
layouts.set(name, {
|
|
25
|
+
name: meta.name,
|
|
26
|
+
filePath: meta.filePath,
|
|
27
|
+
props: meta.props,
|
|
28
|
+
states: new Map(Object.entries(meta.states || {})),
|
|
29
|
+
html: meta.html,
|
|
30
|
+
scripts: meta.scripts,
|
|
31
|
+
styles: meta.styles
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return layouts;
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
console.warn(`[Zenith Native] Layout discovery failed for ${layoutsDir}: ${error.message}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return new Map();
|
|
41
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compiler Error Handling
|
|
3
|
+
*
|
|
4
|
+
* Compiler errors with source location information
|
|
5
|
+
*/
|
|
6
|
+
export declare class CompilerError extends Error {
|
|
7
|
+
file: string;
|
|
8
|
+
line: number;
|
|
9
|
+
column: number;
|
|
10
|
+
errorType: string;
|
|
11
|
+
context?: string;
|
|
12
|
+
hints: string[];
|
|
13
|
+
code?: string;
|
|
14
|
+
constructor(message: string, file: string, line: number, column: number, errorType?: string, context?: string, hints?: string[], code?: string);
|
|
15
|
+
toString(): string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Invariant Error
|
|
19
|
+
*
|
|
20
|
+
* Thrown when a Zenith compiler invariant is violated.
|
|
21
|
+
* Invariants are non-negotiable rules that guarantee correct behavior.
|
|
22
|
+
*
|
|
23
|
+
* If an invariant fails, the compiler is at fault — not the user.
|
|
24
|
+
* The user receives a clear explanation of what is forbidden and why.
|
|
25
|
+
*/
|
|
26
|
+
export declare class InvariantError extends CompilerError {
|
|
27
|
+
invariantId: string;
|
|
28
|
+
guarantee: string;
|
|
29
|
+
constructor(invariantId: string, message: string, guarantee: string, file: string, line: number, column: number, context?: string, hints?: string[]);
|
|
30
|
+
toString(): string;
|
|
31
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compiler Error Handling
|
|
3
|
+
*
|
|
4
|
+
* Compiler errors with source location information
|
|
5
|
+
*/
|
|
6
|
+
export class CompilerError extends Error {
|
|
7
|
+
file;
|
|
8
|
+
line;
|
|
9
|
+
column;
|
|
10
|
+
errorType;
|
|
11
|
+
context;
|
|
12
|
+
hints;
|
|
13
|
+
code;
|
|
14
|
+
constructor(message, file, line, column, errorType = 'COMPILER_ERROR', context, hints = [], code) {
|
|
15
|
+
super(`${file}:${line}:${column} ${message}`);
|
|
16
|
+
this.name = 'CompilerError';
|
|
17
|
+
this.file = file;
|
|
18
|
+
this.line = line;
|
|
19
|
+
this.column = column;
|
|
20
|
+
this.errorType = errorType;
|
|
21
|
+
this.context = context;
|
|
22
|
+
this.hints = hints;
|
|
23
|
+
this.code = code;
|
|
24
|
+
}
|
|
25
|
+
toString() {
|
|
26
|
+
return `${this.file}:${this.line}:${this.column} [${this.errorType}] ${this.message}`;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Invariant Error
|
|
31
|
+
*
|
|
32
|
+
* Thrown when a Zenith compiler invariant is violated.
|
|
33
|
+
* Invariants are non-negotiable rules that guarantee correct behavior.
|
|
34
|
+
*
|
|
35
|
+
* If an invariant fails, the compiler is at fault — not the user.
|
|
36
|
+
* The user receives a clear explanation of what is forbidden and why.
|
|
37
|
+
*/
|
|
38
|
+
export class InvariantError extends CompilerError {
|
|
39
|
+
invariantId;
|
|
40
|
+
guarantee;
|
|
41
|
+
constructor(invariantId, message, guarantee, file, line, column, context, hints = []) {
|
|
42
|
+
super(`[${invariantId}] ${message}\n\n Zenith Guarantee: ${guarantee}`, file, line, column, 'COMPILER_INVARIANT_VIOLATION', context, hints, invariantId);
|
|
43
|
+
this.name = 'InvariantError';
|
|
44
|
+
this.invariantId = invariantId;
|
|
45
|
+
this.guarantee = guarantee;
|
|
46
|
+
this.code = invariantId;
|
|
47
|
+
}
|
|
48
|
+
toString() {
|
|
49
|
+
return `${this.file}:${this.line}:${this.column} [${this.invariantId}] ${this.message}`;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finalize Output
|
|
3
|
+
*
|
|
4
|
+
* NATIVE BRIDGE: Delegates ALL finalization (Phase 8/9/10) to Rust (`native/compiler-native/src/finalize.rs`).
|
|
5
|
+
*/
|
|
6
|
+
import type { CompiledTemplate } from '../output/types';
|
|
7
|
+
import type { ZenIR, BundlePlan } from '../ir/types';
|
|
8
|
+
/**
|
|
9
|
+
* Finalized output ready for browser
|
|
10
|
+
*/
|
|
11
|
+
export interface FinalizedOutput {
|
|
12
|
+
html: string;
|
|
13
|
+
js: string;
|
|
14
|
+
npmImports: string;
|
|
15
|
+
styles: string[];
|
|
16
|
+
hasErrors: boolean;
|
|
17
|
+
errors: string[];
|
|
18
|
+
/** Compiler-emitted bundling plan. If present, bundling MUST occur. If absent, bundling MUST NOT occur. */
|
|
19
|
+
bundlePlan?: BundlePlan;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Finalize compiler output (Native Bridge)
|
|
23
|
+
*
|
|
24
|
+
* @param ir - Intermediate representation
|
|
25
|
+
* @param compiled - Compiled template
|
|
26
|
+
* @returns Finalized output
|
|
27
|
+
*/
|
|
28
|
+
export declare function finalizeOutput(ir: ZenIR, compiled: CompiledTemplate): Promise<FinalizedOutput>;
|
|
29
|
+
/**
|
|
30
|
+
* Generate final output with error handling
|
|
31
|
+
*/
|
|
32
|
+
export declare function finalizeOutputOrThrow(ir: ZenIR, compiled: CompiledTemplate): Promise<FinalizedOutput>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finalize Output
|
|
3
|
+
*
|
|
4
|
+
* NATIVE BRIDGE: Delegates ALL finalization (Phase 8/9/10) to Rust (`native/compiler-native/src/finalize.rs`).
|
|
5
|
+
*/
|
|
6
|
+
let native;
|
|
7
|
+
try {
|
|
8
|
+
try {
|
|
9
|
+
native = require('../../native/compiler-native');
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
native = require('../../native/compiler-native/index.js');
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
catch (e) {
|
|
16
|
+
// Bridge load handled elsewhere
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Finalize compiler output (Native Bridge)
|
|
20
|
+
*
|
|
21
|
+
* @param ir - Intermediate representation
|
|
22
|
+
* @param compiled - Compiled template
|
|
23
|
+
* @returns Finalized output
|
|
24
|
+
*/
|
|
25
|
+
export async function finalizeOutput(ir, compiled) {
|
|
26
|
+
if (native && native.finalizeOutputNative) {
|
|
27
|
+
try {
|
|
28
|
+
const result = native.finalizeOutputNative(ir, compiled);
|
|
29
|
+
return {
|
|
30
|
+
html: result.html,
|
|
31
|
+
js: result.js,
|
|
32
|
+
npmImports: result.npmImports,
|
|
33
|
+
styles: result.styles,
|
|
34
|
+
hasErrors: result.hasErrors,
|
|
35
|
+
errors: result.errors,
|
|
36
|
+
bundlePlan: result.bundlePlan
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
return {
|
|
41
|
+
html: '',
|
|
42
|
+
js: '',
|
|
43
|
+
npmImports: '',
|
|
44
|
+
styles: [],
|
|
45
|
+
hasErrors: true,
|
|
46
|
+
errors: [`Native finalization failed: ${error.message}`]
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
throw new Error(`[Zenith Native] Finalize bridge unavailable - cannot finalize ${ir.filePath}`);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Generate final output with error handling
|
|
54
|
+
*/
|
|
55
|
+
export async function finalizeOutputOrThrow(ir, compiled) {
|
|
56
|
+
const output = await finalizeOutput(ir, compiled);
|
|
57
|
+
if (output.hasErrors) {
|
|
58
|
+
const errorMessage = output.errors.join('\n\n');
|
|
59
|
+
throw new Error(`Compilation failed:\n\n${errorMessage}`);
|
|
60
|
+
}
|
|
61
|
+
return output;
|
|
62
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate Final Bundle
|
|
3
|
+
*
|
|
4
|
+
* Phase 8/9/10: Generate final browser-ready bundle
|
|
5
|
+
*
|
|
6
|
+
* Combines:
|
|
7
|
+
* - Compiled HTML
|
|
8
|
+
* - Runtime JS
|
|
9
|
+
* - Expression functions
|
|
10
|
+
* - Event bindings
|
|
11
|
+
* - Style injection
|
|
12
|
+
*/
|
|
13
|
+
import type { FinalizedOutput } from './finalizeOutput';
|
|
14
|
+
/**
|
|
15
|
+
* Generate final bundle code
|
|
16
|
+
*
|
|
17
|
+
* This is the complete JavaScript bundle that will execute in the browser.
|
|
18
|
+
* All expressions are pre-compiled - no template parsing at runtime.
|
|
19
|
+
*/
|
|
20
|
+
export declare function generateFinalBundle(finalized: FinalizedOutput): string;
|
|
21
|
+
/**
|
|
22
|
+
* Generate HTML with inline script
|
|
23
|
+
*/
|
|
24
|
+
export declare function generateHTMLWithScript(html: string, jsBundle: string, styles: string[]): string;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate Final Bundle
|
|
3
|
+
*
|
|
4
|
+
* Phase 8/9/10: Generate final browser-ready bundle
|
|
5
|
+
*
|
|
6
|
+
* Combines:
|
|
7
|
+
* - Compiled HTML
|
|
8
|
+
* - Runtime JS
|
|
9
|
+
* - Expression functions
|
|
10
|
+
* - Event bindings
|
|
11
|
+
* - Style injection
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Generate final bundle code
|
|
15
|
+
*
|
|
16
|
+
* This is the complete JavaScript bundle that will execute in the browser.
|
|
17
|
+
* All expressions are pre-compiled - no template parsing at runtime.
|
|
18
|
+
*/
|
|
19
|
+
export function generateFinalBundle(finalized) {
|
|
20
|
+
return `// Zenith Compiled Bundle (Phase 8/9/10)
|
|
21
|
+
// Generated at compile time - no .zen parsing in browser
|
|
22
|
+
// All expressions are pre-compiled - deterministic output
|
|
23
|
+
|
|
24
|
+
${finalized.js}
|
|
25
|
+
|
|
26
|
+
// Bundle complete - ready for browser execution
|
|
27
|
+
`;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Generate HTML with inline script
|
|
31
|
+
*/
|
|
32
|
+
export function generateHTMLWithScript(html, jsBundle, styles) {
|
|
33
|
+
// Inject styles as <style> tags
|
|
34
|
+
const styleTags = styles.map(style => `<style>${escapeHTML(style)}</style>`).join('\n');
|
|
35
|
+
// Inject JS bundle as inline script
|
|
36
|
+
const scriptTag = `<script>${jsBundle}</script>`;
|
|
37
|
+
// Find </head> or <body> to inject styles
|
|
38
|
+
// Find </body> to inject script
|
|
39
|
+
let result = html;
|
|
40
|
+
if (styleTags) {
|
|
41
|
+
if (result.includes('</head>')) {
|
|
42
|
+
result = result.replace('</head>', `${styleTags}\n</head>`);
|
|
43
|
+
}
|
|
44
|
+
else if (result.includes('<body')) {
|
|
45
|
+
result = result.replace('<body', `${styleTags}\n<body`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (scriptTag) {
|
|
49
|
+
if (result.includes('</body>')) {
|
|
50
|
+
result = result.replace('</body>', `${scriptTag}\n</body>`);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
result += scriptTag;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Escape HTML for safe embedding
|
|
60
|
+
*/
|
|
61
|
+
function escapeHTML(str) {
|
|
62
|
+
return str
|
|
63
|
+
.replace(/&/g, '&')
|
|
64
|
+
.replace(/</g, '<')
|
|
65
|
+
.replace(/>/g, '>')
|
|
66
|
+
.replace(/"/g, '"')
|
|
67
|
+
.replace(/'/g, ''');
|
|
68
|
+
}
|