@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.
- package/dist/build/compiler-runtime.d.ts +59 -0
- package/dist/build/compiler-runtime.js +277 -0
- package/dist/build/expression-rewrites.d.ts +88 -0
- package/dist/build/expression-rewrites.js +372 -0
- package/dist/build/hoisted-code-transforms.d.ts +44 -0
- package/dist/build/hoisted-code-transforms.js +316 -0
- package/dist/build/merge-component-ir.d.ts +16 -0
- package/dist/build/merge-component-ir.js +257 -0
- package/dist/build/page-component-loop.d.ts +92 -0
- package/dist/build/page-component-loop.js +257 -0
- package/dist/build/page-ir-normalization.d.ts +23 -0
- package/dist/build/page-ir-normalization.js +370 -0
- package/dist/build/page-loop-metrics.d.ts +100 -0
- package/dist/build/page-loop-metrics.js +131 -0
- package/dist/build/page-loop-state.d.ts +261 -0
- package/dist/build/page-loop-state.js +92 -0
- package/dist/build/page-loop.d.ts +33 -0
- package/dist/build/page-loop.js +217 -0
- package/dist/build/scoped-identifier-rewrite.d.ts +112 -0
- package/dist/build/scoped-identifier-rewrite.js +245 -0
- package/dist/build/server-script.d.ts +41 -0
- package/dist/build/server-script.js +210 -0
- package/dist/build/type-declarations.d.ts +16 -0
- package/dist/build/type-declarations.js +158 -0
- package/dist/build/typescript-expression-utils.d.ts +23 -0
- package/dist/build/typescript-expression-utils.js +272 -0
- package/dist/build.d.ts +10 -18
- package/dist/build.js +74 -2261
- package/dist/component-instance-ir.d.ts +2 -2
- package/dist/component-instance-ir.js +146 -39
- package/dist/component-occurrences.js +63 -15
- package/dist/config.d.ts +66 -0
- package/dist/config.js +86 -0
- package/dist/debug-script.d.ts +1 -0
- package/dist/debug-script.js +8 -0
- package/dist/dev-build-session.d.ts +23 -0
- package/dist/dev-build-session.js +421 -0
- package/dist/dev-server.js +256 -54
- package/dist/framework-components/Image.zen +316 -0
- package/dist/images/materialize.d.ts +17 -0
- package/dist/images/materialize.js +200 -0
- package/dist/images/payload.d.ts +18 -0
- package/dist/images/payload.js +65 -0
- package/dist/images/runtime.d.ts +4 -0
- package/dist/images/runtime.js +254 -0
- package/dist/images/service.d.ts +4 -0
- package/dist/images/service.js +302 -0
- package/dist/images/shared.d.ts +58 -0
- package/dist/images/shared.js +306 -0
- package/dist/index.js +2 -17
- package/dist/manifest.js +45 -0
- package/dist/preview.d.ts +4 -1
- package/dist/preview.js +59 -6
- package/dist/resolve-components.js +20 -3
- package/dist/server-contract.js +3 -2
- package/dist/server-script-composition.d.ts +39 -0
- package/dist/server-script-composition.js +133 -0
- package/dist/startup-profile.d.ts +10 -0
- package/dist/startup-profile.js +62 -0
- package/dist/toolchain-paths.d.ts +1 -0
- package/dist/toolchain-paths.js +31 -0
- package/dist/version-check.d.ts +2 -1
- package/dist/version-check.js +12 -5
- 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>;
|