@zenithbuild/cli 0.6.17 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/build/compiler-runtime.d.ts +59 -0
  2. package/dist/build/compiler-runtime.js +277 -0
  3. package/dist/build/expression-rewrites.d.ts +88 -0
  4. package/dist/build/expression-rewrites.js +372 -0
  5. package/dist/build/hoisted-code-transforms.d.ts +44 -0
  6. package/dist/build/hoisted-code-transforms.js +316 -0
  7. package/dist/build/merge-component-ir.d.ts +16 -0
  8. package/dist/build/merge-component-ir.js +257 -0
  9. package/dist/build/page-component-loop.d.ts +92 -0
  10. package/dist/build/page-component-loop.js +257 -0
  11. package/dist/build/page-ir-normalization.d.ts +23 -0
  12. package/dist/build/page-ir-normalization.js +370 -0
  13. package/dist/build/page-loop-metrics.d.ts +100 -0
  14. package/dist/build/page-loop-metrics.js +131 -0
  15. package/dist/build/page-loop-state.d.ts +261 -0
  16. package/dist/build/page-loop-state.js +92 -0
  17. package/dist/build/page-loop.d.ts +33 -0
  18. package/dist/build/page-loop.js +217 -0
  19. package/dist/build/scoped-identifier-rewrite.d.ts +112 -0
  20. package/dist/build/scoped-identifier-rewrite.js +245 -0
  21. package/dist/build/server-script.d.ts +41 -0
  22. package/dist/build/server-script.js +210 -0
  23. package/dist/build/type-declarations.d.ts +16 -0
  24. package/dist/build/type-declarations.js +158 -0
  25. package/dist/build/typescript-expression-utils.d.ts +23 -0
  26. package/dist/build/typescript-expression-utils.js +272 -0
  27. package/dist/build.d.ts +10 -18
  28. package/dist/build.js +74 -2261
  29. package/dist/component-instance-ir.d.ts +2 -2
  30. package/dist/component-instance-ir.js +146 -39
  31. package/dist/component-occurrences.js +63 -15
  32. package/dist/config.d.ts +66 -0
  33. package/dist/config.js +86 -0
  34. package/dist/debug-script.d.ts +1 -0
  35. package/dist/debug-script.js +8 -0
  36. package/dist/dev-build-session.d.ts +23 -0
  37. package/dist/dev-build-session.js +421 -0
  38. package/dist/dev-server.js +256 -54
  39. package/dist/framework-components/Image.zen +316 -0
  40. package/dist/images/materialize.d.ts +17 -0
  41. package/dist/images/materialize.js +200 -0
  42. package/dist/images/payload.d.ts +18 -0
  43. package/dist/images/payload.js +65 -0
  44. package/dist/images/runtime.d.ts +4 -0
  45. package/dist/images/runtime.js +254 -0
  46. package/dist/images/service.d.ts +4 -0
  47. package/dist/images/service.js +302 -0
  48. package/dist/images/shared.d.ts +58 -0
  49. package/dist/images/shared.js +306 -0
  50. package/dist/index.js +2 -17
  51. package/dist/manifest.js +45 -0
  52. package/dist/preview.d.ts +4 -1
  53. package/dist/preview.js +59 -6
  54. package/dist/resolve-components.js +20 -3
  55. package/dist/server-contract.js +3 -2
  56. package/dist/server-script-composition.d.ts +39 -0
  57. package/dist/server-script-composition.js +133 -0
  58. package/dist/startup-profile.d.ts +10 -0
  59. package/dist/startup-profile.js +62 -0
  60. package/dist/toolchain-paths.d.ts +1 -0
  61. package/dist/toolchain-paths.js +31 -0
  62. package/dist/version-check.d.ts +2 -1
  63. package/dist/version-check.js +12 -5
  64. package/package.json +5 -4
@@ -0,0 +1,59 @@
1
+ /**
2
+ * @returns {import('typescript') | null}
3
+ */
4
+ export function loadTypeScriptApi(): typeof import("typescript") | null;
5
+ /**
6
+ * @param {(line: string) => void} sink
7
+ * @returns {(line: string) => void}
8
+ */
9
+ export function createCompilerWarningEmitter(sink?: (line: string) => void): (line: string) => void;
10
+ /**
11
+ * @param {string} filePath
12
+ * @param {string} [stdinSource]
13
+ * @param {object} [compilerOpts]
14
+ * @param {object} [compilerRunOptions]
15
+ * @param {(warning: string) => void} [compilerRunOptions.onWarning]
16
+ * @param {boolean} [compilerRunOptions.suppressWarnings]
17
+ * @param {string|object} [compilerRunOptions.compilerBin]
18
+ * @param {object} [compilerRunOptions.compilerToolchain]
19
+ * @returns {object}
20
+ */
21
+ export function runCompiler(filePath: string, stdinSource?: string, compilerOpts?: object, compilerRunOptions?: {
22
+ onWarning?: ((warning: string) => void) | undefined;
23
+ suppressWarnings?: boolean | undefined;
24
+ compilerBin?: string | object | undefined;
25
+ compilerToolchain?: object | undefined;
26
+ }): object;
27
+ /**
28
+ * @param {string} source
29
+ * @returns {string}
30
+ */
31
+ export function stripStyleBlocks(source: string): string;
32
+ /**
33
+ * @param {ReturnType<import('../startup-profile.js').createStartupProfiler>} startupProfile
34
+ * @param {Record<string, number>} compilerTotals
35
+ * @returns {(phase: 'page' | 'owner' | 'component', filePath: string, stdinSource: string | undefined, compilerOpts: object, compilerRunOptions: object) => object}
36
+ */
37
+ export function createTimedCompilerRunner(startupProfile: ReturnType<typeof import("../startup-profile.js").createStartupProfiler>, compilerTotals: Record<string, number>): (phase: "page" | "owner" | "component", filePath: string, stdinSource: string | undefined, compilerOpts: object, compilerRunOptions: object) => object;
38
+ /**
39
+ * @param {object|object[]} envelope
40
+ * @param {string} outDir
41
+ * @param {string} projectRoot
42
+ * @param {object | null} [logger]
43
+ * @param {boolean} [showInfo]
44
+ * @param {string|object} [bundlerBin]
45
+ * @param {{ devStableAssets?: boolean, rebuildStrategy?: 'full'|'bundle-only'|'page-only', changedRoutes?: string[], fastPath?: boolean, globalGraphHash?: string }} [bundlerOptions]
46
+ * @returns {Promise<void>}
47
+ */
48
+ export function runBundler(envelope: object | object[], outDir: string, projectRoot: string, logger?: object | null, showInfo?: boolean, bundlerBin?: string | object, bundlerOptions?: {
49
+ devStableAssets?: boolean;
50
+ rebuildStrategy?: "full" | "bundle-only" | "page-only";
51
+ changedRoutes?: string[];
52
+ fastPath?: boolean;
53
+ globalGraphHash?: string;
54
+ }): Promise<void>;
55
+ /**
56
+ * @param {string} rootDir
57
+ * @returns {Promise<string[]>}
58
+ */
59
+ export function collectAssets(rootDir: string): Promise<string[]>;
@@ -0,0 +1,277 @@
1
+ import { spawn, spawnSync } from 'node:child_process';
2
+ import { readdir, stat } from 'node:fs/promises';
3
+ import { createRequire } from 'node:module';
4
+ import { performance } from 'node:perf_hooks';
5
+ import { join, relative } from 'node:path';
6
+ import { resolveBundlerBin } from '../toolchain-paths.js';
7
+ import { createCompilerToolchain, getActiveToolchainCandidate, runToolchainSync } from '../toolchain-runner.js';
8
+ const require = createRequire(import.meta.url);
9
+ const COMPILER_SPAWN_MAX_BUFFER = 32 * 1024 * 1024;
10
+ let cachedTypeScript = undefined;
11
+ /**
12
+ * @returns {import('typescript') | null}
13
+ */
14
+ export function loadTypeScriptApi() {
15
+ if (cachedTypeScript === undefined) {
16
+ try {
17
+ cachedTypeScript = require('typescript');
18
+ }
19
+ catch {
20
+ cachedTypeScript = null;
21
+ }
22
+ }
23
+ return cachedTypeScript;
24
+ }
25
+ /**
26
+ * @param {(line: string) => void} sink
27
+ * @returns {(line: string) => void}
28
+ */
29
+ export function createCompilerWarningEmitter(sink = (line) => console.warn(line)) {
30
+ const emitted = new Set();
31
+ return (line) => {
32
+ const text = String(line || '').trim();
33
+ if (!text || emitted.has(text)) {
34
+ return;
35
+ }
36
+ emitted.add(text);
37
+ sink(text);
38
+ };
39
+ }
40
+ /**
41
+ * @param {import('node:stream').Readable | null | undefined} stream
42
+ * @param {(line: string) => void} onLine
43
+ */
44
+ function forwardStreamLines(stream, onLine) {
45
+ if (!stream || typeof stream.on !== 'function') {
46
+ return;
47
+ }
48
+ let pending = '';
49
+ stream.setEncoding?.('utf8');
50
+ stream.on('data', (chunk) => {
51
+ pending += String(chunk || '');
52
+ const lines = pending.split(/\r?\n/);
53
+ pending = lines.pop() || '';
54
+ for (const line of lines) {
55
+ if (line.trim().length > 0) {
56
+ onLine(line);
57
+ }
58
+ }
59
+ });
60
+ stream.on('end', () => {
61
+ if (pending.trim().length > 0) {
62
+ onLine(pending);
63
+ }
64
+ });
65
+ }
66
+ /**
67
+ * @param {string} filePath
68
+ * @param {string} [stdinSource]
69
+ * @param {object} [compilerOpts]
70
+ * @param {object} [compilerRunOptions]
71
+ * @param {(warning: string) => void} [compilerRunOptions.onWarning]
72
+ * @param {boolean} [compilerRunOptions.suppressWarnings]
73
+ * @param {string|object} [compilerRunOptions.compilerBin]
74
+ * @param {object} [compilerRunOptions.compilerToolchain]
75
+ * @returns {object}
76
+ */
77
+ export function runCompiler(filePath, stdinSource, compilerOpts = {}, compilerRunOptions = {}) {
78
+ const compilerToolchain = compilerRunOptions.compilerToolchain
79
+ || (compilerRunOptions.compilerBin && typeof compilerRunOptions.compilerBin === 'object'
80
+ ? compilerRunOptions.compilerBin
81
+ : null);
82
+ const compilerBin = !compilerToolchain && typeof compilerRunOptions.compilerBin === 'string'
83
+ ? compilerRunOptions.compilerBin
84
+ : null;
85
+ const args = stdinSource !== undefined
86
+ ? ['--stdin', filePath]
87
+ : [filePath];
88
+ if (compilerOpts?.experimentalEmbeddedMarkup) {
89
+ args.push('--embedded-markup-expressions');
90
+ }
91
+ if (compilerOpts?.strictDomLints) {
92
+ args.push('--strict-dom-lints');
93
+ }
94
+ const opts = {
95
+ encoding: 'utf8',
96
+ maxBuffer: COMPILER_SPAWN_MAX_BUFFER
97
+ };
98
+ if (stdinSource !== undefined) {
99
+ opts.input = stdinSource;
100
+ }
101
+ const result = compilerToolchain
102
+ ? runToolchainSync(compilerToolchain, args, opts).result
103
+ : (compilerBin
104
+ ? spawnSync(compilerBin, args, opts)
105
+ : runToolchainSync(createCompilerToolchain({
106
+ logger: compilerRunOptions.logger || null
107
+ }), args, opts).result);
108
+ if (result.error) {
109
+ throw new Error(`Compiler spawn failed for ${filePath}: ${result.error.message}`);
110
+ }
111
+ if (result.status !== 0) {
112
+ throw new Error(`Compiler failed for ${filePath} with exit code ${result.status}\n${result.stderr || ''}`);
113
+ }
114
+ if (result.stderr && result.stderr.trim().length > 0 && compilerRunOptions.suppressWarnings !== true) {
115
+ const lines = String(result.stderr)
116
+ .split('\n')
117
+ .map((line) => line.trim())
118
+ .filter((line) => line.length > 0);
119
+ for (const line of lines) {
120
+ if (typeof compilerRunOptions.onWarning === 'function') {
121
+ compilerRunOptions.onWarning(line);
122
+ }
123
+ else {
124
+ console.warn(line);
125
+ }
126
+ }
127
+ }
128
+ try {
129
+ return JSON.parse(result.stdout);
130
+ }
131
+ catch (err) {
132
+ throw new Error(`Compiler emitted invalid JSON: ${err.message}`);
133
+ }
134
+ }
135
+ /**
136
+ * @param {string} source
137
+ * @returns {string}
138
+ */
139
+ export function stripStyleBlocks(source) {
140
+ return String(source || '').replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, '');
141
+ }
142
+ /**
143
+ * @param {ReturnType<import('../startup-profile.js').createStartupProfiler>} startupProfile
144
+ * @param {Record<string, number>} compilerTotals
145
+ * @returns {(phase: 'page' | 'owner' | 'component', filePath: string, stdinSource: string | undefined, compilerOpts: object, compilerRunOptions: object) => object}
146
+ */
147
+ export function createTimedCompilerRunner(startupProfile, compilerTotals) {
148
+ return (phase, filePath, stdinSource, compilerOpts, compilerRunOptions) => {
149
+ const startedAt = performance.now();
150
+ const result = runCompiler(filePath, stdinSource, compilerOpts, compilerRunOptions);
151
+ const durationMs = startupProfile.roundMs(performance.now() - startedAt);
152
+ if (phase === 'page') {
153
+ compilerTotals.pageMs += durationMs;
154
+ compilerTotals.pageCalls += 1;
155
+ }
156
+ else if (phase === 'owner') {
157
+ compilerTotals.ownerMs += durationMs;
158
+ compilerTotals.ownerCalls += 1;
159
+ }
160
+ else if (phase === 'component') {
161
+ compilerTotals.componentMs += durationMs;
162
+ compilerTotals.componentCalls += 1;
163
+ }
164
+ return result;
165
+ };
166
+ }
167
+ /**
168
+ * @param {object|object[]} envelope
169
+ * @param {string} outDir
170
+ * @param {string} projectRoot
171
+ * @param {object | null} [logger]
172
+ * @param {boolean} [showInfo]
173
+ * @param {string|object} [bundlerBin]
174
+ * @param {{ devStableAssets?: boolean, rebuildStrategy?: 'full'|'bundle-only'|'page-only', changedRoutes?: string[], fastPath?: boolean, globalGraphHash?: string }} [bundlerOptions]
175
+ * @returns {Promise<void>}
176
+ */
177
+ export function runBundler(envelope, outDir, projectRoot, logger = null, showInfo = true, bundlerBin = resolveBundlerBin(projectRoot), bundlerOptions = {}) {
178
+ return new Promise((resolvePromise, rejectPromise) => {
179
+ const useStructuredLogger = Boolean(logger && typeof logger.childLine === 'function');
180
+ const bundlerToolchain = bundlerBin && typeof bundlerBin === 'object'
181
+ ? bundlerBin
182
+ : null;
183
+ const bundlerCandidate = bundlerToolchain
184
+ ? getActiveToolchainCandidate(bundlerToolchain)
185
+ : null;
186
+ const bundlerPath = bundlerCandidate?.command || bundlerBin;
187
+ const bundlerArgs = [
188
+ ...(Array.isArray(bundlerCandidate?.argsPrefix) ? bundlerCandidate.argsPrefix : []),
189
+ '--out-dir',
190
+ outDir
191
+ ];
192
+ if (bundlerOptions.devStableAssets === true) {
193
+ bundlerArgs.push('--dev-stable-assets');
194
+ }
195
+ if (typeof bundlerOptions.rebuildStrategy === 'string' && bundlerOptions.rebuildStrategy.length > 0) {
196
+ bundlerArgs.push('--rebuild-strategy', bundlerOptions.rebuildStrategy);
197
+ }
198
+ if (Array.isArray(bundlerOptions.changedRoutes)) {
199
+ for (const route of bundlerOptions.changedRoutes) {
200
+ const value = String(route || '').trim();
201
+ if (value.length > 0) {
202
+ bundlerArgs.push('--changed-route', value);
203
+ }
204
+ }
205
+ }
206
+ if (bundlerOptions.fastPath === true) {
207
+ bundlerArgs.push('--fast-path');
208
+ }
209
+ if (typeof bundlerOptions.globalGraphHash === 'string' && bundlerOptions.globalGraphHash.length > 0) {
210
+ bundlerArgs.push('--global-graph-hash', bundlerOptions.globalGraphHash);
211
+ }
212
+ const child = spawn(bundlerPath, bundlerArgs, {
213
+ cwd: projectRoot,
214
+ stdio: useStructuredLogger ? ['pipe', 'pipe', 'pipe'] : ['pipe', 'inherit', 'inherit']
215
+ });
216
+ if (useStructuredLogger) {
217
+ forwardStreamLines(child.stdout, (line) => {
218
+ logger.childLine('bundler', line, { stream: 'stdout', showInfo });
219
+ });
220
+ forwardStreamLines(child.stderr, (line) => {
221
+ logger.childLine('bundler', line, { stream: 'stderr', showInfo: true });
222
+ });
223
+ }
224
+ child.on('error', (err) => {
225
+ rejectPromise(new Error(`Bundler spawn failed: ${err.message}`));
226
+ });
227
+ child.on('close', (code) => {
228
+ if (code === 0) {
229
+ resolvePromise();
230
+ return;
231
+ }
232
+ rejectPromise(new Error(`Bundler failed with exit code ${code}`));
233
+ });
234
+ child.stdin.write(JSON.stringify(envelope));
235
+ child.stdin.end();
236
+ });
237
+ }
238
+ /**
239
+ * @param {string} rootDir
240
+ * @returns {Promise<string[]>}
241
+ */
242
+ export async function collectAssets(rootDir) {
243
+ const files = [];
244
+ async function walk(dir) {
245
+ let entries = [];
246
+ try {
247
+ entries = await readdir(dir);
248
+ }
249
+ catch {
250
+ return;
251
+ }
252
+ entries.sort((a, b) => a.localeCompare(b));
253
+ for (const name of entries) {
254
+ const fullPath = join(dir, name);
255
+ let info;
256
+ try {
257
+ info = await stat(fullPath);
258
+ }
259
+ catch (error) {
260
+ if (error && typeof error === 'object' && error.code === 'ENOENT') {
261
+ continue;
262
+ }
263
+ throw error;
264
+ }
265
+ if (info.isDirectory()) {
266
+ await walk(fullPath);
267
+ continue;
268
+ }
269
+ if (fullPath.endsWith('.js') || fullPath.endsWith('.css')) {
270
+ files.push(relative(rootDir, fullPath).replaceAll('\\', '/'));
271
+ }
272
+ }
273
+ }
274
+ await walk(rootDir);
275
+ files.sort((a, b) => a.localeCompare(b));
276
+ return files;
277
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * @param {string} compPath
3
+ * @param {string} componentSource
4
+ * @param {object} compIr
5
+ * @param {object} compilerOpts
6
+ * @param {string|object} compilerBin
7
+ * @param {Map<string, string[]> | null} [templateExpressionCache]
8
+ * @param {Record<string, number> | null} [rewriteMetrics]
9
+ * @returns {{
10
+ * map: Map<string, string>,
11
+ * bindings: Map<string, {
12
+ * compiled_expr: string | null,
13
+ * signal_index: number | null,
14
+ * signal_indices: number[],
15
+ * state_index: number | null,
16
+ * component_instance: string | null,
17
+ * component_binding: string | null
18
+ * }>,
19
+ * signals: Array<{ id?: number, kind?: string, state_index?: number }>,
20
+ * stateBindings: Array<{ key?: string, value?: string }>,
21
+ * ambiguous: Set<string>,
22
+ * sequence: Array<{ raw: string, rewritten: string, binding: object | null }>
23
+ * }}
24
+ */
25
+ export function buildComponentExpressionRewrite(compPath: string, componentSource: string, compIr: object, compilerOpts: object, compilerBin: string | object, templateExpressionCache?: Map<string, string[]> | null, rewriteMetrics?: Record<string, number> | null): {
26
+ map: Map<string, string>;
27
+ bindings: Map<string, {
28
+ compiled_expr: string | null;
29
+ signal_index: number | null;
30
+ signal_indices: number[];
31
+ state_index: number | null;
32
+ component_instance: string | null;
33
+ component_binding: string | null;
34
+ }>;
35
+ signals: Array<{
36
+ id?: number;
37
+ kind?: string;
38
+ state_index?: number;
39
+ }>;
40
+ stateBindings: Array<{
41
+ key?: string;
42
+ value?: string;
43
+ }>;
44
+ ambiguous: Set<string>;
45
+ sequence: Array<{
46
+ raw: string;
47
+ rewritten: string;
48
+ binding: object | null;
49
+ }>;
50
+ };
51
+ /**
52
+ * @param {string} compiledExpr
53
+ * @param {Array<{ state_index?: number }>} componentSignals
54
+ * @param {Array<{ key?: string }>} componentStateBindings
55
+ * @param {Map<string, number>} pageSignalIndexByStateKey
56
+ * @returns {string | null}
57
+ */
58
+ export function remapCompiledExpressionSignals(compiledExpr: string, componentSignals: Array<{
59
+ state_index?: number;
60
+ }>, componentStateBindings: Array<{
61
+ key?: string;
62
+ }>, pageSignalIndexByStateKey: Map<string, number>): string | null;
63
+ /**
64
+ * @param {object} pageBindingContext
65
+ * @param {object} componentRewrite
66
+ * @param {object} binding
67
+ * @param {Record<string, number> | null} [resolutionMetrics]
68
+ * @returns {object | null}
69
+ */
70
+ export function resolveRewrittenBindingMetadata(pageBindingContext: object, componentRewrite: object, binding: object, resolutionMetrics?: Record<string, number> | null): object | null;
71
+ /**
72
+ * @param {Map<string, string>} pageMap
73
+ * @param {Map<string, object>} pageBindingMap
74
+ * @param {Set<string>} pageAmbiguous
75
+ * @param {object} componentRewrite
76
+ * @param {object} pageBindingContext
77
+ * @param {Record<string, number> | null} [bindingResolutionMetrics]
78
+ */
79
+ export function mergeExpressionRewriteMaps(pageMap: Map<string, string>, pageBindingMap: Map<string, object>, pageAmbiguous: Set<string>, componentRewrite: object, pageBindingContext: object, bindingResolutionMetrics?: Record<string, number> | null): void;
80
+ /**
81
+ * @param {string} identifier
82
+ * @param {Array<{ key?: string }>} stateBindings
83
+ * @param {Set<string> | null} [preferredKeys]
84
+ * @returns {string | null}
85
+ */
86
+ export function resolveStateKeyFromBindings(identifier: string, stateBindings: Array<{
87
+ key?: string;
88
+ }>, preferredKeys?: Set<string> | null): string | null;