@zenithbuild/cli 0.6.17 → 0.7.0

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,316 @@
1
+ import { dirname, relative, resolve } from 'node:path';
2
+ import { loadTypeScriptApi } from './compiler-runtime.js';
3
+ /**
4
+ * @param {string} spec
5
+ * @returns {boolean}
6
+ */
7
+ function isRelativeSpecifier(spec) {
8
+ return spec.startsWith('./') || spec.startsWith('../');
9
+ }
10
+ function rebaseRelativeSpecifier(spec, fromFile, toFile) {
11
+ if (!isRelativeSpecifier(spec)) {
12
+ return spec;
13
+ }
14
+ const absoluteTarget = resolve(dirname(fromFile), spec);
15
+ let rebased = relative(dirname(toFile), absoluteTarget).replaceAll('\\', '/');
16
+ if (!rebased.startsWith('.')) {
17
+ rebased = `./${rebased}`;
18
+ }
19
+ return rebased;
20
+ }
21
+ /**
22
+ * @param {string} line
23
+ * @param {string} oldSpec
24
+ * @param {string} newSpec
25
+ * @returns {string}
26
+ */
27
+ function replaceImportSpecifierLiteral(line, oldSpec, newSpec) {
28
+ const single = `'${oldSpec}'`;
29
+ if (line.includes(single)) {
30
+ return line.replace(single, `'${newSpec}'`);
31
+ }
32
+ const dbl = `"${oldSpec}"`;
33
+ if (line.includes(dbl)) {
34
+ return line.replace(dbl, `"${newSpec}"`);
35
+ }
36
+ return line;
37
+ }
38
+ export function rewriteStaticImportLine(line, fromFile, toFile) {
39
+ const match = line.match(/^\s*import(?:\s+[^'"]+?\s+from)?\s*['"]([^'"]+)['"]\s*;?\s*$/);
40
+ if (!match) {
41
+ return line;
42
+ }
43
+ const spec = match[1];
44
+ if (!isRelativeSpecifier(spec)) {
45
+ return line;
46
+ }
47
+ const rebased = rebaseRelativeSpecifier(spec, fromFile, toFile);
48
+ return replaceImportSpecifierLiteral(line, spec, rebased);
49
+ }
50
+ /**
51
+ * @param {string} line
52
+ * @returns {string | null}
53
+ */
54
+ export function extractStaticImportSpecifier(line) {
55
+ const match = line.match(/^\s*import(?:\s+[^'"]+?\s+from)?\s*['"]([^'"]+)['"]\s*;?\s*$/);
56
+ return match ? match[1] : null;
57
+ }
58
+ /**
59
+ * @param {string} spec
60
+ * @returns {boolean}
61
+ */
62
+ export function isCssSpecifier(spec) {
63
+ return /\.css(?:[?#].*)?$/i.test(spec);
64
+ }
65
+ /**
66
+ * @param {string} source
67
+ * @param {string} fromFile
68
+ * @param {string} toFile
69
+ * @returns {string}
70
+ */
71
+ export function rewriteStaticImportsInSource(source, fromFile, toFile) {
72
+ return source.replace(/(^\s*import(?:\s+[^'"]+?\s+from)?\s*['"])([^'"]+)(['"]\s*;?\s*$)/gm, (_full, prefix, spec, suffix) => `${prefix}${rebaseRelativeSpecifier(spec, fromFile, toFile)}${suffix}`);
73
+ }
74
+ /**
75
+ * @param {string} source
76
+ * @param {string} sourceFile
77
+ * @param {object | null} [transformCache]
78
+ * @param {Record<string, number> | null} [mergeMetrics]
79
+ * @returns {string}
80
+ */
81
+ export function transpileTypeScriptToJs(source, sourceFile, transformCache = null, mergeMetrics = null) {
82
+ const cacheKey = transformCache?.transpileToJs instanceof Map
83
+ ? `${sourceFile}\u0000${source}`
84
+ : null;
85
+ if (cacheKey && transformCache.transpileToJs.has(cacheKey)) {
86
+ if (mergeMetrics && typeof mergeMetrics === 'object') {
87
+ mergeMetrics.codeTranspileCacheHits = (mergeMetrics.codeTranspileCacheHits || 0) + 1;
88
+ }
89
+ return transformCache.transpileToJs.get(cacheKey);
90
+ }
91
+ const ts = loadTypeScriptApi();
92
+ if (!ts) {
93
+ return source;
94
+ }
95
+ try {
96
+ const output = ts.transpileModule(source, {
97
+ fileName: sourceFile,
98
+ compilerOptions: {
99
+ module: ts.ModuleKind.ESNext,
100
+ target: ts.ScriptTarget.ES5,
101
+ importsNotUsedAsValues: ts.ImportsNotUsedAsValues.Preserve,
102
+ verbatimModuleSyntax: true,
103
+ newLine: ts.NewLineKind.LineFeed,
104
+ },
105
+ reportDiagnostics: false,
106
+ });
107
+ const transpiled = output.outputText;
108
+ if (mergeMetrics && typeof mergeMetrics === 'object') {
109
+ if (transpiled === source) {
110
+ mergeMetrics.codeTranspileExactNoopCount = (mergeMetrics.codeTranspileExactNoopCount || 0) + 1;
111
+ }
112
+ else if (transpiled.trim() === String(source).trim()) {
113
+ mergeMetrics.codeTranspileTrimmedNoopCount = (mergeMetrics.codeTranspileTrimmedNoopCount || 0) + 1;
114
+ }
115
+ else {
116
+ mergeMetrics.codeTranspileChangedOutputCount = (mergeMetrics.codeTranspileChangedOutputCount || 0) + 1;
117
+ }
118
+ }
119
+ if (cacheKey) {
120
+ transformCache.transpileToJs.set(cacheKey, transpiled);
121
+ if (mergeMetrics && typeof mergeMetrics === 'object') {
122
+ mergeMetrics.codeTranspileCacheMisses = (mergeMetrics.codeTranspileCacheMisses || 0) + 1;
123
+ }
124
+ }
125
+ return transpiled;
126
+ }
127
+ catch {
128
+ return source;
129
+ }
130
+ }
131
+ const DEFERRED_RUNTIME_CALLS = new Set(['zenMount', 'zenEffect', 'zeneffect']);
132
+ /**
133
+ * @param {string} body
134
+ * @returns {{ hoisted: string, deferred: string }}
135
+ */
136
+ function splitDeferredRuntimeCalls(body) {
137
+ const ts = loadTypeScriptApi();
138
+ if (!ts || typeof body !== 'string' || body.trim().length === 0) {
139
+ return { hoisted: body, deferred: '' };
140
+ }
141
+ let sourceFile;
142
+ try {
143
+ sourceFile = ts.createSourceFile('zenith-component-runtime.ts', body, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
144
+ }
145
+ catch {
146
+ return { hoisted: body, deferred: '' };
147
+ }
148
+ if (!sourceFile || !Array.isArray(sourceFile.statements) || sourceFile.statements.length === 0) {
149
+ return { hoisted: body, deferred: '' };
150
+ }
151
+ const ranges = [];
152
+ for (const statement of sourceFile.statements) {
153
+ if (!ts.isExpressionStatement(statement) || !ts.isCallExpression(statement.expression)) {
154
+ continue;
155
+ }
156
+ let callee = statement.expression.expression;
157
+ while (ts.isParenthesizedExpression(callee)) {
158
+ callee = callee.expression;
159
+ }
160
+ if (!ts.isIdentifier(callee) || !DEFERRED_RUNTIME_CALLS.has(callee.text)) {
161
+ continue;
162
+ }
163
+ const start = typeof statement.getFullStart === 'function' ? statement.getFullStart() : statement.pos;
164
+ const end = statement.end;
165
+ if (!Number.isInteger(start) || !Number.isInteger(end) || end <= start) {
166
+ continue;
167
+ }
168
+ ranges.push({ start, end });
169
+ }
170
+ if (ranges.length === 0) {
171
+ return { hoisted: body, deferred: '' };
172
+ }
173
+ ranges.sort((a, b) => a.start - b.start);
174
+ const merged = [];
175
+ for (const range of ranges) {
176
+ const last = merged[merged.length - 1];
177
+ if (!last || range.start > last.end) {
178
+ merged.push({ start: range.start, end: range.end });
179
+ continue;
180
+ }
181
+ if (range.end > last.end) {
182
+ last.end = range.end;
183
+ }
184
+ }
185
+ let cursor = 0;
186
+ let hoisted = '';
187
+ let deferred = '';
188
+ for (const range of merged) {
189
+ if (range.start > cursor) {
190
+ hoisted += body.slice(cursor, range.start);
191
+ }
192
+ deferred += body.slice(range.start, range.end);
193
+ if (!deferred.endsWith('\n')) {
194
+ deferred += '\n';
195
+ }
196
+ cursor = range.end;
197
+ }
198
+ if (cursor < body.length) {
199
+ hoisted += body.slice(cursor);
200
+ }
201
+ return { hoisted, deferred };
202
+ }
203
+ /**
204
+ * @param {string} source
205
+ * @param {Set<string>} seenStaticImports
206
+ * @returns {string}
207
+ */
208
+ export function dedupeStaticImportsInSource(source, seenStaticImports) {
209
+ const lines = source.split('\n');
210
+ const kept = [];
211
+ for (const line of lines) {
212
+ const spec = extractStaticImportSpecifier(line);
213
+ if (!spec) {
214
+ kept.push(line);
215
+ continue;
216
+ }
217
+ const key = line.trim();
218
+ if (seenStaticImports.has(key)) {
219
+ continue;
220
+ }
221
+ seenStaticImports.add(key);
222
+ kept.push(line);
223
+ }
224
+ return kept.join('\n');
225
+ }
226
+ /**
227
+ * @param {string} source
228
+ * @returns {string}
229
+ */
230
+ export function stripNonCssStaticImportsInSource(source) {
231
+ const lines = source.split('\n');
232
+ const kept = [];
233
+ for (const line of lines) {
234
+ const spec = extractStaticImportSpecifier(line);
235
+ if (!spec) {
236
+ kept.push(line);
237
+ continue;
238
+ }
239
+ if (isCssSpecifier(spec)) {
240
+ kept.push(line);
241
+ }
242
+ }
243
+ return kept.join('\n');
244
+ }
245
+ /**
246
+ * @param {string} source
247
+ * @param {object | null} [transformCache]
248
+ * @param {Record<string, number> | null} [mergeMetrics]
249
+ * @returns {string}
250
+ */
251
+ export function deferComponentRuntimeBlock(source, transformCache = null, mergeMetrics = null) {
252
+ const cacheKey = transformCache?.deferRuntime instanceof Map ? source : null;
253
+ if (cacheKey && transformCache.deferRuntime.has(cacheKey)) {
254
+ if (mergeMetrics && typeof mergeMetrics === 'object') {
255
+ mergeMetrics.codeDeferRuntimeCacheHits = (mergeMetrics.codeDeferRuntimeCacheHits || 0) + 1;
256
+ }
257
+ return transformCache.deferRuntime.get(cacheKey);
258
+ }
259
+ const lines = source.split('\n');
260
+ const importLines = [];
261
+ const bodyLines = [];
262
+ let inImportPrefix = true;
263
+ for (const line of lines) {
264
+ if (inImportPrefix && extractStaticImportSpecifier(line)) {
265
+ importLines.push(line);
266
+ continue;
267
+ }
268
+ inImportPrefix = false;
269
+ bodyLines.push(line);
270
+ }
271
+ const body = bodyLines.join('\n');
272
+ if (body.trim().length === 0) {
273
+ const output = importLines.join('\n');
274
+ if (cacheKey) {
275
+ transformCache.deferRuntime.set(cacheKey, output);
276
+ if (mergeMetrics && typeof mergeMetrics === 'object') {
277
+ mergeMetrics.codeDeferRuntimeCacheMisses = (mergeMetrics.codeDeferRuntimeCacheMisses || 0) + 1;
278
+ }
279
+ }
280
+ return output;
281
+ }
282
+ const { hoisted, deferred } = splitDeferredRuntimeCalls(body);
283
+ if (deferred.trim().length === 0) {
284
+ const output = [importLines.join('\n').trim(), hoisted.trim()]
285
+ .filter((segment) => segment.length > 0)
286
+ .join('\n');
287
+ if (cacheKey) {
288
+ transformCache.deferRuntime.set(cacheKey, output);
289
+ if (mergeMetrics && typeof mergeMetrics === 'object') {
290
+ mergeMetrics.codeDeferRuntimeCacheMisses = (mergeMetrics.codeDeferRuntimeCacheMisses || 0) + 1;
291
+ }
292
+ }
293
+ return output;
294
+ }
295
+ const indentedBody = deferred
296
+ .trim()
297
+ .split('\n')
298
+ .map((line) => ` ${line}`)
299
+ .join('\n');
300
+ const wrapped = [
301
+ importLines.join('\n').trim(),
302
+ hoisted.trim(),
303
+ "__zenith_component_bootstraps.push(() => {",
304
+ indentedBody,
305
+ "});"
306
+ ]
307
+ .filter((segment) => segment.length > 0)
308
+ .join('\n');
309
+ if (cacheKey) {
310
+ transformCache.deferRuntime.set(cacheKey, wrapped);
311
+ if (mergeMetrics && typeof mergeMetrics === 'object') {
312
+ mergeMetrics.codeDeferRuntimeCacheMisses = (mergeMetrics.codeDeferRuntimeCacheMisses || 0) + 1;
313
+ }
314
+ }
315
+ return wrapped;
316
+ }
@@ -0,0 +1,16 @@
1
+ export function createPageIrMergeCache(pageIr: any): {
2
+ stateEntries: any;
3
+ signals: any;
4
+ importSet: Set<any>;
5
+ declarationSet: Set<any>;
6
+ functionSet: Set<any>;
7
+ hoistedSignalSet: Set<any>;
8
+ stateKeySet: Set<any>;
9
+ stateIndexByKey: Map<any, any>;
10
+ runtimeSignalStateKeySet: Set<any>;
11
+ signalIndexByStateKey: Map<any, any>;
12
+ signalIndicesByStateIndex: Map<any, any>;
13
+ codeSet: Set<any>;
14
+ };
15
+ export function addMergeMetric(mergeMetrics: any, key: any, value: any): void;
16
+ export function mergeComponentIr(pageIr: any, compIr: any, compPath: any, pageFile: any, options: any, seenStaticImports: any, knownRefKeys?: null, mergeCache?: null, mergeMetrics?: null, transformCache?: null): void;
@@ -0,0 +1,257 @@
1
+ import { performance } from 'node:perf_hooks';
2
+ import { resolveStateKeyFromBindings } from './expression-rewrites.js';
3
+ import { injectPropsPrelude } from './scoped-identifier-rewrite.js';
4
+ import { dedupeStaticImportsInSource, deferComponentRuntimeBlock, extractStaticImportSpecifier, isCssSpecifier, rewriteStaticImportLine, rewriteStaticImportsInSource, stripNonCssStaticImportsInSource, transpileTypeScriptToJs } from './hoisted-code-transforms.js';
5
+ export function createPageIrMergeCache(pageIr) {
6
+ const hoisted = pageIr?.hoisted || {};
7
+ const stateEntries = Array.isArray(hoisted.state) ? hoisted.state : [];
8
+ const signals = Array.isArray(pageIr?.signals) ? pageIr.signals : [];
9
+ const signalIndexByStateKey = new Map();
10
+ const signalIndicesByStateIndex = new Map();
11
+ for (let index = 0; index < signals.length; index++) {
12
+ const stateIndex = signals[index]?.state_index;
13
+ if (!Number.isInteger(stateIndex) || stateIndex < 0) {
14
+ continue;
15
+ }
16
+ const stateKey = stateEntries[stateIndex]?.key;
17
+ if (typeof stateKey === 'string' && stateKey.length > 0 && !signalIndexByStateKey.has(stateKey)) {
18
+ signalIndexByStateKey.set(stateKey, index);
19
+ }
20
+ const existingIndices = signalIndicesByStateIndex.get(stateIndex);
21
+ if (existingIndices) {
22
+ existingIndices.push(index);
23
+ }
24
+ else {
25
+ signalIndicesByStateIndex.set(stateIndex, [index]);
26
+ }
27
+ }
28
+ return {
29
+ stateEntries,
30
+ signals,
31
+ importSet: new Set(Array.isArray(hoisted.imports) ? hoisted.imports : []),
32
+ declarationSet: new Set(Array.isArray(hoisted.declarations) ? hoisted.declarations : []),
33
+ functionSet: new Set(Array.isArray(hoisted.functions) ? hoisted.functions : []),
34
+ hoistedSignalSet: new Set(Array.isArray(hoisted.signals) ? hoisted.signals : []),
35
+ stateKeySet: new Set(stateEntries.map((entry) => entry?.key).filter(Boolean)),
36
+ stateIndexByKey: new Map(stateEntries
37
+ .map((entry, index) => [entry?.key, index])
38
+ .filter(([key]) => typeof key === 'string' && key.length > 0)),
39
+ runtimeSignalStateKeySet: new Set(signals
40
+ .map((signal) => {
41
+ const stateIndex = signal?.state_index;
42
+ return Number.isInteger(stateIndex) ? stateEntries[stateIndex]?.key : null;
43
+ })
44
+ .filter(Boolean)),
45
+ signalIndexByStateKey,
46
+ signalIndicesByStateIndex,
47
+ codeSet: new Set(Array.isArray(hoisted.code) ? hoisted.code : [])
48
+ };
49
+ }
50
+ export function addMergeMetric(mergeMetrics, key, value) {
51
+ if (!mergeMetrics || typeof mergeMetrics !== 'object' || !Number.isFinite(value)) {
52
+ return;
53
+ }
54
+ mergeMetrics[key] = (mergeMetrics[key] || 0) + value;
55
+ }
56
+ export function mergeComponentIr(pageIr, compIr, compPath, pageFile, options, seenStaticImports, knownRefKeys = null, mergeCache = null, mergeMetrics = null, transformCache = null) {
57
+ const componentScriptsStartedAt = performance.now();
58
+ if (compIr.components_scripts) {
59
+ for (const [hoistId, script] of Object.entries(compIr.components_scripts)) {
60
+ if (!pageIr.components_scripts[hoistId]) {
61
+ pageIr.components_scripts[hoistId] = script;
62
+ }
63
+ }
64
+ }
65
+ addMergeMetric(mergeMetrics, 'componentScriptsMs', performance.now() - componentScriptsStartedAt);
66
+ const componentInstancesStartedAt = performance.now();
67
+ if (compIr.component_instances?.length) {
68
+ pageIr.component_instances.push(...compIr.component_instances);
69
+ }
70
+ addMergeMetric(mergeMetrics, 'componentInstancesMs', performance.now() - componentInstancesStartedAt);
71
+ const refBindingsStartedAt = performance.now();
72
+ if (knownRefKeys instanceof Set && Array.isArray(compIr.ref_bindings)) {
73
+ const componentStateBindings = Array.isArray(compIr?.hoisted?.state) ? compIr.hoisted.state : [];
74
+ for (const binding of compIr.ref_bindings) {
75
+ if (!binding || typeof binding.identifier !== 'string' || binding.identifier.length === 0) {
76
+ continue;
77
+ }
78
+ const resolved = resolveStateKeyFromBindings(binding.identifier, componentStateBindings);
79
+ knownRefKeys.add(resolved || binding.identifier);
80
+ }
81
+ }
82
+ addMergeMetric(mergeMetrics, 'refBindingsMs', performance.now() - refBindingsStartedAt);
83
+ const importsStartedAt = performance.now();
84
+ if (compIr.hoisted?.imports?.length) {
85
+ for (const imp of compIr.hoisted.imports) {
86
+ const rebased = rewriteStaticImportLine(imp, compPath, pageFile);
87
+ if (options.cssImportsOnly) {
88
+ const spec = extractStaticImportSpecifier(rebased);
89
+ if (!spec || !isCssSpecifier(spec)) {
90
+ continue;
91
+ }
92
+ }
93
+ if (mergeCache?.importSet instanceof Set) {
94
+ if (mergeCache.importSet.has(rebased)) {
95
+ continue;
96
+ }
97
+ mergeCache.importSet.add(rebased);
98
+ }
99
+ else if (pageIr.hoisted.imports.includes(rebased)) {
100
+ continue;
101
+ }
102
+ if (!mergeCache?.importSet || mergeCache.importSet.has(rebased)) {
103
+ pageIr.hoisted.imports.push(rebased);
104
+ }
105
+ }
106
+ }
107
+ addMergeMetric(mergeMetrics, 'importsMs', performance.now() - importsStartedAt);
108
+ const hoistedSymbolsStartedAt = performance.now();
109
+ if (options.includeCode && compIr.hoisted) {
110
+ if (Array.isArray(compIr.hoisted.declarations)) {
111
+ for (const decl of compIr.hoisted.declarations) {
112
+ if (mergeCache?.declarationSet instanceof Set) {
113
+ if (mergeCache.declarationSet.has(decl)) {
114
+ continue;
115
+ }
116
+ mergeCache.declarationSet.add(decl);
117
+ }
118
+ else if (pageIr.hoisted.declarations.includes(decl)) {
119
+ continue;
120
+ }
121
+ pageIr.hoisted.declarations.push(decl);
122
+ }
123
+ }
124
+ if (Array.isArray(compIr.hoisted.functions)) {
125
+ for (const fnName of compIr.hoisted.functions) {
126
+ if (mergeCache?.functionSet instanceof Set) {
127
+ if (mergeCache.functionSet.has(fnName)) {
128
+ continue;
129
+ }
130
+ mergeCache.functionSet.add(fnName);
131
+ }
132
+ else if (pageIr.hoisted.functions.includes(fnName)) {
133
+ continue;
134
+ }
135
+ pageIr.hoisted.functions.push(fnName);
136
+ }
137
+ }
138
+ if (Array.isArray(compIr.hoisted.signals)) {
139
+ for (const signalName of compIr.hoisted.signals) {
140
+ if (mergeCache?.hoistedSignalSet instanceof Set) {
141
+ if (mergeCache.hoistedSignalSet.has(signalName)) {
142
+ continue;
143
+ }
144
+ mergeCache.hoistedSignalSet.add(signalName);
145
+ }
146
+ else if (pageIr.hoisted.signals.includes(signalName)) {
147
+ continue;
148
+ }
149
+ pageIr.hoisted.signals.push(signalName);
150
+ }
151
+ }
152
+ if (Array.isArray(compIr.hoisted.state)) {
153
+ const existingKeys = mergeCache?.stateKeySet instanceof Set
154
+ ? mergeCache.stateKeySet
155
+ : new Set((pageIr.hoisted.state || [])
156
+ .map((entry) => entry && typeof entry === 'object' ? entry.key : null)
157
+ .filter(Boolean));
158
+ for (const stateEntry of compIr.hoisted.state) {
159
+ if (!stateEntry || typeof stateEntry !== 'object') {
160
+ continue;
161
+ }
162
+ if (typeof stateEntry.key !== 'string' || stateEntry.key.length === 0 || existingKeys.has(stateEntry.key)) {
163
+ continue;
164
+ }
165
+ existingKeys.add(stateEntry.key);
166
+ pageIr.hoisted.state.push(stateEntry);
167
+ if (mergeCache?.stateIndexByKey instanceof Map) {
168
+ mergeCache.stateIndexByKey.set(stateEntry.key, pageIr.hoisted.state.length - 1);
169
+ }
170
+ }
171
+ }
172
+ }
173
+ addMergeMetric(mergeMetrics, 'hoistedSymbolsMs', performance.now() - hoistedSymbolsStartedAt);
174
+ const runtimeSignalsStartedAt = performance.now();
175
+ if (options.includeCode && Array.isArray(compIr.signals)) {
176
+ pageIr.signals = Array.isArray(pageIr.signals) ? pageIr.signals : [];
177
+ const existingSignalStateKeys = mergeCache?.runtimeSignalStateKeySet instanceof Set
178
+ ? mergeCache.runtimeSignalStateKeySet
179
+ : new Set(pageIr.signals
180
+ .map((signal) => {
181
+ const stateIndex = signal?.state_index;
182
+ return Number.isInteger(stateIndex) ? pageIr.hoisted.state?.[stateIndex]?.key : null;
183
+ })
184
+ .filter(Boolean));
185
+ for (const signal of compIr.signals) {
186
+ if (!signal || !Number.isInteger(signal.state_index)) {
187
+ continue;
188
+ }
189
+ const stateKey = compIr.hoisted?.state?.[signal.state_index]?.key;
190
+ if (typeof stateKey !== 'string' || stateKey.length === 0) {
191
+ continue;
192
+ }
193
+ const pageStateIndex = mergeCache?.stateIndexByKey instanceof Map
194
+ ? mergeCache.stateIndexByKey.get(stateKey)
195
+ : pageIr.hoisted.state.findIndex((entry) => entry?.key === stateKey);
196
+ if (!Number.isInteger(pageStateIndex) || pageStateIndex < 0 || existingSignalStateKeys.has(stateKey)) {
197
+ continue;
198
+ }
199
+ existingSignalStateKeys.add(stateKey);
200
+ const nextSignalIndex = pageIr.signals.length;
201
+ pageIr.signals.push({
202
+ id: nextSignalIndex,
203
+ kind: typeof signal.kind === 'string' && signal.kind.length > 0 ? signal.kind : 'signal',
204
+ state_index: pageStateIndex
205
+ });
206
+ if (mergeCache?.signalIndexByStateKey instanceof Map && !mergeCache.signalIndexByStateKey.has(stateKey)) {
207
+ mergeCache.signalIndexByStateKey.set(stateKey, nextSignalIndex);
208
+ }
209
+ if (mergeCache?.signalIndicesByStateIndex instanceof Map) {
210
+ const existingIndices = mergeCache.signalIndicesByStateIndex.get(pageStateIndex);
211
+ if (existingIndices) {
212
+ existingIndices.push(nextSignalIndex);
213
+ }
214
+ else {
215
+ mergeCache.signalIndicesByStateIndex.set(pageStateIndex, [nextSignalIndex]);
216
+ }
217
+ }
218
+ }
219
+ }
220
+ addMergeMetric(mergeMetrics, 'runtimeSignalsMs', performance.now() - runtimeSignalsStartedAt);
221
+ const hoistedCodeStartedAt = performance.now();
222
+ if (options.includeCode && compIr.hoisted?.code?.length) {
223
+ for (const block of compIr.hoisted.code) {
224
+ const rebaseStartedAt = performance.now();
225
+ const rebased = rewriteStaticImportsInSource(block, compPath, pageFile);
226
+ addMergeMetric(mergeMetrics, 'codeRebaseImportsMs', performance.now() - rebaseStartedAt);
227
+ const filterImportsStartedAt = performance.now();
228
+ const filteredImports = options.cssImportsOnly ? stripNonCssStaticImportsInSource(rebased) : rebased;
229
+ addMergeMetric(mergeMetrics, 'codeFilterImportsMs', performance.now() - filterImportsStartedAt);
230
+ const transpileStartedAt = performance.now();
231
+ const transpiled = transpileTypeScriptToJs(filteredImports, compPath, transformCache, mergeMetrics);
232
+ addMergeMetric(mergeMetrics, 'codeTranspileMs', performance.now() - transpileStartedAt);
233
+ const propsPreludeStartedAt = performance.now();
234
+ const withPropsPrelude = injectPropsPrelude(transpiled, options.componentAttrs || '', options.componentAttrsRewrite || null);
235
+ addMergeMetric(mergeMetrics, 'codePropsPreludeMs', performance.now() - propsPreludeStartedAt);
236
+ const dedupeImportsStartedAt = performance.now();
237
+ const deduped = dedupeStaticImportsInSource(withPropsPrelude, seenStaticImports);
238
+ addMergeMetric(mergeMetrics, 'codeDedupeImportsMs', performance.now() - dedupeImportsStartedAt);
239
+ const deferRuntimeStartedAt = performance.now();
240
+ const deferred = deferComponentRuntimeBlock(deduped, transformCache, mergeMetrics);
241
+ addMergeMetric(mergeMetrics, 'codeDeferRuntimeMs', performance.now() - deferRuntimeStartedAt);
242
+ if (deferred.trim().length > 0) {
243
+ if (mergeCache?.codeSet instanceof Set) {
244
+ if (mergeCache.codeSet.has(deferred)) {
245
+ continue;
246
+ }
247
+ mergeCache.codeSet.add(deferred);
248
+ }
249
+ else if (pageIr.hoisted.code.includes(deferred)) {
250
+ continue;
251
+ }
252
+ pageIr.hoisted.code.push(deferred);
253
+ }
254
+ }
255
+ }
256
+ addMergeMetric(mergeMetrics, 'hoistedCodeMs', performance.now() - hoistedCodeStartedAt);
257
+ }
@@ -0,0 +1,92 @@
1
+ export function buildPageOwnerContext({ componentOccurrences, sourceFile, pageOwnerSource, compilerOpts, compilerBin, timedRunCompiler, cooperativeYield, templateExpressionCache, expressionRewriteMetrics, startupProfile }: {
2
+ componentOccurrences: any;
3
+ sourceFile: any;
4
+ pageOwnerSource: any;
5
+ compilerOpts: any;
6
+ compilerBin: any;
7
+ timedRunCompiler: any;
8
+ cooperativeYield: any;
9
+ templateExpressionCache: any;
10
+ expressionRewriteMetrics: any;
11
+ startupProfile: any;
12
+ }): Promise<{
13
+ pageOwnerCompileMs: number;
14
+ pageOwnerExpressionRewrite: {
15
+ map: Map<any, any>;
16
+ bindings: Map<any, any>;
17
+ signals: never[];
18
+ stateBindings: never[];
19
+ ambiguous: Set<any>;
20
+ sequence: never[];
21
+ };
22
+ pageOwnerScopeRewrite: {
23
+ map: Map<any, any>;
24
+ ambiguous: Set<any>;
25
+ };
26
+ } | {
27
+ pageOwnerCompileMs: any;
28
+ pageOwnerExpressionRewrite: {
29
+ map: Map<string, string>;
30
+ bindings: Map<string, {
31
+ compiled_expr: string | null;
32
+ signal_index: number | null;
33
+ signal_indices: number[];
34
+ state_index: number | null;
35
+ component_instance: string | null;
36
+ component_binding: string | null;
37
+ }>;
38
+ signals: Array<{
39
+ id?: number;
40
+ kind?: string;
41
+ state_index?: number;
42
+ }>;
43
+ stateBindings: Array<{
44
+ key?: string;
45
+ value?: string;
46
+ }>;
47
+ ambiguous: Set<string>;
48
+ sequence: Array<{
49
+ raw: string;
50
+ rewritten: string;
51
+ binding: object | null;
52
+ }>;
53
+ };
54
+ pageOwnerScopeRewrite: {
55
+ map: Map<string, string>;
56
+ ambiguous: Set<string>;
57
+ };
58
+ }>;
59
+ export function runPageComponentLoop({ componentOccurrences, occurrenceCountByPath, sourceFile, registry, compilerOpts, compilerBin, timedRunCompiler, cooperativeYield, startupProfile, compilerTotals, emitCompilerWarning, componentIrCache, componentDocumentModeCache, componentExpressionRewriteCache, templateExpressionCache, expressionRewriteMetrics, pageOwnerExpressionRewrite, pageOwnerScopeRewrite, pageIr, pageIrMergeCache, seenStaticImports, pageExpressionRewriteMap, pageExpressionBindingMap, pageAmbiguousExpressionMap, knownRefKeys, componentOccurrencePlans, pagePhase, pageBindingResolutionBreakdown, pageMergeBreakdown, pageComponentLoopBreakdown, hoistedCodeTransformCache, pageStats }: {
60
+ componentOccurrences: any;
61
+ occurrenceCountByPath: any;
62
+ sourceFile: any;
63
+ registry: any;
64
+ compilerOpts: any;
65
+ compilerBin: any;
66
+ timedRunCompiler: any;
67
+ cooperativeYield: any;
68
+ startupProfile: any;
69
+ compilerTotals: any;
70
+ emitCompilerWarning: any;
71
+ componentIrCache: any;
72
+ componentDocumentModeCache: any;
73
+ componentExpressionRewriteCache: any;
74
+ templateExpressionCache: any;
75
+ expressionRewriteMetrics: any;
76
+ pageOwnerExpressionRewrite: any;
77
+ pageOwnerScopeRewrite: any;
78
+ pageIr: any;
79
+ pageIrMergeCache: any;
80
+ seenStaticImports: any;
81
+ pageExpressionRewriteMap: any;
82
+ pageExpressionBindingMap: any;
83
+ pageAmbiguousExpressionMap: any;
84
+ knownRefKeys: any;
85
+ componentOccurrencePlans: any;
86
+ pagePhase: any;
87
+ pageBindingResolutionBreakdown: any;
88
+ pageMergeBreakdown: any;
89
+ pageComponentLoopBreakdown: any;
90
+ hoistedCodeTransformCache: any;
91
+ pageStats: any;
92
+ }): Promise<void>;