@zenithbuild/cli 0.7.3 → 0.7.4

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 (54) hide show
  1. package/README.md +14 -11
  2. package/dist/adapters/adapter-netlify.js +1 -0
  3. package/dist/adapters/adapter-node.js +8 -0
  4. package/dist/adapters/adapter-vercel.js +1 -0
  5. package/dist/build/compiler-runtime.d.ts +10 -9
  6. package/dist/build/compiler-runtime.js +51 -1
  7. package/dist/build/compiler-signal-expression.d.ts +1 -0
  8. package/dist/build/compiler-signal-expression.js +155 -0
  9. package/dist/build/expression-rewrites.d.ts +1 -6
  10. package/dist/build/expression-rewrites.js +61 -65
  11. package/dist/build/page-component-loop.d.ts +3 -13
  12. package/dist/build/page-component-loop.js +21 -46
  13. package/dist/build/page-ir-normalization.d.ts +0 -8
  14. package/dist/build/page-ir-normalization.js +13 -234
  15. package/dist/build/page-loop-state.d.ts +6 -9
  16. package/dist/build/page-loop-state.js +9 -8
  17. package/dist/build/page-loop.js +27 -22
  18. package/dist/build/scoped-identifier-rewrite.d.ts +37 -44
  19. package/dist/build/scoped-identifier-rewrite.js +28 -128
  20. package/dist/build/server-script.d.ts +2 -1
  21. package/dist/build/server-script.js +29 -3
  22. package/dist/build.js +5 -3
  23. package/dist/component-instance-ir.js +158 -52
  24. package/dist/dev-build-session.js +20 -6
  25. package/dist/dev-server.js +82 -39
  26. package/dist/framework-components/Image.zen +1 -1
  27. package/dist/images/materialization-plan.d.ts +1 -0
  28. package/dist/images/materialization-plan.js +6 -0
  29. package/dist/images/materialize.d.ts +5 -3
  30. package/dist/images/materialize.js +24 -109
  31. package/dist/images/router-manifest.d.ts +1 -0
  32. package/dist/images/router-manifest.js +49 -0
  33. package/dist/index.js +8 -2
  34. package/dist/manifest.js +3 -2
  35. package/dist/preview.d.ts +4 -3
  36. package/dist/preview.js +87 -53
  37. package/dist/request-body.d.ts +2 -0
  38. package/dist/request-body.js +13 -0
  39. package/dist/request-origin.d.ts +2 -0
  40. package/dist/request-origin.js +45 -0
  41. package/dist/route-check-support.d.ts +1 -0
  42. package/dist/route-check-support.js +4 -0
  43. package/dist/server-contract.d.ts +15 -0
  44. package/dist/server-contract.js +102 -32
  45. package/dist/server-error.d.ts +4 -0
  46. package/dist/server-error.js +34 -0
  47. package/dist/server-output.d.ts +2 -0
  48. package/dist/server-output.js +13 -0
  49. package/dist/server-runtime/node-server.js +33 -27
  50. package/dist/server-runtime/route-render.d.ts +3 -3
  51. package/dist/server-runtime/route-render.js +20 -31
  52. package/dist/server-script-composition.d.ts +11 -5
  53. package/dist/server-script-composition.js +25 -10
  54. package/package.json +6 -3
@@ -1,10 +1,10 @@
1
1
  import { readFileSync } from 'node:fs';
2
2
  import { performance } from 'node:perf_hooks';
3
3
  import { cloneComponentIrForInstance } from '../component-instance-ir.js';
4
+ import { renderPropsLiteralFromAttrs } from './scoped-identifier-rewrite.js';
4
5
  import { extractTemplate, isDocumentMode } from '../resolve-components.js';
5
6
  import { buildComponentExpressionRewrite, mergeExpressionRewriteMaps, resolveStateKeyFromBindings } from './expression-rewrites.js';
6
7
  import { mergeComponentIr } from './merge-component-ir.js';
7
- import { buildScopedIdentifierRewrite } from './scoped-identifier-rewrite.js';
8
8
  import { stripStyleBlocks } from './compiler-runtime.js';
9
9
  import { extractDeclaredIdentifiers } from './typescript-expression-utils.js';
10
10
  function createEmptyExpressionRewrite() {
@@ -17,12 +17,6 @@ function createEmptyExpressionRewrite() {
17
17
  sequence: []
18
18
  };
19
19
  }
20
- function createEmptyScopeRewrite() {
21
- return {
22
- map: new Map(),
23
- ambiguous: new Set()
24
- };
25
- }
26
20
  async function resolveComponentIr({ compPath, componentSource, compilerOpts, compilerBin, timedRunCompiler, cooperativeYield, componentIrCache, compilerTotals, pageStats, startupProfile, emitCompilerWarning }) {
27
21
  let compIr;
28
22
  if (componentIrCache.has(compPath)) {
@@ -51,24 +45,23 @@ function resolveDocumentMode({ compPath, componentSource, componentDocumentModeC
51
45
  }
52
46
  return docMode;
53
47
  }
54
- function resolveComponentExpressionRewrite({ compPath, componentSource, compIr, compilerOpts, compilerBin, templateExpressionCache, expressionRewriteMetrics, componentExpressionRewriteCache, pageComponentLoopBreakdown, startupProfile }) {
48
+ function resolveComponentExpressionRewrite({ compPath, compIr, expressionRewriteMetrics, componentExpressionRewriteCache, pageComponentLoopBreakdown, startupProfile }) {
55
49
  let expressionRewrite = componentExpressionRewriteCache.get(compPath);
56
50
  if (!expressionRewrite) {
57
51
  const startedAt = performance.now();
58
- expressionRewrite = buildComponentExpressionRewrite(compPath, componentSource, compIr, compilerOpts, compilerBin, templateExpressionCache, expressionRewriteMetrics);
52
+ expressionRewrite = buildComponentExpressionRewrite(compIr, expressionRewriteMetrics);
59
53
  pageComponentLoopBreakdown.componentExpressionRewriteBuildMs += startupProfile.roundMs(performance.now() - startedAt);
60
54
  componentExpressionRewriteCache.set(compPath, expressionRewrite);
61
55
  }
62
56
  return expressionRewrite;
63
57
  }
64
- async function resolveOwnerRewriteContext({ occurrence, sourceFile, compilerOpts, compilerBin, timedRunCompiler, cooperativeYield, componentIrCache, componentExpressionRewriteCache, componentScopeRewriteCache, templateExpressionCache, expressionRewriteMetrics, startupProfile, compilerTotals, emitCompilerWarning, pageComponentLoopBreakdown, pageStats, pageOwnerExpressionRewrite, pageOwnerScopeRewrite }) {
58
+ async function resolveOwnerRewriteContext({ occurrence, sourceFile, compilerOpts, compilerBin, timedRunCompiler, cooperativeYield, componentIrCache, componentExpressionRewriteCache, expressionRewriteMetrics, startupProfile, compilerTotals, emitCompilerWarning, pageComponentLoopBreakdown, pageStats, pageOwnerExpressionRewrite }) {
65
59
  const ownerPath = typeof occurrence.ownerPath === 'string' && occurrence.ownerPath.length > 0
66
60
  ? occurrence.ownerPath
67
61
  : sourceFile;
68
62
  if (ownerPath === sourceFile) {
69
63
  return {
70
- attrExpressionRewrite: pageOwnerExpressionRewrite,
71
- attrScopeRewrite: pageOwnerScopeRewrite
64
+ attrExpressionRewrite: pageOwnerExpressionRewrite
72
65
  };
73
66
  }
74
67
  let ownerIr = componentIrCache.get(ownerPath);
@@ -97,20 +90,13 @@ async function resolveOwnerRewriteContext({ occurrence, sourceFile, compilerOpts
97
90
  pageComponentLoopBreakdown.ownerSourceReadMs += startupProfile.roundMs(performance.now() - ownerSourceReadStartedAt);
98
91
  }
99
92
  const startedAt = performance.now();
100
- attrExpressionRewrite = buildComponentExpressionRewrite(ownerPath, ownerSource, ownerIr, compilerOpts, compilerBin, templateExpressionCache, expressionRewriteMetrics);
93
+ attrExpressionRewrite = buildComponentExpressionRewrite(ownerIr, expressionRewriteMetrics);
101
94
  pageComponentLoopBreakdown.ownerExpressionRewriteBuildMs += startupProfile.roundMs(performance.now() - startedAt);
102
95
  componentExpressionRewriteCache.set(ownerPath, attrExpressionRewrite);
103
96
  }
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 };
97
+ return { attrExpressionRewrite };
112
98
  }
113
- function resolveInstanceState({ useIsolatedInstance, compIr, compPath, componentSource, compilerOpts, compilerBin, templateExpressionCache, expressionRewriteMetrics, expressionRewrite, startupProfile, pagePhase, componentInstanceCounter }) {
99
+ function resolveInstanceState({ useIsolatedInstance, compIr, expressionRewriteMetrics, expressionRewrite, startupProfile, pagePhase, componentInstanceCounter }) {
114
100
  if (!useIsolatedInstance) {
115
101
  return {
116
102
  instanceIr: compIr,
@@ -123,7 +109,7 @@ function resolveInstanceState({ useIsolatedInstance, compIr, compPath, component
123
109
  const cloned = cloneComponentIrForInstance(compIr, componentInstanceCounter, extractDeclaredIdentifiers, resolveStateKeyFromBindings);
124
110
  pagePhase.cloneMs += startupProfile.roundMs(performance.now() - cloneStartedAt);
125
111
  const instanceRewriteStartedAt = performance.now();
126
- const instanceRewrite = buildComponentExpressionRewrite(compPath, componentSource, cloned.ir, compilerOpts, compilerBin, templateExpressionCache, expressionRewriteMetrics);
112
+ const instanceRewrite = buildComponentExpressionRewrite(cloned.ir, expressionRewriteMetrics);
127
113
  pagePhase.instanceRewriteMs += startupProfile.roundMs(performance.now() - instanceRewriteStartedAt);
128
114
  return {
129
115
  instanceIr: cloned.ir,
@@ -132,12 +118,11 @@ function resolveInstanceState({ useIsolatedInstance, compIr, compPath, component
132
118
  componentInstanceCounter: componentInstanceCounter + 1
133
119
  };
134
120
  }
135
- export async function buildPageOwnerContext({ componentOccurrences, sourceFile, pageOwnerSource, compilerOpts, compilerBin, timedRunCompiler, cooperativeYield, templateExpressionCache, expressionRewriteMetrics, startupProfile }) {
121
+ export async function buildPageOwnerContext({ componentOccurrences, sourceFile, pageOwnerSource, compilerOpts, compilerBin, timedRunCompiler, cooperativeYield, expressionRewriteMetrics, startupProfile }) {
136
122
  if (componentOccurrences.length === 0) {
137
123
  return {
138
124
  pageOwnerCompileMs: 0,
139
- pageOwnerExpressionRewrite: createEmptyExpressionRewrite(),
140
- pageOwnerScopeRewrite: createEmptyScopeRewrite()
125
+ pageOwnerExpressionRewrite: createEmptyExpressionRewrite()
141
126
  };
142
127
  }
143
128
  await cooperativeYield();
@@ -146,12 +131,10 @@ export async function buildPageOwnerContext({ componentOccurrences, sourceFile,
146
131
  const pageOwnerCompileMs = startupProfile.roundMs(performance.now() - ownerStartedAt);
147
132
  return {
148
133
  pageOwnerCompileMs,
149
- pageOwnerExpressionRewrite: buildComponentExpressionRewrite(sourceFile, pageOwnerSource, pageOwnerIr, compilerOpts, compilerBin, templateExpressionCache, expressionRewriteMetrics),
150
- pageOwnerScopeRewrite: buildScopedIdentifierRewrite(pageOwnerIr)
134
+ pageOwnerExpressionRewrite: buildComponentExpressionRewrite(pageOwnerIr, expressionRewriteMetrics)
151
135
  };
152
136
  }
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();
137
+ export async function runPageComponentLoop({ componentOccurrences, occurrenceCountByPath, sourceFile, registry, compilerOpts, compilerBin, timedRunCompiler, cooperativeYield, startupProfile, compilerTotals, emitCompilerWarning, componentIrCache, componentDocumentModeCache, componentExpressionRewriteCache, expressionRewriteMetrics, pageOwnerExpressionRewrite, pageIr, pageIrMergeCache, seenStaticImports, pageExpressionRewriteMap, pageExpressionBindingMap, pageAmbiguousExpressionMap, knownRefKeys, componentOccurrencePlans, imagePropsLiterals, pagePhase, pageBindingResolutionBreakdown, pageMergeBreakdown, pageComponentLoopBreakdown, hoistedCodeTransformCache, pageStats }) {
155
138
  let componentInstanceCounter = 0;
156
139
  for (const occurrence of componentOccurrences) {
157
140
  await cooperativeYield();
@@ -186,17 +169,13 @@ export async function runPageComponentLoop({ componentOccurrences, occurrenceCou
186
169
  });
187
170
  const expressionRewrite = resolveComponentExpressionRewrite({
188
171
  compPath,
189
- componentSource,
190
172
  compIr,
191
- compilerOpts,
192
- compilerBin,
193
- templateExpressionCache,
194
173
  expressionRewriteMetrics,
195
174
  componentExpressionRewriteCache,
196
175
  pageComponentLoopBreakdown,
197
176
  startupProfile
198
177
  });
199
- const { attrExpressionRewrite, attrScopeRewrite } = await resolveOwnerRewriteContext({
178
+ const { attrExpressionRewrite } = await resolveOwnerRewriteContext({
200
179
  occurrence,
201
180
  sourceFile,
202
181
  compilerOpts,
@@ -205,26 +184,23 @@ export async function runPageComponentLoop({ componentOccurrences, occurrenceCou
205
184
  cooperativeYield,
206
185
  componentIrCache,
207
186
  componentExpressionRewriteCache,
208
- componentScopeRewriteCache,
209
- templateExpressionCache,
210
187
  expressionRewriteMetrics,
211
188
  startupProfile,
212
189
  compilerTotals,
213
190
  emitCompilerWarning,
214
191
  pageComponentLoopBreakdown,
215
192
  pageStats,
216
- pageOwnerExpressionRewrite,
217
- pageOwnerScopeRewrite
193
+ pageOwnerExpressionRewrite
218
194
  });
195
+ if (compName === 'Image') {
196
+ imagePropsLiterals.push(renderPropsLiteralFromAttrs(occurrence.attrs || '', {
197
+ expressionRewrite: attrExpressionRewrite
198
+ }));
199
+ }
219
200
  const useIsolatedInstance = occurrenceCount > 1;
220
201
  const instanceState = resolveInstanceState({
221
202
  useIsolatedInstance,
222
203
  compIr,
223
- compPath,
224
- componentSource,
225
- compilerOpts,
226
- compilerBin,
227
- templateExpressionCache,
228
204
  expressionRewriteMetrics,
229
205
  expressionRewrite,
230
206
  startupProfile,
@@ -239,8 +215,7 @@ export async function runPageComponentLoop({ componentOccurrences, occurrenceCou
239
215
  documentMode: isDocMode,
240
216
  componentAttrs: typeof occurrence.attrs === 'string' ? occurrence.attrs : '',
241
217
  componentAttrsRewrite: {
242
- expressionRewrite: attrExpressionRewrite,
243
- scopeRewrite: attrScopeRewrite
218
+ expressionRewrite: attrExpressionRewrite
244
219
  }
245
220
  }, seenStaticImports, knownRefKeys, pageIrMergeCache, pageMergeBreakdown, hoistedCodeTransformCache);
246
221
  pagePhase.mergeMs += startupProfile.roundMs(performance.now() - mergeStartedAt);
@@ -10,14 +10,6 @@ export function rewriteRefBindingIdentifiers(pageIr: object, preferredKeys?: Set
10
10
  * @param {Set<string>} ambiguous
11
11
  */
12
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
13
  export function normalizeExpressionPayload(pageIr: any): void;
22
14
  export function normalizeHoistedSourcePayload(pageIr: any): void;
23
15
  export function rewriteLegacyMarkupIdentifiers(pageIr: any): void;
@@ -1,4 +1,3 @@
1
- import { rewritePropsExpression } from './scoped-identifier-rewrite.js';
2
1
  import { resolveStateKeyFromBindings } from './expression-rewrites.js';
3
2
  import { expandScopedShorthandPropertiesInSource, normalizeTypeScriptExpression } from './typescript-expression-utils.js';
4
3
  /**
@@ -69,236 +68,6 @@ export function applyExpressionRewrites(pageIr, expressionMap, bindingMap, ambig
69
68
  }
70
69
  }
71
70
  }
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
71
  export function normalizeExpressionPayload(pageIr) {
303
72
  if (!Array.isArray(pageIr?.expressions) || pageIr.expressions.length === 0) {
304
73
  return;
@@ -347,24 +116,34 @@ export function rewriteLegacyMarkupIdentifiers(pageIr) {
347
116
  return;
348
117
  }
349
118
  const bindings = Array.isArray(pageIr.expression_bindings) ? pageIr.expression_bindings : [];
119
+ function failLegacyMarkup(source) {
120
+ throw new Error(`[Zenith:Build] Legacy ${LEGACY_MARKUP_IDENT}\`...\` markup syntax is unsupported. ` +
121
+ 'Use embedded markup expressions with embeddedMarkupExpressions: true, or unsafeHTML={value} for explicit raw HTML.');
122
+ }
350
123
  for (let i = 0; i < pageIr.expressions.length; i++) {
351
124
  if (typeof pageIr.expressions[i] === 'string' && pageIr.expressions[i].includes(LEGACY_MARKUP_IDENT)) {
352
125
  LEGACY_MARKUP_RE.lastIndex = 0;
353
- pageIr.expressions[i] = pageIr.expressions[i].replace(LEGACY_MARKUP_RE, '__ZENITH_INTERNAL_ZENHTML');
126
+ if (LEGACY_MARKUP_RE.test(pageIr.expressions[i])) {
127
+ failLegacyMarkup(pageIr.expressions[i]);
128
+ }
354
129
  }
355
130
  if (bindings[i] &&
356
131
  typeof bindings[i] === 'object' &&
357
132
  typeof bindings[i].literal === 'string' &&
358
133
  bindings[i].literal.includes(LEGACY_MARKUP_IDENT)) {
359
134
  LEGACY_MARKUP_RE.lastIndex = 0;
360
- bindings[i].literal = bindings[i].literal.replace(LEGACY_MARKUP_RE, '__ZENITH_INTERNAL_ZENHTML');
135
+ if (LEGACY_MARKUP_RE.test(bindings[i].literal)) {
136
+ failLegacyMarkup(bindings[i].literal);
137
+ }
361
138
  }
362
139
  if (bindings[i] &&
363
140
  typeof bindings[i] === 'object' &&
364
141
  typeof bindings[i].compiled_expr === 'string' &&
365
142
  bindings[i].compiled_expr.includes(LEGACY_MARKUP_IDENT)) {
366
143
  LEGACY_MARKUP_RE.lastIndex = 0;
367
- bindings[i].compiled_expr = bindings[i].compiled_expr.replace(LEGACY_MARKUP_RE, '__ZENITH_INTERNAL_ZENHTML');
144
+ if (LEGACY_MARKUP_RE.test(bindings[i].compiled_expr)) {
145
+ failLegacyMarkup(bindings[i].compiled_expr);
146
+ }
368
147
  }
369
148
  }
370
149
  }
@@ -1,9 +1,8 @@
1
1
  export function createPageLoopState(): {
2
2
  expressionRewriteMetrics: {
3
3
  calls: number;
4
- cacheHits: number;
5
- cacheMisses: number;
6
- templateCompileMs: number;
4
+ compilerOwnedBindings: number;
5
+ ambiguousBindings: number;
7
6
  };
8
7
  pagePhaseTotals: {
9
8
  occurrenceCollectMs: number;
@@ -78,7 +77,6 @@ export function createPageLoopState(): {
78
77
  componentIrCache: Map<any, any>;
79
78
  componentDocumentModeCache: Map<any, any>;
80
79
  componentExpressionRewriteCache: Map<any, any>;
81
- templateExpressionCache: Map<any, any>;
82
80
  hoistedCodeTransformCache: {
83
81
  transpileToJs: Map<any, any>;
84
82
  deferRuntime: Map<any, any>;
@@ -88,7 +86,6 @@ export function createPageLoopCaches(): {
88
86
  componentIrCache: Map<any, any>;
89
87
  componentDocumentModeCache: Map<any, any>;
90
88
  componentExpressionRewriteCache: Map<any, any>;
91
- templateExpressionCache: Map<any, any>;
92
89
  hoistedCodeTransformCache: {
93
90
  transpileToJs: Map<any, any>;
94
91
  deferRuntime: Map<any, any>;
@@ -97,9 +94,8 @@ export function createPageLoopCaches(): {
97
94
  export function createPageLoopExecutionState(): {
98
95
  expressionRewriteMetrics: {
99
96
  calls: number;
100
- cacheHits: number;
101
- cacheMisses: number;
102
- templateCompileMs: number;
97
+ compilerOwnedBindings: number;
98
+ ambiguousBindings: number;
103
99
  };
104
100
  pagePhaseTotals: {
105
101
  occurrenceCollectMs: number;
@@ -173,11 +169,12 @@ export function createPageLoopExecutionState(): {
173
169
  envelopes: never[];
174
170
  };
175
171
  export function preparePageIrForMerge(pageIr: any): void;
176
- export function applyServerEnvelopeToPageIr({ pageIr, composedServer, hasGuard, hasLoad, entry, srcDir, sourceFile }: {
172
+ export function applyServerEnvelopeToPageIr({ pageIr, composedServer, hasGuard, hasLoad, hasAction, entry, srcDir, sourceFile }: {
177
173
  pageIr: any;
178
174
  composedServer: any;
179
175
  hasGuard: any;
180
176
  hasLoad: any;
177
+ hasAction: any;
181
178
  entry: any;
182
179
  srcDir: any;
183
180
  sourceFile: any;
@@ -11,7 +11,6 @@ export function createPageLoopCaches() {
11
11
  componentIrCache: new Map(),
12
12
  componentDocumentModeCache: new Map(),
13
13
  componentExpressionRewriteCache: new Map(),
14
- templateExpressionCache: new Map(),
15
14
  hoistedCodeTransformCache: {
16
15
  transpileToJs: new Map(),
17
16
  deferRuntime: new Map()
@@ -22,9 +21,8 @@ export function createPageLoopExecutionState() {
22
21
  return {
23
22
  expressionRewriteMetrics: {
24
23
  calls: 0,
25
- cacheHits: 0,
26
- cacheMisses: 0,
27
- templateCompileMs: 0
24
+ compilerOwnedBindings: 0,
25
+ ambiguousBindings: 0
28
26
  },
29
27
  pagePhaseTotals: createPagePhaseTotals(),
30
28
  occurrenceApplyPhaseTotals: createOccurrenceApplyPhaseTotals(),
@@ -48,22 +46,25 @@ export function preparePageIrForMerge(pageIr) {
48
46
  pageIr.hoisted.state = pageIr.hoisted.state || [];
49
47
  pageIr.hoisted.code = pageIr.hoisted.code || [];
50
48
  }
51
- export function applyServerEnvelopeToPageIr({ pageIr, composedServer, hasGuard, hasLoad, entry, srcDir, sourceFile }) {
49
+ export function applyServerEnvelopeToPageIr({ pageIr, composedServer, hasGuard, hasLoad, hasAction, entry, srcDir, sourceFile }) {
52
50
  if (composedServer.serverScript) {
53
- pageIr.server_script = composedServer.serverScript;
51
+ const { has_action: _unusedHasAction, ...serverScript } = composedServer.serverScript;
52
+ pageIr.server_script = serverScript;
54
53
  pageIr.prerender = composedServer.serverScript.prerender === true;
55
54
  if (pageIr.ssr_data === undefined) {
56
55
  pageIr.ssr_data = null;
57
56
  }
58
57
  }
59
- if (pageIr.prerender === true && (hasGuard || hasLoad)) {
58
+ if (pageIr.prerender === true && (hasGuard || hasLoad || hasAction)) {
60
59
  throw new Error(`[zenith] Build failed for ${entry.file}: protected routes require SSR/runtime. ` +
61
- 'Cannot prerender a static route with a `guard` or `load` function.');
60
+ 'Cannot prerender a static route with a `guard`, `load`, or `action` function.');
62
61
  }
63
62
  pageIr.has_guard = hasGuard;
64
63
  pageIr.has_load = hasLoad;
64
+ pageIr.has_action = hasAction;
65
65
  pageIr.guard_module_ref = composedServer.guardPath ? relative(srcDir, composedServer.guardPath).replaceAll('\\', '/') : null;
66
66
  pageIr.load_module_ref = composedServer.loadPath ? relative(srcDir, composedServer.loadPath).replaceAll('\\', '/') : null;
67
+ pageIr.action_module_ref = composedServer.actionPath ? relative(srcDir, composedServer.actionPath).replaceAll('\\', '/') : null;
67
68
  preparePageIrForMerge(pageIr);
68
69
  }
69
70
  export function buildOccurrenceCountByPath(componentOccurrences) {