@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,257 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { performance } from 'node:perf_hooks';
3
+ import { cloneComponentIrForInstance } from '../component-instance-ir.js';
4
+ import { extractTemplate, isDocumentMode } from '../resolve-components.js';
5
+ import { buildComponentExpressionRewrite, mergeExpressionRewriteMaps, resolveStateKeyFromBindings } from './expression-rewrites.js';
6
+ import { mergeComponentIr } from './merge-component-ir.js';
7
+ import { buildScopedIdentifierRewrite } from './scoped-identifier-rewrite.js';
8
+ import { stripStyleBlocks } from './compiler-runtime.js';
9
+ import { extractDeclaredIdentifiers } from './typescript-expression-utils.js';
10
+ function createEmptyExpressionRewrite() {
11
+ return {
12
+ map: new Map(),
13
+ bindings: new Map(),
14
+ signals: [],
15
+ stateBindings: [],
16
+ ambiguous: new Set(),
17
+ sequence: []
18
+ };
19
+ }
20
+ function createEmptyScopeRewrite() {
21
+ return {
22
+ map: new Map(),
23
+ ambiguous: new Set()
24
+ };
25
+ }
26
+ async function resolveComponentIr({ compPath, componentSource, compilerOpts, compilerBin, timedRunCompiler, cooperativeYield, componentIrCache, compilerTotals, pageStats, startupProfile, emitCompilerWarning }) {
27
+ let compIr;
28
+ if (componentIrCache.has(compPath)) {
29
+ compIr = componentIrCache.get(compPath);
30
+ compilerTotals.componentCacheHits += 1;
31
+ pageStats.pageComponentCacheHits += 1;
32
+ }
33
+ else {
34
+ await cooperativeYield();
35
+ const componentCompileStartedAt = performance.now();
36
+ compIr = timedRunCompiler('component', compPath, stripStyleBlocks(componentSource), compilerOpts, { compilerToolchain: compilerBin, onWarning: emitCompilerWarning });
37
+ pageStats.pageComponentCompileMs += startupProfile.roundMs(performance.now() - componentCompileStartedAt);
38
+ compilerTotals.componentCacheMisses += 1;
39
+ pageStats.pageComponentCacheMisses += 1;
40
+ componentIrCache.set(compPath, compIr);
41
+ }
42
+ return compIr;
43
+ }
44
+ function resolveDocumentMode({ compPath, componentSource, componentDocumentModeCache, pageComponentLoopBreakdown, startupProfile }) {
45
+ let docMode = componentDocumentModeCache.get(compPath);
46
+ if (docMode === undefined) {
47
+ const componentDocModeStartedAt = performance.now();
48
+ docMode = isDocumentMode(extractTemplate(componentSource));
49
+ pageComponentLoopBreakdown.componentDocModeDetectMs += startupProfile.roundMs(performance.now() - componentDocModeStartedAt);
50
+ componentDocumentModeCache.set(compPath, docMode);
51
+ }
52
+ return docMode;
53
+ }
54
+ function resolveComponentExpressionRewrite({ compPath, componentSource, compIr, compilerOpts, compilerBin, templateExpressionCache, expressionRewriteMetrics, componentExpressionRewriteCache, pageComponentLoopBreakdown, startupProfile }) {
55
+ let expressionRewrite = componentExpressionRewriteCache.get(compPath);
56
+ if (!expressionRewrite) {
57
+ const startedAt = performance.now();
58
+ expressionRewrite = buildComponentExpressionRewrite(compPath, componentSource, compIr, compilerOpts, compilerBin, templateExpressionCache, expressionRewriteMetrics);
59
+ pageComponentLoopBreakdown.componentExpressionRewriteBuildMs += startupProfile.roundMs(performance.now() - startedAt);
60
+ componentExpressionRewriteCache.set(compPath, expressionRewrite);
61
+ }
62
+ return expressionRewrite;
63
+ }
64
+ async function resolveOwnerRewriteContext({ occurrence, sourceFile, compilerOpts, compilerBin, timedRunCompiler, cooperativeYield, componentIrCache, componentExpressionRewriteCache, componentScopeRewriteCache, templateExpressionCache, expressionRewriteMetrics, startupProfile, compilerTotals, emitCompilerWarning, pageComponentLoopBreakdown, pageStats, pageOwnerExpressionRewrite, pageOwnerScopeRewrite }) {
65
+ const ownerPath = typeof occurrence.ownerPath === 'string' && occurrence.ownerPath.length > 0
66
+ ? occurrence.ownerPath
67
+ : sourceFile;
68
+ if (ownerPath === sourceFile) {
69
+ return {
70
+ attrExpressionRewrite: pageOwnerExpressionRewrite,
71
+ attrScopeRewrite: pageOwnerScopeRewrite
72
+ };
73
+ }
74
+ let ownerIr = componentIrCache.get(ownerPath);
75
+ let ownerSource = null;
76
+ if (!ownerIr) {
77
+ const ownerSourceReadStartedAt = performance.now();
78
+ ownerSource = readFileSync(ownerPath, 'utf8');
79
+ pageComponentLoopBreakdown.ownerSourceReadMs += startupProfile.roundMs(performance.now() - ownerSourceReadStartedAt);
80
+ await cooperativeYield();
81
+ const ownerCompileStartedAt = performance.now();
82
+ ownerIr = timedRunCompiler('component', ownerPath, stripStyleBlocks(ownerSource), compilerOpts, { compilerToolchain: compilerBin, onWarning: emitCompilerWarning });
83
+ pageStats.pageComponentCompileMs += startupProfile.roundMs(performance.now() - ownerCompileStartedAt);
84
+ compilerTotals.componentCacheMisses += 1;
85
+ pageStats.pageComponentCacheMisses += 1;
86
+ componentIrCache.set(ownerPath, ownerIr);
87
+ }
88
+ else {
89
+ compilerTotals.componentCacheHits += 1;
90
+ pageStats.pageComponentCacheHits += 1;
91
+ }
92
+ let attrExpressionRewrite = componentExpressionRewriteCache.get(ownerPath);
93
+ if (!attrExpressionRewrite) {
94
+ if (!ownerSource) {
95
+ const ownerSourceReadStartedAt = performance.now();
96
+ ownerSource = readFileSync(ownerPath, 'utf8');
97
+ pageComponentLoopBreakdown.ownerSourceReadMs += startupProfile.roundMs(performance.now() - ownerSourceReadStartedAt);
98
+ }
99
+ const startedAt = performance.now();
100
+ attrExpressionRewrite = buildComponentExpressionRewrite(ownerPath, ownerSource, ownerIr, compilerOpts, compilerBin, templateExpressionCache, expressionRewriteMetrics);
101
+ pageComponentLoopBreakdown.ownerExpressionRewriteBuildMs += startupProfile.roundMs(performance.now() - startedAt);
102
+ componentExpressionRewriteCache.set(ownerPath, attrExpressionRewrite);
103
+ }
104
+ let attrScopeRewrite = componentScopeRewriteCache.get(ownerPath);
105
+ if (!attrScopeRewrite) {
106
+ const startedAt = performance.now();
107
+ attrScopeRewrite = buildScopedIdentifierRewrite(ownerIr);
108
+ pageComponentLoopBreakdown.ownerScopeRewriteBuildMs += startupProfile.roundMs(performance.now() - startedAt);
109
+ componentScopeRewriteCache.set(ownerPath, attrScopeRewrite);
110
+ }
111
+ return { attrExpressionRewrite, attrScopeRewrite };
112
+ }
113
+ function resolveInstanceState({ useIsolatedInstance, compIr, compPath, componentSource, compilerOpts, compilerBin, templateExpressionCache, expressionRewriteMetrics, expressionRewrite, startupProfile, pagePhase, componentInstanceCounter }) {
114
+ if (!useIsolatedInstance) {
115
+ return {
116
+ instanceIr: compIr,
117
+ refIdentifierPairs: [],
118
+ instanceRewrite: expressionRewrite,
119
+ componentInstanceCounter
120
+ };
121
+ }
122
+ const cloneStartedAt = performance.now();
123
+ const cloned = cloneComponentIrForInstance(compIr, componentInstanceCounter, extractDeclaredIdentifiers, resolveStateKeyFromBindings);
124
+ pagePhase.cloneMs += startupProfile.roundMs(performance.now() - cloneStartedAt);
125
+ const instanceRewriteStartedAt = performance.now();
126
+ const instanceRewrite = buildComponentExpressionRewrite(compPath, componentSource, cloned.ir, compilerOpts, compilerBin, templateExpressionCache, expressionRewriteMetrics);
127
+ pagePhase.instanceRewriteMs += startupProfile.roundMs(performance.now() - instanceRewriteStartedAt);
128
+ return {
129
+ instanceIr: cloned.ir,
130
+ refIdentifierPairs: cloned.refIdentifierPairs,
131
+ instanceRewrite,
132
+ componentInstanceCounter: componentInstanceCounter + 1
133
+ };
134
+ }
135
+ export async function buildPageOwnerContext({ componentOccurrences, sourceFile, pageOwnerSource, compilerOpts, compilerBin, timedRunCompiler, cooperativeYield, templateExpressionCache, expressionRewriteMetrics, startupProfile }) {
136
+ if (componentOccurrences.length === 0) {
137
+ return {
138
+ pageOwnerCompileMs: 0,
139
+ pageOwnerExpressionRewrite: createEmptyExpressionRewrite(),
140
+ pageOwnerScopeRewrite: createEmptyScopeRewrite()
141
+ };
142
+ }
143
+ await cooperativeYield();
144
+ const ownerStartedAt = performance.now();
145
+ const pageOwnerIr = timedRunCompiler('owner', sourceFile, pageOwnerSource, compilerOpts, { suppressWarnings: true, compilerToolchain: compilerBin });
146
+ const pageOwnerCompileMs = startupProfile.roundMs(performance.now() - ownerStartedAt);
147
+ return {
148
+ pageOwnerCompileMs,
149
+ pageOwnerExpressionRewrite: buildComponentExpressionRewrite(sourceFile, pageOwnerSource, pageOwnerIr, compilerOpts, compilerBin, templateExpressionCache, expressionRewriteMetrics),
150
+ pageOwnerScopeRewrite: buildScopedIdentifierRewrite(pageOwnerIr)
151
+ };
152
+ }
153
+ export async 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 }) {
154
+ const componentScopeRewriteCache = new Map();
155
+ let componentInstanceCounter = 0;
156
+ for (const occurrence of componentOccurrences) {
157
+ await cooperativeYield();
158
+ const compName = occurrence.name;
159
+ const compPath = occurrence.componentPath || registry.get(compName);
160
+ if (!compPath) {
161
+ continue;
162
+ }
163
+ const componentSourceReadStartedAt = performance.now();
164
+ const componentSource = readFileSync(compPath, 'utf8');
165
+ pageComponentLoopBreakdown.componentSourceReadMs += startupProfile.roundMs(performance.now() - componentSourceReadStartedAt);
166
+ const occurrenceCount = occurrenceCountByPath.get(compPath) || 0;
167
+ const compIr = await resolveComponentIr({
168
+ compPath,
169
+ componentSource,
170
+ compilerOpts,
171
+ compilerBin,
172
+ timedRunCompiler,
173
+ cooperativeYield,
174
+ componentIrCache,
175
+ compilerTotals,
176
+ pageStats,
177
+ startupProfile,
178
+ emitCompilerWarning
179
+ });
180
+ const isDocMode = resolveDocumentMode({
181
+ compPath,
182
+ componentSource,
183
+ componentDocumentModeCache,
184
+ pageComponentLoopBreakdown,
185
+ startupProfile
186
+ });
187
+ const expressionRewrite = resolveComponentExpressionRewrite({
188
+ compPath,
189
+ componentSource,
190
+ compIr,
191
+ compilerOpts,
192
+ compilerBin,
193
+ templateExpressionCache,
194
+ expressionRewriteMetrics,
195
+ componentExpressionRewriteCache,
196
+ pageComponentLoopBreakdown,
197
+ startupProfile
198
+ });
199
+ const { attrExpressionRewrite, attrScopeRewrite } = await resolveOwnerRewriteContext({
200
+ occurrence,
201
+ sourceFile,
202
+ compilerOpts,
203
+ compilerBin,
204
+ timedRunCompiler,
205
+ cooperativeYield,
206
+ componentIrCache,
207
+ componentExpressionRewriteCache,
208
+ componentScopeRewriteCache,
209
+ templateExpressionCache,
210
+ expressionRewriteMetrics,
211
+ startupProfile,
212
+ compilerTotals,
213
+ emitCompilerWarning,
214
+ pageComponentLoopBreakdown,
215
+ pageStats,
216
+ pageOwnerExpressionRewrite,
217
+ pageOwnerScopeRewrite
218
+ });
219
+ const useIsolatedInstance = occurrenceCount > 1;
220
+ const instanceState = resolveInstanceState({
221
+ useIsolatedInstance,
222
+ compIr,
223
+ compPath,
224
+ componentSource,
225
+ compilerOpts,
226
+ compilerBin,
227
+ templateExpressionCache,
228
+ expressionRewriteMetrics,
229
+ expressionRewrite,
230
+ startupProfile,
231
+ pagePhase,
232
+ componentInstanceCounter
233
+ });
234
+ componentInstanceCounter = instanceState.componentInstanceCounter;
235
+ const mergeStartedAt = performance.now();
236
+ mergeComponentIr(pageIr, instanceState.instanceIr, compPath, sourceFile, {
237
+ includeCode: true,
238
+ cssImportsOnly: isDocMode,
239
+ documentMode: isDocMode,
240
+ componentAttrs: typeof occurrence.attrs === 'string' ? occurrence.attrs : '',
241
+ componentAttrsRewrite: {
242
+ expressionRewrite: attrExpressionRewrite,
243
+ scopeRewrite: attrScopeRewrite
244
+ }
245
+ }, seenStaticImports, knownRefKeys, pageIrMergeCache, pageMergeBreakdown, hoistedCodeTransformCache);
246
+ pagePhase.mergeMs += startupProfile.roundMs(performance.now() - mergeStartedAt);
247
+ if (useIsolatedInstance) {
248
+ componentOccurrencePlans.push({
249
+ rewrite: instanceState.instanceRewrite,
250
+ expressionSequence: instanceState.instanceRewrite.sequence,
251
+ refSequence: instanceState.refIdentifierPairs
252
+ });
253
+ continue;
254
+ }
255
+ mergeExpressionRewriteMaps(pageExpressionRewriteMap, pageExpressionBindingMap, pageAmbiguousExpressionMap, expressionRewrite, pageIrMergeCache, pageBindingResolutionBreakdown);
256
+ }
257
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @param {object} pageIr
3
+ * @param {Set<string> | null} [preferredKeys]
4
+ */
5
+ export function rewriteRefBindingIdentifiers(pageIr: object, preferredKeys?: Set<string> | null): void;
6
+ /**
7
+ * @param {object} pageIr
8
+ * @param {Map<string, string>} expressionMap
9
+ * @param {Map<string, object>} bindingMap
10
+ * @param {Set<string>} ambiguous
11
+ */
12
+ export function applyExpressionRewrites(pageIr: object, expressionMap: Map<string, string>, bindingMap: Map<string, object>, ambiguous: Set<string>): void;
13
+ /**
14
+ * @param {object} pageIr
15
+ * @param {object} scopeRewrite
16
+ * @param {Record<string, number> | null} [scopedMetrics]
17
+ */
18
+ export function applyScopedIdentifierRewrites(pageIr: object, scopeRewrite: object, scopedMetrics?: Record<string, number> | null): void;
19
+ export function synthesizeSignalBackedCompiledExpressions(pageIr: any): void;
20
+ export function normalizeExpressionBindingDependencies(pageIr: any): void;
21
+ export function normalizeExpressionPayload(pageIr: any): void;
22
+ export function normalizeHoistedSourcePayload(pageIr: any): void;
23
+ export function rewriteLegacyMarkupIdentifiers(pageIr: any): void;
@@ -0,0 +1,370 @@
1
+ import { rewritePropsExpression } from './scoped-identifier-rewrite.js';
2
+ import { resolveStateKeyFromBindings } from './expression-rewrites.js';
3
+ import { expandScopedShorthandPropertiesInSource, normalizeTypeScriptExpression } from './typescript-expression-utils.js';
4
+ /**
5
+ * @param {object} pageIr
6
+ * @param {Set<string> | null} [preferredKeys]
7
+ */
8
+ export function rewriteRefBindingIdentifiers(pageIr, preferredKeys = null) {
9
+ if (!Array.isArray(pageIr?.ref_bindings) || pageIr.ref_bindings.length === 0) {
10
+ return;
11
+ }
12
+ const stateBindings = Array.isArray(pageIr?.hoisted?.state) ? pageIr.hoisted.state : [];
13
+ if (stateBindings.length === 0) {
14
+ return;
15
+ }
16
+ for (const binding of pageIr.ref_bindings) {
17
+ if (!binding || typeof binding !== 'object' || typeof binding.identifier !== 'string') {
18
+ continue;
19
+ }
20
+ const resolved = resolveStateKeyFromBindings(binding.identifier, stateBindings, preferredKeys);
21
+ if (resolved) {
22
+ binding.identifier = resolved;
23
+ }
24
+ }
25
+ }
26
+ /**
27
+ * @param {object} pageIr
28
+ * @param {Map<string, string>} expressionMap
29
+ * @param {Map<string, object>} bindingMap
30
+ * @param {Set<string>} ambiguous
31
+ */
32
+ export function applyExpressionRewrites(pageIr, expressionMap, bindingMap, ambiguous) {
33
+ if (!Array.isArray(pageIr?.expressions) || pageIr.expressions.length === 0) {
34
+ return;
35
+ }
36
+ const bindings = Array.isArray(pageIr.expression_bindings) ? pageIr.expression_bindings : [];
37
+ for (let index = 0; index < pageIr.expressions.length; index++) {
38
+ const current = pageIr.expressions[index];
39
+ if (typeof current !== 'string' || ambiguous.has(current)) {
40
+ continue;
41
+ }
42
+ const rewritten = expressionMap.get(current);
43
+ const rewrittenBinding = bindingMap.get(current);
44
+ if (rewritten && rewritten !== current) {
45
+ pageIr.expressions[index] = rewritten;
46
+ }
47
+ if (!bindings[index] || typeof bindings[index] !== 'object') {
48
+ continue;
49
+ }
50
+ if (rewritten && rewritten !== current && bindings[index].literal === current) {
51
+ bindings[index].literal = rewritten;
52
+ }
53
+ if (rewrittenBinding) {
54
+ bindings[index].compiled_expr = rewrittenBinding.compiled_expr;
55
+ bindings[index].signal_index = rewrittenBinding.signal_index;
56
+ bindings[index].signal_indices = rewrittenBinding.signal_indices;
57
+ bindings[index].state_index = rewrittenBinding.state_index;
58
+ bindings[index].component_instance = rewrittenBinding.component_instance;
59
+ bindings[index].component_binding = rewrittenBinding.component_binding;
60
+ }
61
+ else if (rewritten && rewritten !== current && bindings[index].compiled_expr === current) {
62
+ bindings[index].compiled_expr = rewritten;
63
+ }
64
+ if (!rewrittenBinding &&
65
+ (!rewritten || rewritten === current) &&
66
+ bindings[index].literal === current &&
67
+ bindings[index].compiled_expr === current) {
68
+ bindings[index].compiled_expr = current;
69
+ }
70
+ }
71
+ }
72
+ /**
73
+ * @param {object} pageIr
74
+ * @param {object} scopeRewrite
75
+ * @param {Record<string, number> | null} [scopedMetrics]
76
+ */
77
+ export function applyScopedIdentifierRewrites(pageIr, scopeRewrite, scopedMetrics = null) {
78
+ if (!Array.isArray(pageIr?.expressions) || pageIr.expressions.length === 0) {
79
+ return;
80
+ }
81
+ const bindings = Array.isArray(pageIr.expression_bindings) ? pageIr.expression_bindings : [];
82
+ const scopeMap = scopeRewrite?.map instanceof Map ? scopeRewrite.map : null;
83
+ const scopeAmbiguous = scopeRewrite?.ambiguous instanceof Set ? scopeRewrite.ambiguous : null;
84
+ const scopeCandidates = scopeMap instanceof Map
85
+ ? new Set([...scopeMap.keys()].filter((identifier) => typeof identifier === 'string'
86
+ && identifier.length > 0
87
+ && !(scopeAmbiguous instanceof Set && scopeAmbiguous.has(identifier))))
88
+ : null;
89
+ const rewriteContext = { scopeRewrite };
90
+ const rewriteCache = new Map();
91
+ const shouldCheckIdentifierCandidate = (charCode, isStart) => {
92
+ if (charCode === 36 || charCode === 95)
93
+ return true;
94
+ if (charCode >= 65 && charCode <= 90)
95
+ return true;
96
+ if (charCode >= 97 && charCode <= 122)
97
+ return true;
98
+ if (!isStart && charCode >= 48 && charCode <= 57)
99
+ return true;
100
+ return false;
101
+ };
102
+ const canSkipScopedRewrite = (value) => {
103
+ if (!(scopeCandidates instanceof Set) || scopeCandidates.size === 0) {
104
+ return true;
105
+ }
106
+ let token = '';
107
+ for (let index = 0; index < value.length; index++) {
108
+ const charCode = value.charCodeAt(index);
109
+ if (shouldCheckIdentifierCandidate(charCode, token.length === 0)) {
110
+ token += value[index];
111
+ continue;
112
+ }
113
+ if (token.length > 0) {
114
+ if (scopeCandidates.has(token)) {
115
+ return false;
116
+ }
117
+ token = '';
118
+ }
119
+ }
120
+ return token.length > 0 ? !scopeCandidates.has(token) : true;
121
+ };
122
+ const addScopedMetric = (key, value) => {
123
+ if (!scopedMetrics || typeof scopedMetrics !== 'object' || !Number.isFinite(value)) {
124
+ return;
125
+ }
126
+ scopedMetrics[key] = (scopedMetrics[key] || 0) + value;
127
+ };
128
+ const rewriteScoped = (value) => {
129
+ if (typeof value !== 'string') {
130
+ return value;
131
+ }
132
+ addScopedMetric('totalValues', 1);
133
+ const cached = rewriteCache.get(value);
134
+ if (typeof cached === 'string') {
135
+ addScopedMetric('cacheHitCount', 1);
136
+ return cached;
137
+ }
138
+ addScopedMetric('cacheMissCount', 1);
139
+ const missStartedAt = performance.now();
140
+ const identifierCheckStartedAt = performance.now();
141
+ const shouldSkip = canSkipScopedRewrite(value);
142
+ const identifierCheckMs = performance.now() - identifierCheckStartedAt;
143
+ addScopedMetric('identifierCheckMs', identifierCheckMs);
144
+ if (shouldSkip) {
145
+ addScopedMetric('fastSkipCount', 1);
146
+ addScopedMetric('fastSkipMs', identifierCheckMs);
147
+ rewriteCache.set(value, value);
148
+ addScopedMetric('unchangedMissCount', 1);
149
+ addScopedMetric('cacheMissMs', performance.now() - missStartedAt);
150
+ return value;
151
+ }
152
+ const rewriteCallStartedAt = performance.now();
153
+ const rewritten = rewritePropsExpression(value, rewriteContext);
154
+ addScopedMetric('rewriteCallMs', performance.now() - rewriteCallStartedAt);
155
+ addScopedMetric(rewritten === value ? 'unchangedMissCount' : 'changedMissCount', 1);
156
+ addScopedMetric('cacheMissMs', performance.now() - missStartedAt);
157
+ rewriteCache.set(value, rewritten);
158
+ return rewritten;
159
+ };
160
+ for (let index = 0; index < pageIr.expressions.length; index++) {
161
+ const current = pageIr.expressions[index];
162
+ if (typeof current === 'string') {
163
+ pageIr.expressions[index] = rewriteScoped(current);
164
+ }
165
+ if (!bindings[index] || typeof bindings[index] !== 'object') {
166
+ continue;
167
+ }
168
+ if (typeof bindings[index].literal === 'string') {
169
+ bindings[index].literal = rewriteScoped(bindings[index].literal);
170
+ }
171
+ if (typeof bindings[index].compiled_expr === 'string') {
172
+ bindings[index].compiled_expr = rewriteScoped(bindings[index].compiled_expr);
173
+ }
174
+ }
175
+ }
176
+ export function synthesizeSignalBackedCompiledExpressions(pageIr) {
177
+ if (!Array.isArray(pageIr?.expression_bindings) || pageIr.expression_bindings.length === 0) {
178
+ return;
179
+ }
180
+ const stateBindings = Array.isArray(pageIr?.hoisted?.state) ? pageIr.hoisted.state : [];
181
+ const signals = Array.isArray(pageIr?.signals) ? pageIr.signals : [];
182
+ if (stateBindings.length === 0 || signals.length === 0) {
183
+ return;
184
+ }
185
+ const signalBackedStateIndices = new Set(signals
186
+ .map((signal) => signal?.state_index)
187
+ .filter((value) => Number.isInteger(value)));
188
+ const signalIndexByStateKey = new Map();
189
+ for (let index = 0; index < signals.length; index++) {
190
+ const stateIndex = signals[index]?.state_index;
191
+ const stateKey = Number.isInteger(stateIndex) ? stateBindings[stateIndex]?.key : null;
192
+ if (typeof stateKey === 'string' && stateKey.length > 0) {
193
+ signalIndexByStateKey.set(stateKey, index);
194
+ }
195
+ }
196
+ if (signalIndexByStateKey.size === 0) {
197
+ return;
198
+ }
199
+ for (let index = 0; index < pageIr.expression_bindings.length; index++) {
200
+ const binding = pageIr.expression_bindings[index];
201
+ if (!binding || typeof binding !== 'object') {
202
+ continue;
203
+ }
204
+ if (typeof binding.compiled_expr === 'string' && binding.compiled_expr.includes('signalMap.get(')) {
205
+ continue;
206
+ }
207
+ const candidate = typeof binding.literal === 'string' && binding.literal.trim().length > 0
208
+ ? binding.literal
209
+ : typeof pageIr.expressions?.[index] === 'string'
210
+ ? pageIr.expressions[index]
211
+ : null;
212
+ if (typeof candidate !== 'string' || candidate.trim().length === 0) {
213
+ continue;
214
+ }
215
+ if (Number.isInteger(binding.state_index) &&
216
+ !signalBackedStateIndices.has(binding.state_index)) {
217
+ continue;
218
+ }
219
+ let rewritten = candidate;
220
+ const signalIndices = [];
221
+ for (const [stateKey, signalIndex] of signalIndexByStateKey.entries()) {
222
+ if (!rewritten.includes(stateKey)) {
223
+ continue;
224
+ }
225
+ const escaped = stateKey.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
226
+ const pattern = new RegExp(`(?<!\\.)\\b${escaped}\\b`, 'g');
227
+ if (!pattern.test(rewritten)) {
228
+ continue;
229
+ }
230
+ rewritten = rewritten.replace(pattern, `signalMap.get(${signalIndex}).get()`);
231
+ signalIndices.push(signalIndex);
232
+ }
233
+ if (rewritten === candidate || signalIndices.length === 0) {
234
+ continue;
235
+ }
236
+ const uniqueSignalIndices = [...new Set(signalIndices)].sort((a, b) => a - b);
237
+ binding.compiled_expr = rewritten;
238
+ binding.signal_indices = uniqueSignalIndices;
239
+ if (uniqueSignalIndices.length === 1) {
240
+ binding.signal_index = uniqueSignalIndices[0];
241
+ const stateIndex = signals[uniqueSignalIndices[0]]?.state_index;
242
+ if (Number.isInteger(stateIndex)) {
243
+ binding.state_index = stateIndex;
244
+ }
245
+ }
246
+ }
247
+ }
248
+ export function normalizeExpressionBindingDependencies(pageIr) {
249
+ if (!Array.isArray(pageIr?.expression_bindings) || pageIr.expression_bindings.length === 0) {
250
+ return;
251
+ }
252
+ const signals = Array.isArray(pageIr.signals) ? pageIr.signals : [];
253
+ const dependencyRe = /signalMap\.get\((\d+)\)/g;
254
+ for (const binding of pageIr.expression_bindings) {
255
+ if (!binding || typeof binding !== 'object' || typeof binding.compiled_expr !== 'string') {
256
+ continue;
257
+ }
258
+ const indices = [];
259
+ dependencyRe.lastIndex = 0;
260
+ let match;
261
+ while ((match = dependencyRe.exec(binding.compiled_expr)) !== null) {
262
+ const index = Number.parseInt(match[1], 10);
263
+ if (Number.isInteger(index)) {
264
+ indices.push(index);
265
+ }
266
+ }
267
+ if (indices.length === 0) {
268
+ continue;
269
+ }
270
+ let signalIndices = [...new Set(indices)].sort((a, b) => a - b);
271
+ if (Number.isInteger(binding.state_index)) {
272
+ const owningSignalIndices = signals
273
+ .map((signal, index) => signal?.state_index === binding.state_index ? index : null)
274
+ .filter((value) => Number.isInteger(value));
275
+ const extractedMatchState = signalIndices.length > 0 &&
276
+ signalIndices.every((index) => signals[index]?.state_index === binding.state_index);
277
+ if (owningSignalIndices.length > 0 && !extractedMatchState) {
278
+ signalIndices = owningSignalIndices;
279
+ }
280
+ }
281
+ if (!Array.isArray(binding.signal_indices) ||
282
+ binding.signal_indices.length === 0 ||
283
+ binding.signal_indices.some((index) => signals[index]?.state_index !== binding.state_index)) {
284
+ binding.signal_indices = signalIndices;
285
+ }
286
+ if ((!Number.isInteger(binding.signal_index) ||
287
+ signals[binding.signal_index]?.state_index !== binding.state_index) &&
288
+ signalIndices.length === 1) {
289
+ binding.signal_index = signalIndices[0];
290
+ }
291
+ if (!Number.isInteger(binding.state_index) && Number.isInteger(binding.signal_index)) {
292
+ const stateIndex = signals[binding.signal_index]?.state_index;
293
+ if (Number.isInteger(stateIndex)) {
294
+ binding.state_index = stateIndex;
295
+ }
296
+ }
297
+ if (signalIndices.length === 1) {
298
+ binding.compiled_expr = binding.compiled_expr.replace(/signalMap\.get\(\d+\)/g, `signalMap.get(${signalIndices[0]})`);
299
+ }
300
+ }
301
+ }
302
+ export function normalizeExpressionPayload(pageIr) {
303
+ if (!Array.isArray(pageIr?.expressions) || pageIr.expressions.length === 0) {
304
+ return;
305
+ }
306
+ const bindings = Array.isArray(pageIr.expression_bindings) ? pageIr.expression_bindings : [];
307
+ for (let index = 0; index < pageIr.expressions.length; index++) {
308
+ if (typeof pageIr.expressions[index] === 'string') {
309
+ pageIr.expressions[index] = normalizeTypeScriptExpression(pageIr.expressions[index]);
310
+ }
311
+ const binding = bindings[index];
312
+ if (!binding || typeof binding !== 'object') {
313
+ continue;
314
+ }
315
+ if (typeof binding.literal === 'string') {
316
+ binding.literal = normalizeTypeScriptExpression(binding.literal);
317
+ }
318
+ if (typeof binding.compiled_expr === 'string') {
319
+ binding.compiled_expr = normalizeTypeScriptExpression(binding.compiled_expr);
320
+ }
321
+ }
322
+ }
323
+ export function normalizeHoistedSourcePayload(pageIr) {
324
+ const declarations = Array.isArray(pageIr?.hoisted?.declarations) ? pageIr.hoisted.declarations : null;
325
+ if (declarations) {
326
+ pageIr.hoisted.declarations = declarations.map((entry) => {
327
+ if (typeof entry !== 'string') {
328
+ return entry;
329
+ }
330
+ return expandScopedShorthandPropertiesInSource(entry);
331
+ });
332
+ }
333
+ const codeBlocks = Array.isArray(pageIr?.hoisted?.code) ? pageIr.hoisted.code : null;
334
+ if (codeBlocks) {
335
+ pageIr.hoisted.code = codeBlocks.map((entry) => {
336
+ if (typeof entry !== 'string') {
337
+ return entry;
338
+ }
339
+ return expandScopedShorthandPropertiesInSource(entry);
340
+ });
341
+ }
342
+ }
343
+ const LEGACY_MARKUP_IDENT = 'zen' + 'html';
344
+ const LEGACY_MARKUP_RE = new RegExp(`\\b${LEGACY_MARKUP_IDENT}\\b`, 'g');
345
+ export function rewriteLegacyMarkupIdentifiers(pageIr) {
346
+ if (!Array.isArray(pageIr?.expressions) || pageIr.expressions.length === 0) {
347
+ return;
348
+ }
349
+ const bindings = Array.isArray(pageIr.expression_bindings) ? pageIr.expression_bindings : [];
350
+ for (let i = 0; i < pageIr.expressions.length; i++) {
351
+ if (typeof pageIr.expressions[i] === 'string' && pageIr.expressions[i].includes(LEGACY_MARKUP_IDENT)) {
352
+ LEGACY_MARKUP_RE.lastIndex = 0;
353
+ pageIr.expressions[i] = pageIr.expressions[i].replace(LEGACY_MARKUP_RE, '__ZENITH_INTERNAL_ZENHTML');
354
+ }
355
+ if (bindings[i] &&
356
+ typeof bindings[i] === 'object' &&
357
+ typeof bindings[i].literal === 'string' &&
358
+ bindings[i].literal.includes(LEGACY_MARKUP_IDENT)) {
359
+ LEGACY_MARKUP_RE.lastIndex = 0;
360
+ bindings[i].literal = bindings[i].literal.replace(LEGACY_MARKUP_RE, '__ZENITH_INTERNAL_ZENHTML');
361
+ }
362
+ if (bindings[i] &&
363
+ typeof bindings[i] === 'object' &&
364
+ typeof bindings[i].compiled_expr === 'string' &&
365
+ bindings[i].compiled_expr.includes(LEGACY_MARKUP_IDENT)) {
366
+ LEGACY_MARKUP_RE.lastIndex = 0;
367
+ bindings[i].compiled_expr = bindings[i].compiled_expr.replace(LEGACY_MARKUP_RE, '__ZENITH_INTERNAL_ZENHTML');
368
+ }
369
+ }
370
+ }