@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.
- package/README.md +14 -11
- package/dist/adapters/adapter-netlify.js +1 -0
- package/dist/adapters/adapter-node.js +8 -0
- package/dist/adapters/adapter-vercel.js +1 -0
- package/dist/build/compiler-runtime.d.ts +10 -9
- package/dist/build/compiler-runtime.js +51 -1
- package/dist/build/compiler-signal-expression.d.ts +1 -0
- package/dist/build/compiler-signal-expression.js +155 -0
- package/dist/build/expression-rewrites.d.ts +1 -6
- package/dist/build/expression-rewrites.js +61 -65
- package/dist/build/page-component-loop.d.ts +3 -13
- package/dist/build/page-component-loop.js +21 -46
- package/dist/build/page-ir-normalization.d.ts +0 -8
- package/dist/build/page-ir-normalization.js +13 -234
- package/dist/build/page-loop-state.d.ts +6 -9
- package/dist/build/page-loop-state.js +9 -8
- package/dist/build/page-loop.js +27 -22
- package/dist/build/scoped-identifier-rewrite.d.ts +37 -44
- package/dist/build/scoped-identifier-rewrite.js +28 -128
- package/dist/build/server-script.d.ts +2 -1
- package/dist/build/server-script.js +29 -3
- package/dist/build.js +5 -3
- package/dist/component-instance-ir.js +158 -52
- package/dist/dev-build-session.js +20 -6
- package/dist/dev-server.js +82 -39
- package/dist/framework-components/Image.zen +1 -1
- package/dist/images/materialization-plan.d.ts +1 -0
- package/dist/images/materialization-plan.js +6 -0
- package/dist/images/materialize.d.ts +5 -3
- package/dist/images/materialize.js +24 -109
- package/dist/images/router-manifest.d.ts +1 -0
- package/dist/images/router-manifest.js +49 -0
- package/dist/index.js +8 -2
- package/dist/manifest.js +3 -2
- package/dist/preview.d.ts +4 -3
- package/dist/preview.js +87 -53
- package/dist/request-body.d.ts +2 -0
- package/dist/request-body.js +13 -0
- package/dist/request-origin.d.ts +2 -0
- package/dist/request-origin.js +45 -0
- package/dist/route-check-support.d.ts +1 -0
- package/dist/route-check-support.js +4 -0
- package/dist/server-contract.d.ts +15 -0
- package/dist/server-contract.js +102 -32
- package/dist/server-error.d.ts +4 -0
- package/dist/server-error.js +34 -0
- package/dist/server-output.d.ts +2 -0
- package/dist/server-output.js +13 -0
- package/dist/server-runtime/node-server.js +33 -27
- package/dist/server-runtime/route-render.d.ts +3 -3
- package/dist/server-runtime/route-render.js +20 -31
- package/dist/server-script-composition.d.ts +11 -5
- package/dist/server-script-composition.js +25 -10
- package/package.json +6 -3
package/dist/build/page-loop.js
CHANGED
|
@@ -5,14 +5,14 @@ import { applyOccurrenceRewritePlans } from '../component-instance-ir.js';
|
|
|
5
5
|
import { collectExpandedComponentOccurrences } from '../component-occurrences.js';
|
|
6
6
|
import { expandComponents } from '../resolve-components.js';
|
|
7
7
|
import { composeServerScriptEnvelope, resolveAdjacentServerModules } from '../server-script-composition.js';
|
|
8
|
-
import { createTimedCompilerRunner } from './compiler-runtime.js';
|
|
8
|
+
import { createTimedCompilerRunner, mergePageImageMaterialization } from './compiler-runtime.js';
|
|
9
9
|
import { buildComponentExpressionRewrite, mergeExpressionRewriteMaps, resolveRewrittenBindingMetadata } from './expression-rewrites.js';
|
|
10
10
|
import { createPageIrMergeCache } from './merge-component-ir.js';
|
|
11
11
|
import { buildPageOwnerContext, runPageComponentLoop } from './page-component-loop.js';
|
|
12
|
-
import { applyExpressionRewrites,
|
|
12
|
+
import { applyExpressionRewrites, normalizeExpressionPayload, normalizeHoistedSourcePayload, rewriteLegacyMarkupIdentifiers, rewriteRefBindingIdentifiers } from './page-ir-normalization.js';
|
|
13
|
+
import { deferComponentRuntimeBlock } from './hoisted-code-transforms.js';
|
|
13
14
|
import { addBreakdown, emitPageLoopSummary, recordPageProfile } from './page-loop-metrics.js';
|
|
14
15
|
import { applyServerEnvelopeToPageIr, buildOccurrenceCountByPath, createPageBuildState, createPageLoopCaches, createPageLoopExecutionState } from './page-loop-state.js';
|
|
15
|
-
import { buildScopedIdentifierRewrite } from './scoped-identifier-rewrite.js';
|
|
16
16
|
import { extractServerScript } from './server-script.js';
|
|
17
17
|
/**
|
|
18
18
|
* @param {{
|
|
@@ -33,7 +33,7 @@ export async function buildPageEnvelopes(input) {
|
|
|
33
33
|
const { manifest, pagesDir, srcDir, registry, compilerOpts, compilerBin, routerEnabled, startupProfile, compilerTotals, emitCompilerWarning } = input;
|
|
34
34
|
const cacheState = input.pageLoopCaches || createPageLoopCaches();
|
|
35
35
|
const executionState = createPageLoopExecutionState();
|
|
36
|
-
const { componentIrCache, componentDocumentModeCache, componentExpressionRewriteCache,
|
|
36
|
+
const { componentIrCache, componentDocumentModeCache, componentExpressionRewriteCache, hoistedCodeTransformCache } = cacheState;
|
|
37
37
|
const { expressionRewriteMetrics, pagePhaseTotals, occurrenceApplyPhaseTotals, bindingResolutionTotals, scopedRewritePhaseTotals, mergePhaseTotals, componentLoopPhaseTotals, pageProfiles, envelopes } = executionState;
|
|
38
38
|
async function cooperativeYield() {
|
|
39
39
|
await new Promise((resolve) => setImmediate(resolve));
|
|
@@ -52,7 +52,7 @@ export async function buildPageEnvelopes(input) {
|
|
|
52
52
|
const pageOwnerExtractStartedAt = performance.now();
|
|
53
53
|
const pageOwnerSource = extractServerScript(rawSource, sourceFile, compilerOpts).source;
|
|
54
54
|
pagePhase.serverExtractMs += startupProfile.roundMs(performance.now() - pageOwnerExtractStartedAt);
|
|
55
|
-
const { guardPath: adjacentGuard, loadPath: adjacentLoad } = resolveAdjacentServerModules(sourceFile);
|
|
55
|
+
const { guardPath: adjacentGuard, loadPath: adjacentLoad, actionPath: adjacentAction } = resolveAdjacentServerModules(sourceFile);
|
|
56
56
|
const expandedStartedAt = performance.now();
|
|
57
57
|
const { expandedSource } = expandComponents(rawSource, registry, sourceFile);
|
|
58
58
|
pageExpandMs = startupProfile.roundMs(performance.now() - expandedStartedAt);
|
|
@@ -62,21 +62,24 @@ export async function buildPageEnvelopes(input) {
|
|
|
62
62
|
const compileSource = extractedServer.source;
|
|
63
63
|
await cooperativeYield();
|
|
64
64
|
const pageCompileStartedAt = performance.now();
|
|
65
|
-
|
|
65
|
+
let pageIr = timedRunCompiler('page', sourceFile, compileSource, compilerOpts, { compilerToolchain: compilerBin, onWarning: emitCompilerWarning });
|
|
66
66
|
pageCompileMs = startupProfile.roundMs(performance.now() - pageCompileStartedAt);
|
|
67
67
|
const composedServer = composeServerScriptEnvelope({
|
|
68
68
|
sourceFile,
|
|
69
69
|
inlineServerScript: extractedServer.serverScript,
|
|
70
70
|
adjacentGuardPath: adjacentGuard,
|
|
71
|
-
adjacentLoadPath: adjacentLoad
|
|
71
|
+
adjacentLoadPath: adjacentLoad,
|
|
72
|
+
adjacentActionPath: adjacentAction
|
|
72
73
|
});
|
|
73
74
|
const hasGuard = composedServer.serverScript?.has_guard === true;
|
|
74
75
|
const hasLoad = composedServer.serverScript?.has_load === true;
|
|
76
|
+
const hasAction = composedServer.serverScript?.has_action === true;
|
|
75
77
|
applyServerEnvelopeToPageIr({
|
|
76
78
|
pageIr,
|
|
77
79
|
composedServer,
|
|
78
80
|
hasGuard,
|
|
79
81
|
hasLoad,
|
|
82
|
+
hasAction,
|
|
80
83
|
entry,
|
|
81
84
|
srcDir,
|
|
82
85
|
sourceFile
|
|
@@ -89,7 +92,8 @@ export async function buildPageEnvelopes(input) {
|
|
|
89
92
|
const pageAmbiguousExpressionMap = new Set();
|
|
90
93
|
const knownRefKeys = new Set();
|
|
91
94
|
const componentOccurrencePlans = [];
|
|
92
|
-
const
|
|
95
|
+
const imagePropsLiterals = [];
|
|
96
|
+
const { pageOwnerCompileMs: resolvedPageOwnerCompileMs, pageOwnerExpressionRewrite } = await buildPageOwnerContext({
|
|
93
97
|
componentOccurrences,
|
|
94
98
|
sourceFile,
|
|
95
99
|
pageOwnerSource,
|
|
@@ -97,13 +101,12 @@ export async function buildPageEnvelopes(input) {
|
|
|
97
101
|
compilerBin,
|
|
98
102
|
timedRunCompiler,
|
|
99
103
|
cooperativeYield,
|
|
100
|
-
templateExpressionCache,
|
|
101
104
|
expressionRewriteMetrics,
|
|
102
105
|
startupProfile
|
|
103
106
|
});
|
|
104
107
|
pageOwnerCompileMs = resolvedPageOwnerCompileMs;
|
|
105
108
|
const pageSelfRewriteStartedAt = performance.now();
|
|
106
|
-
const pageSelfExpressionRewrite = buildComponentExpressionRewrite(
|
|
109
|
+
const pageSelfExpressionRewrite = buildComponentExpressionRewrite(pageIr, expressionRewriteMetrics);
|
|
107
110
|
pagePhase.selfRewriteMs = startupProfile.roundMs(performance.now() - pageSelfRewriteStartedAt);
|
|
108
111
|
mergeExpressionRewriteMaps(pageExpressionRewriteMap, pageExpressionBindingMap, pageAmbiguousExpressionMap, pageSelfExpressionRewrite, pageIrMergeCache, pageBindingResolutionBreakdown);
|
|
109
112
|
const componentLoopStartedAt = performance.now();
|
|
@@ -127,10 +130,8 @@ export async function buildPageEnvelopes(input) {
|
|
|
127
130
|
componentIrCache,
|
|
128
131
|
componentDocumentModeCache,
|
|
129
132
|
componentExpressionRewriteCache,
|
|
130
|
-
templateExpressionCache,
|
|
131
133
|
expressionRewriteMetrics,
|
|
132
134
|
pageOwnerExpressionRewrite,
|
|
133
|
-
pageOwnerScopeRewrite,
|
|
134
135
|
pageIr,
|
|
135
136
|
pageIrMergeCache,
|
|
136
137
|
seenStaticImports,
|
|
@@ -139,6 +140,7 @@ export async function buildPageEnvelopes(input) {
|
|
|
139
140
|
pageAmbiguousExpressionMap,
|
|
140
141
|
knownRefKeys,
|
|
141
142
|
componentOccurrencePlans,
|
|
143
|
+
imagePropsLiterals,
|
|
142
144
|
pagePhase,
|
|
143
145
|
pageBindingResolutionBreakdown,
|
|
144
146
|
pageMergeBreakdown,
|
|
@@ -150,25 +152,25 @@ export async function buildPageEnvelopes(input) {
|
|
|
150
152
|
pageComponentCacheHits = pageStats.pageComponentCacheHits;
|
|
151
153
|
pageComponentCacheMisses = pageStats.pageComponentCacheMisses;
|
|
152
154
|
pagePhase.componentLoopMs = startupProfile.roundMs(performance.now() - componentLoopStartedAt);
|
|
155
|
+
if (imagePropsLiterals.length > 0) {
|
|
156
|
+
pageIr = mergePageImageMaterialization(pageIr, imagePropsLiterals, {
|
|
157
|
+
compilerToolchain: compilerBin
|
|
158
|
+
});
|
|
159
|
+
}
|
|
153
160
|
const occurrencePlanApplyStartedAt = performance.now();
|
|
154
161
|
applyOccurrenceRewritePlans(pageIr, componentOccurrencePlans, (rewrite, binding) => resolveRewrittenBindingMetadata(pageIrMergeCache, rewrite, binding, pageBindingResolutionBreakdown), pageOccurrenceApplyBreakdown);
|
|
155
162
|
pagePhase.occurrencePlanApplyMs = startupProfile.roundMs(performance.now() - occurrencePlanApplyStartedAt);
|
|
156
163
|
const expressionApplyStartedAt = performance.now();
|
|
157
164
|
applyExpressionRewrites(pageIr, pageExpressionRewriteMap, pageExpressionBindingMap, pageAmbiguousExpressionMap);
|
|
158
165
|
pagePhase.expressionApplyMs = startupProfile.roundMs(performance.now() - expressionApplyStartedAt);
|
|
159
|
-
const scopedRewriteStartedAt = performance.now();
|
|
160
|
-
const scopedRewritePlanStartedAt = performance.now();
|
|
161
|
-
const scopedRewritePlan = buildScopedIdentifierRewrite(pageIr);
|
|
162
|
-
pagePhase.scopedRewritePlanMs = startupProfile.roundMs(performance.now() - scopedRewritePlanStartedAt);
|
|
163
|
-
const scopedRewriteApplyStartedAt = performance.now();
|
|
164
|
-
applyScopedIdentifierRewrites(pageIr, scopedRewritePlan, pageScopedRewriteBreakdown);
|
|
165
|
-
pagePhase.scopedRewriteApplyMs = startupProfile.roundMs(performance.now() - scopedRewriteApplyStartedAt);
|
|
166
|
-
pagePhase.scopedRewriteMs = startupProfile.roundMs(performance.now() - scopedRewriteStartedAt);
|
|
167
166
|
const normalizeStartedAt = performance.now();
|
|
168
|
-
synthesizeSignalBackedCompiledExpressions(pageIr);
|
|
169
167
|
normalizeExpressionPayload(pageIr);
|
|
170
168
|
normalizeHoistedSourcePayload(pageIr);
|
|
171
|
-
|
|
169
|
+
if (Array.isArray(pageIr?.hoisted?.code) && pageIr.hoisted.code.length > 0) {
|
|
170
|
+
pageIr.hoisted.code = pageIr.hoisted.code
|
|
171
|
+
.map((entry) => deferComponentRuntimeBlock(entry, hoistedCodeTransformCache, expressionRewriteMetrics))
|
|
172
|
+
.filter((entry) => typeof entry === 'string' && entry.trim().length > 0);
|
|
173
|
+
}
|
|
172
174
|
rewriteLegacyMarkupIdentifiers(pageIr);
|
|
173
175
|
rewriteRefBindingIdentifiers(pageIr, knownRefKeys);
|
|
174
176
|
pagePhase.normalizeMs = startupProfile.roundMs(performance.now() - normalizeStartedAt);
|
|
@@ -182,6 +184,9 @@ export async function buildPageEnvelopes(input) {
|
|
|
182
184
|
route: entry.path,
|
|
183
185
|
file: sourceFile,
|
|
184
186
|
ir: pageIr,
|
|
187
|
+
image_materialization: Array.isArray(pageIr.image_materialization)
|
|
188
|
+
? pageIr.image_materialization
|
|
189
|
+
: [],
|
|
185
190
|
router: routerEnabled
|
|
186
191
|
});
|
|
187
192
|
recordPageProfile({
|
|
@@ -1,29 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @param {object | null | undefined} ir
|
|
3
|
-
* @returns {{ map: Map<string, string>, ambiguous: Set<string> }}
|
|
4
|
-
*/
|
|
5
|
-
export function buildScopedIdentifierRewrite(ir: object | null | undefined): {
|
|
6
|
-
map: Map<string, string>;
|
|
7
|
-
ambiguous: Set<string>;
|
|
8
|
-
};
|
|
9
|
-
/**
|
|
10
|
-
* @param {string} expr
|
|
11
|
-
* @param {{
|
|
12
|
-
* expressionRewrite?: { map?: Map<string, string>, ambiguous?: Set<string> } | null,
|
|
13
|
-
* scopeRewrite?: { map?: Map<string, string>, ambiguous?: Set<string> } | null
|
|
14
|
-
* } | null} rewriteContext
|
|
15
|
-
* @returns {string}
|
|
16
|
-
*/
|
|
17
|
-
export function rewritePropsExpression(expr: string, rewriteContext?: {
|
|
18
|
-
expressionRewrite?: {
|
|
19
|
-
map?: Map<string, string>;
|
|
20
|
-
ambiguous?: Set<string>;
|
|
21
|
-
} | null;
|
|
22
|
-
scopeRewrite?: {
|
|
23
|
-
map?: Map<string, string>;
|
|
24
|
-
ambiguous?: Set<string>;
|
|
25
|
-
} | null;
|
|
26
|
-
} | null): string;
|
|
27
1
|
/**
|
|
28
2
|
* @param {string | null | undefined} compiledExpr
|
|
29
3
|
* @param {{
|
|
@@ -41,6 +15,10 @@ export function resolveCompiledPropsExpression(compiledExpr: string | null | und
|
|
|
41
15
|
}>;
|
|
42
16
|
} | null | undefined): string | null;
|
|
43
17
|
/**
|
|
18
|
+
* The only allowed downstream props rewrite boundary is compiler-owned exact lookup.
|
|
19
|
+
* If the compiler did not emit a mapping for the attr expression, CLI keeps the
|
|
20
|
+
* original expression text without attempting identifier reinterpretation.
|
|
21
|
+
*
|
|
44
22
|
* @param {string} expr
|
|
45
23
|
* @param {{
|
|
46
24
|
* expressionRewrite?: {
|
|
@@ -49,8 +27,7 @@ export function resolveCompiledPropsExpression(compiledExpr: string | null | und
|
|
|
49
27
|
* ambiguous?: Set<string>,
|
|
50
28
|
* signals?: Array<{ state_index?: number }>,
|
|
51
29
|
* stateBindings?: Array<{ key?: string }>
|
|
52
|
-
* } | null
|
|
53
|
-
* scopeRewrite?: { map?: Map<string, string>, ambiguous?: Set<string> } | null
|
|
30
|
+
* } | null
|
|
54
31
|
* } | null} rewriteContext
|
|
55
32
|
* @returns {string}
|
|
56
33
|
*/
|
|
@@ -68,45 +45,61 @@ export function resolvePropsValueCode(expr: string, rewriteContext?: {
|
|
|
68
45
|
key?: string;
|
|
69
46
|
}>;
|
|
70
47
|
} | null;
|
|
71
|
-
scopeRewrite?: {
|
|
72
|
-
map?: Map<string, string>;
|
|
73
|
-
ambiguous?: Set<string>;
|
|
74
|
-
} | null;
|
|
75
48
|
} | null): string;
|
|
76
49
|
/**
|
|
77
50
|
* @param {string} attrs
|
|
78
51
|
* @param {{
|
|
79
|
-
* expressionRewrite?: {
|
|
80
|
-
*
|
|
52
|
+
* expressionRewrite?: {
|
|
53
|
+
* map?: Map<string, string>,
|
|
54
|
+
* bindings?: Map<string, { compiled_expr?: string | null }>,
|
|
55
|
+
* ambiguous?: Set<string>,
|
|
56
|
+
* signals?: Array<{ state_index?: number }>,
|
|
57
|
+
* stateBindings?: Array<{ key?: string }>
|
|
58
|
+
* } | null
|
|
81
59
|
* } | null} rewriteContext
|
|
82
60
|
* @returns {string}
|
|
83
61
|
*/
|
|
84
62
|
export function renderPropsLiteralFromAttrs(attrs: string, rewriteContext?: {
|
|
85
63
|
expressionRewrite?: {
|
|
86
64
|
map?: Map<string, string>;
|
|
65
|
+
bindings?: Map<string, {
|
|
66
|
+
compiled_expr?: string | null;
|
|
67
|
+
}>;
|
|
87
68
|
ambiguous?: Set<string>;
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
69
|
+
signals?: Array<{
|
|
70
|
+
state_index?: number;
|
|
71
|
+
}>;
|
|
72
|
+
stateBindings?: Array<{
|
|
73
|
+
key?: string;
|
|
74
|
+
}>;
|
|
92
75
|
} | null;
|
|
93
76
|
} | null): string;
|
|
94
77
|
/**
|
|
95
78
|
* @param {string} source
|
|
96
79
|
* @param {string} attrs
|
|
97
80
|
* @param {{
|
|
98
|
-
* expressionRewrite?: {
|
|
99
|
-
*
|
|
81
|
+
* expressionRewrite?: {
|
|
82
|
+
* map?: Map<string, string>,
|
|
83
|
+
* bindings?: Map<string, { compiled_expr?: string | null }>,
|
|
84
|
+
* ambiguous?: Set<string>,
|
|
85
|
+
* signals?: Array<{ state_index?: number }>,
|
|
86
|
+
* stateBindings?: Array<{ key?: string }>
|
|
87
|
+
* } | null
|
|
100
88
|
* } | null} rewriteContext
|
|
101
89
|
* @returns {string}
|
|
102
90
|
*/
|
|
103
91
|
export function injectPropsPrelude(source: string, attrs: string, rewriteContext?: {
|
|
104
92
|
expressionRewrite?: {
|
|
105
93
|
map?: Map<string, string>;
|
|
94
|
+
bindings?: Map<string, {
|
|
95
|
+
compiled_expr?: string | null;
|
|
96
|
+
}>;
|
|
106
97
|
ambiguous?: Set<string>;
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
98
|
+
signals?: Array<{
|
|
99
|
+
state_index?: number;
|
|
100
|
+
}>;
|
|
101
|
+
stateBindings?: Array<{
|
|
102
|
+
key?: string;
|
|
103
|
+
}>;
|
|
111
104
|
} | null;
|
|
112
105
|
} | null): string;
|
|
@@ -1,116 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
* @param {string} value
|
|
4
|
-
* @returns {string | null}
|
|
5
|
-
*/
|
|
6
|
-
function deriveScopedIdentifierAlias(value) {
|
|
7
|
-
const ident = String(value || '').trim();
|
|
8
|
-
if (!/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(ident)) {
|
|
9
|
-
return null;
|
|
10
|
-
}
|
|
11
|
-
const parts = ident.split('_').filter(Boolean);
|
|
12
|
-
const candidate = parts.length > 1 ? parts[parts.length - 1] : ident;
|
|
13
|
-
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(candidate) ? candidate : ident;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* @param {Map<string, string>} map
|
|
17
|
-
* @param {Set<string>} ambiguous
|
|
18
|
-
* @param {string | null} raw
|
|
19
|
-
* @param {string | null} rewritten
|
|
20
|
-
*/
|
|
21
|
-
function recordScopedIdentifierRewrite(map, ambiguous, raw, rewritten) {
|
|
22
|
-
if (typeof raw !== 'string' || raw.length === 0 || typeof rewritten !== 'string' || rewritten.length === 0) {
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
const existing = map.get(raw);
|
|
26
|
-
if (existing && existing !== rewritten) {
|
|
27
|
-
map.delete(raw);
|
|
28
|
-
ambiguous.add(raw);
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
if (!ambiguous.has(raw)) {
|
|
32
|
-
map.set(raw, rewritten);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* @param {object | null | undefined} ir
|
|
37
|
-
* @returns {{ map: Map<string, string>, ambiguous: Set<string> }}
|
|
38
|
-
*/
|
|
39
|
-
export function buildScopedIdentifierRewrite(ir) {
|
|
40
|
-
const out = { map: new Map(), ambiguous: new Set() };
|
|
41
|
-
if (!ir || typeof ir !== 'object') {
|
|
42
|
-
return out;
|
|
43
|
-
}
|
|
44
|
-
const stateBindings = Array.isArray(ir?.hoisted?.state) ? ir.hoisted.state : [];
|
|
45
|
-
for (const stateEntry of stateBindings) {
|
|
46
|
-
const key = typeof stateEntry?.key === 'string' ? stateEntry.key : null;
|
|
47
|
-
recordScopedIdentifierRewrite(out.map, out.ambiguous, deriveScopedIdentifierAlias(key), key);
|
|
48
|
-
}
|
|
49
|
-
const functionBindings = Array.isArray(ir?.hoisted?.functions) ? ir.hoisted.functions : [];
|
|
50
|
-
for (const fnName of functionBindings) {
|
|
51
|
-
if (typeof fnName !== 'string') {
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
recordScopedIdentifierRewrite(out.map, out.ambiguous, deriveScopedIdentifierAlias(fnName), fnName);
|
|
55
|
-
}
|
|
56
|
-
const declarations = Array.isArray(ir?.hoisted?.declarations) ? ir.hoisted.declarations : [];
|
|
57
|
-
for (const declaration of declarations) {
|
|
58
|
-
if (typeof declaration !== 'string') {
|
|
59
|
-
continue;
|
|
60
|
-
}
|
|
61
|
-
for (const identifier of extractDeclaredIdentifiers(declaration)) {
|
|
62
|
-
recordScopedIdentifierRewrite(out.map, out.ambiguous, deriveScopedIdentifierAlias(identifier), identifier);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
return out;
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* @param {string} expr
|
|
69
|
-
* @param {{
|
|
70
|
-
* expressionRewrite?: { map?: Map<string, string>, ambiguous?: Set<string> } | null,
|
|
71
|
-
* scopeRewrite?: { map?: Map<string, string>, ambiguous?: Set<string> } | null
|
|
72
|
-
* } | null} rewriteContext
|
|
73
|
-
* @returns {string}
|
|
74
|
-
*/
|
|
75
|
-
export function rewritePropsExpression(expr, rewriteContext = null) {
|
|
76
|
-
const trimmed = String(expr || '').trim();
|
|
77
|
-
if (!trimmed) {
|
|
78
|
-
return trimmed;
|
|
79
|
-
}
|
|
80
|
-
const expressionMap = rewriteContext?.expressionRewrite?.map;
|
|
81
|
-
const expressionAmbiguous = rewriteContext?.expressionRewrite?.ambiguous;
|
|
82
|
-
if (expressionMap instanceof Map &&
|
|
83
|
-
!(expressionAmbiguous instanceof Set && expressionAmbiguous.has(trimmed))) {
|
|
84
|
-
const exact = expressionMap.get(trimmed);
|
|
85
|
-
if (typeof exact === 'string' && exact.length > 0) {
|
|
86
|
-
return normalizeTypeScriptExpression(exact);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
const scopeMap = rewriteContext?.scopeRewrite?.map;
|
|
90
|
-
const scopeAmbiguous = rewriteContext?.scopeRewrite?.ambiguous;
|
|
91
|
-
const rootMatch = trimmed.match(/^([A-Za-z_$][A-Za-z0-9_$]*)([\s\S]*)$/);
|
|
92
|
-
if (!(scopeMap instanceof Map)) {
|
|
93
|
-
return normalizeTypeScriptExpression(trimmed);
|
|
94
|
-
}
|
|
95
|
-
if (!rootMatch) {
|
|
96
|
-
return rewriteIdentifiersWithinExpression(trimmed, scopeMap, scopeAmbiguous);
|
|
97
|
-
}
|
|
98
|
-
const root = rootMatch[1];
|
|
99
|
-
if (scopeAmbiguous instanceof Set && scopeAmbiguous.has(root)) {
|
|
100
|
-
return rewriteIdentifiersWithinExpression(trimmed, scopeMap, scopeAmbiguous);
|
|
101
|
-
}
|
|
102
|
-
const rewrittenRoot = scopeMap.get(root);
|
|
103
|
-
if (typeof rewrittenRoot !== 'string' || rewrittenRoot.length === 0 || rewrittenRoot === root) {
|
|
104
|
-
return rewriteIdentifiersWithinExpression(trimmed, scopeMap, scopeAmbiguous);
|
|
105
|
-
}
|
|
106
|
-
if (rootMatch[2].trim().length === 0) {
|
|
107
|
-
return normalizeTypeScriptExpression(rewrittenRoot);
|
|
108
|
-
}
|
|
109
|
-
const rewrittenExpr = rewriteIdentifiersWithinExpression(trimmed, scopeMap, scopeAmbiguous);
|
|
110
|
-
return typeof rewrittenExpr === 'string' && rewrittenExpr.length > 0
|
|
111
|
-
? rewrittenExpr
|
|
112
|
-
: normalizeTypeScriptExpression(`${rewrittenRoot}${rootMatch[2]}`);
|
|
113
|
-
}
|
|
1
|
+
import { normalizeTypeScriptExpression, renderObjectKey } from './typescript-expression-utils.js';
|
|
2
|
+
import { rewriteCompilerSignalMapReferences } from './compiler-signal-expression.js';
|
|
114
3
|
/**
|
|
115
4
|
* @param {string | null | undefined} compiledExpr
|
|
116
5
|
* @param {{
|
|
@@ -126,22 +15,24 @@ export function resolveCompiledPropsExpression(compiledExpr, expressionRewrite =
|
|
|
126
15
|
}
|
|
127
16
|
const signals = Array.isArray(expressionRewrite?.signals) ? expressionRewrite.signals : [];
|
|
128
17
|
const stateBindings = Array.isArray(expressionRewrite?.stateBindings) ? expressionRewrite.stateBindings : [];
|
|
129
|
-
|
|
130
|
-
const signalIndex = Number.parseInt(rawIndex, 10);
|
|
131
|
-
if (!Number.isInteger(signalIndex)) {
|
|
132
|
-
return full;
|
|
133
|
-
}
|
|
18
|
+
return rewriteCompilerSignalMapReferences(source, ({ ts, signalIndex, valueRead }) => {
|
|
134
19
|
const signal = signals[signalIndex];
|
|
135
20
|
const stateIndex = signal?.state_index;
|
|
136
21
|
const stateKey = Number.isInteger(stateIndex) ? stateBindings[stateIndex]?.key : null;
|
|
137
22
|
if (typeof stateKey !== 'string' || stateKey.length === 0) {
|
|
138
|
-
return
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
if (valueRead) {
|
|
26
|
+
return ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(stateKey), 'get'), undefined, []);
|
|
139
27
|
}
|
|
140
|
-
return
|
|
28
|
+
return ts.factory.createIdentifier(stateKey);
|
|
141
29
|
});
|
|
142
|
-
return normalizeTypeScriptExpression(resolved);
|
|
143
30
|
}
|
|
144
31
|
/**
|
|
32
|
+
* The only allowed downstream props rewrite boundary is compiler-owned exact lookup.
|
|
33
|
+
* If the compiler did not emit a mapping for the attr expression, CLI keeps the
|
|
34
|
+
* original expression text without attempting identifier reinterpretation.
|
|
35
|
+
*
|
|
145
36
|
* @param {string} expr
|
|
146
37
|
* @param {{
|
|
147
38
|
* expressionRewrite?: {
|
|
@@ -150,8 +41,7 @@ export function resolveCompiledPropsExpression(compiledExpr, expressionRewrite =
|
|
|
150
41
|
* ambiguous?: Set<string>,
|
|
151
42
|
* signals?: Array<{ state_index?: number }>,
|
|
152
43
|
* stateBindings?: Array<{ key?: string }>
|
|
153
|
-
* } | null
|
|
154
|
-
* scopeRewrite?: { map?: Map<string, string>, ambiguous?: Set<string> } | null
|
|
44
|
+
* } | null
|
|
155
45
|
* } | null} rewriteContext
|
|
156
46
|
* @returns {string}
|
|
157
47
|
*/
|
|
@@ -177,13 +67,18 @@ export function resolvePropsValueCode(expr, rewriteContext = null) {
|
|
|
177
67
|
return normalizeTypeScriptExpression(exact);
|
|
178
68
|
}
|
|
179
69
|
}
|
|
180
|
-
return
|
|
70
|
+
return normalizeTypeScriptExpression(trimmed);
|
|
181
71
|
}
|
|
182
72
|
/**
|
|
183
73
|
* @param {string} attrs
|
|
184
74
|
* @param {{
|
|
185
|
-
* expressionRewrite?: {
|
|
186
|
-
*
|
|
75
|
+
* expressionRewrite?: {
|
|
76
|
+
* map?: Map<string, string>,
|
|
77
|
+
* bindings?: Map<string, { compiled_expr?: string | null }>,
|
|
78
|
+
* ambiguous?: Set<string>,
|
|
79
|
+
* signals?: Array<{ state_index?: number }>,
|
|
80
|
+
* stateBindings?: Array<{ key?: string }>
|
|
81
|
+
* } | null
|
|
187
82
|
* } | null} rewriteContext
|
|
188
83
|
* @returns {string}
|
|
189
84
|
*/
|
|
@@ -225,8 +120,13 @@ export function renderPropsLiteralFromAttrs(attrs, rewriteContext = null) {
|
|
|
225
120
|
* @param {string} source
|
|
226
121
|
* @param {string} attrs
|
|
227
122
|
* @param {{
|
|
228
|
-
* expressionRewrite?: {
|
|
229
|
-
*
|
|
123
|
+
* expressionRewrite?: {
|
|
124
|
+
* map?: Map<string, string>,
|
|
125
|
+
* bindings?: Map<string, { compiled_expr?: string | null }>,
|
|
126
|
+
* ambiguous?: Set<string>,
|
|
127
|
+
* signals?: Array<{ state_index?: number }>,
|
|
128
|
+
* stateBindings?: Array<{ key?: string }>
|
|
129
|
+
* } | null
|
|
230
130
|
* } | null} rewriteContext
|
|
231
131
|
* @returns {string}
|
|
232
132
|
*/
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @param {string} source
|
|
3
3
|
* @param {string} sourceFile
|
|
4
4
|
* @param {object} [compilerOpts]
|
|
5
|
-
* @returns {{ source: string, serverScript: { source: string, prerender: boolean, has_guard: boolean, has_load: boolean, source_path: string } | null }}
|
|
5
|
+
* @returns {{ source: string, serverScript: { source: string, prerender: boolean, has_guard: boolean, has_load: boolean, has_action: boolean, source_path: string } | null }}
|
|
6
6
|
*/
|
|
7
7
|
export function extractServerScript(source: string, sourceFile: string, compilerOpts?: object): {
|
|
8
8
|
source: string;
|
|
@@ -11,6 +11,7 @@ export function extractServerScript(source: string, sourceFile: string, compiler
|
|
|
11
11
|
prerender: boolean;
|
|
12
12
|
has_guard: boolean;
|
|
13
13
|
has_load: boolean;
|
|
14
|
+
has_action: boolean;
|
|
14
15
|
source_path: string;
|
|
15
16
|
} | null;
|
|
16
17
|
};
|
|
@@ -4,12 +4,12 @@ import { findNextKnownComponentTag } from '../component-tag-parser.js';
|
|
|
4
4
|
* @param {string} source
|
|
5
5
|
* @param {string} sourceFile
|
|
6
6
|
* @param {object} [compilerOpts]
|
|
7
|
-
* @returns {{ source: string, serverScript: { source: string, prerender: boolean, has_guard: boolean, has_load: boolean, source_path: string } | null }}
|
|
7
|
+
* @returns {{ source: string, serverScript: { source: string, prerender: boolean, has_guard: boolean, has_load: boolean, has_action: boolean, source_path: string } | null }}
|
|
8
8
|
*/
|
|
9
9
|
export function extractServerScript(source, sourceFile, compilerOpts = {}) {
|
|
10
10
|
const scriptRe = /<script\b([^>]*)>([\s\S]*?)<\/script>/gi;
|
|
11
11
|
const serverMatches = [];
|
|
12
|
-
const reservedServerExportRe = /\bexport\s+const\s+(?:data|prerender|guard|load|ssr_data|props|ssr)\b|\bexport\s+(?:async\s+)?function\s+(?:load|guard)\s*\(|\bexport\s+const\s+(?:load|guard)\s*=/;
|
|
12
|
+
const reservedServerExportRe = /\bexport\s+const\s+(?:data|prerender|guard|load|action|ssr_data|props|ssr)\b|\bexport\s+(?:async\s+)?function\s+(?:load|guard|action)\s*\(|\bexport\s+const\s+(?:load|guard|action)\s*=/;
|
|
13
13
|
for (const match of source.matchAll(scriptRe)) {
|
|
14
14
|
const attrs = String(match[1] || '');
|
|
15
15
|
const body = String(match[2] || '');
|
|
@@ -17,7 +17,7 @@ export function extractServerScript(source, sourceFile, compilerOpts = {}) {
|
|
|
17
17
|
if (!isServer && reservedServerExportRe.test(body)) {
|
|
18
18
|
throw new Error(`Zenith server script contract violation:\n` +
|
|
19
19
|
` File: ${sourceFile}\n` +
|
|
20
|
-
` Reason: guard/load/data exports are only allowed in <script server lang="ts"> or adjacent .guard.ts / .load.ts files\n` +
|
|
20
|
+
` Reason: guard/load/action/data exports are only allowed in <script server lang="ts"> or adjacent .guard.ts / .load.ts / .action.ts files\n` +
|
|
21
21
|
` Example: move the export into <script server lang="ts">`);
|
|
22
22
|
}
|
|
23
23
|
if (isServer) {
|
|
@@ -81,6 +81,19 @@ export function extractServerScript(source, sourceFile, compilerOpts = {}) {
|
|
|
81
81
|
` Reason: multiple guard exports detected\n` +
|
|
82
82
|
` Example: keep exactly one export const guard = async (ctx) => ({ ... })`);
|
|
83
83
|
}
|
|
84
|
+
const actionFnMatch = serverSource.match(/\bexport\s+(?:async\s+)?function\s+action\s*\(([^)]*)\)/);
|
|
85
|
+
const actionConstParenMatch = serverSource.match(/\bexport\s+const\s+action\s*=\s*(?:async\s*)?\(([^)]*)\)\s*=>/);
|
|
86
|
+
const actionConstSingleArgMatch = serverSource.match(/\bexport\s+const\s+action\s*=\s*(?:async\s*)?([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=>/);
|
|
87
|
+
const hasAction = Boolean(actionFnMatch || actionConstParenMatch || actionConstSingleArgMatch);
|
|
88
|
+
const actionMatchCount = Number(Boolean(actionFnMatch)) +
|
|
89
|
+
Number(Boolean(actionConstParenMatch)) +
|
|
90
|
+
Number(Boolean(actionConstSingleArgMatch));
|
|
91
|
+
if (actionMatchCount > 1) {
|
|
92
|
+
throw new Error(`Zenith server script contract violation:\n` +
|
|
93
|
+
` File: ${sourceFile}\n` +
|
|
94
|
+
` Reason: multiple action exports detected\n` +
|
|
95
|
+
` Example: keep exactly one export const action = async (ctx) => ({ ... })`);
|
|
96
|
+
}
|
|
84
97
|
const hasData = /\bexport\s+const\s+data\b/.test(serverSource);
|
|
85
98
|
const hasSsrData = /\bexport\s+const\s+ssr_data\b/.test(serverSource);
|
|
86
99
|
const hasSsr = /\bexport\s+const\s+ssr\b/.test(serverSource);
|
|
@@ -119,6 +132,17 @@ export function extractServerScript(source, sourceFile, compilerOpts = {}) {
|
|
|
119
132
|
` Example: export const guard = async (ctx) => ({ ... })`);
|
|
120
133
|
}
|
|
121
134
|
}
|
|
135
|
+
if (hasAction) {
|
|
136
|
+
const singleArg = String(actionConstSingleArgMatch?.[1] || '').trim();
|
|
137
|
+
const paramsText = String((actionFnMatch || actionConstParenMatch)?.[1] || '').trim();
|
|
138
|
+
const arity = singleArg ? 1 : paramsText.length === 0 ? 0 : paramsText.split(',').length;
|
|
139
|
+
if (arity !== 1) {
|
|
140
|
+
throw new Error(`Zenith server script contract violation:\n` +
|
|
141
|
+
` File: ${sourceFile}\n` +
|
|
142
|
+
` Reason: action(ctx) must accept exactly one argument\n` +
|
|
143
|
+
` Example: export const action = async (ctx) => ({ ... })`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
122
146
|
const prerenderMatch = serverSource.match(/\bexport\s+const\s+prerender\s*=\s*([^\n;]+)/);
|
|
123
147
|
let prerender = false;
|
|
124
148
|
if (prerenderMatch) {
|
|
@@ -140,6 +164,7 @@ export function extractServerScript(source, sourceFile, compilerOpts = {}) {
|
|
|
140
164
|
prerender,
|
|
141
165
|
has_guard: hasGuard,
|
|
142
166
|
has_load: hasLoad,
|
|
167
|
+
has_action: hasAction,
|
|
143
168
|
source_path: sourceFile
|
|
144
169
|
}
|
|
145
170
|
};
|
|
@@ -153,6 +178,7 @@ export function extractServerScript(source, sourceFile, compilerOpts = {}) {
|
|
|
153
178
|
prerender,
|
|
154
179
|
has_guard: hasGuard,
|
|
155
180
|
has_load: hasLoad,
|
|
181
|
+
has_action: hasAction,
|
|
156
182
|
source_path: sourceFile
|
|
157
183
|
}
|
|
158
184
|
};
|
package/dist/build.js
CHANGED
|
@@ -11,14 +11,15 @@ import { buildPageEnvelopes } from './build/page-loop.js';
|
|
|
11
11
|
import { deriveProjectRootFromPagesDir, ensureZenithTypeDeclarations } from './build/type-declarations.js';
|
|
12
12
|
import { materializeImageMarkupInHtmlFiles } from './images/materialize.js';
|
|
13
13
|
import { buildImageArtifacts } from './images/service.js';
|
|
14
|
+
import { injectImageMaterializationIntoRouterManifest } from './images/router-manifest.js';
|
|
14
15
|
import { createImageRuntimePayload, injectImageRuntimePayloadIntoHtmlFiles } from './images/payload.js';
|
|
16
|
+
import { supportsTargetRouteCheck } from './route-check-support.js';
|
|
15
17
|
import { createStartupProfiler } from './startup-profile.js';
|
|
16
18
|
import { writeServerOutput } from './server-output.js';
|
|
17
19
|
import { resolveBundlerBin } from './toolchain-paths.js';
|
|
18
20
|
import { createBundlerToolchain, createCompilerToolchain, ensureToolchainCompatibility, getActiveToolchainCandidate } from './toolchain-runner.js';
|
|
19
21
|
import { maybeWarnAboutZenithVersionMismatch } from './version-check.js';
|
|
20
22
|
export { createCompilerWarningEmitter };
|
|
21
|
-
const RUNTIME_MARKUP_BINDING = '__ZENITH_INTERNAL_ZENHTML';
|
|
22
23
|
function createCompilerTotals() {
|
|
23
24
|
return {
|
|
24
25
|
pageMs: 0,
|
|
@@ -55,6 +56,7 @@ export async function build(options) {
|
|
|
55
56
|
const compilerTotals = createCompilerTotals();
|
|
56
57
|
const { target, adapter, mode } = resolveBuildAdapter(config);
|
|
57
58
|
const basePath = normalizeBasePath(config.basePath || '/');
|
|
59
|
+
const routeCheckEnabled = supportsTargetRouteCheck(target);
|
|
58
60
|
const routerEnabled = config.router === true;
|
|
59
61
|
const compilerOpts = {
|
|
60
62
|
typescriptDefault: config.typescriptDefault === true,
|
|
@@ -72,7 +74,6 @@ export async function build(options) {
|
|
|
72
74
|
}));
|
|
73
75
|
}
|
|
74
76
|
const registry = startupProfile.measureSync('build_component_registry', () => buildComponentRegistry(srcDir));
|
|
75
|
-
void RUNTIME_MARKUP_BINDING;
|
|
76
77
|
const manifest = await startupProfile.measureAsync('generate_manifest', () => generateManifest(pagesDir, '.zen', { compilerOpts }));
|
|
77
78
|
if (mode !== 'legacy') {
|
|
78
79
|
adapter.validateRoutes(manifest);
|
|
@@ -103,7 +104,8 @@ export async function build(options) {
|
|
|
103
104
|
emitCompilerWarning
|
|
104
105
|
});
|
|
105
106
|
if (envelopes.length > 0) {
|
|
106
|
-
await startupProfile.measureAsync('run_bundler', () => runBundler(envelopes, staticOutputDir, projectRoot, logger, showBundlerInfo, bundlerBin, { basePath }), { envelopes: envelopes.length });
|
|
107
|
+
await startupProfile.measureAsync('run_bundler', () => runBundler(envelopes, staticOutputDir, projectRoot, logger, showBundlerInfo, bundlerBin, { basePath, routeCheck: routeCheckEnabled }), { envelopes: envelopes.length });
|
|
108
|
+
await startupProfile.measureAsync('inject_image_materialization_manifest', () => injectImageMaterializationIntoRouterManifest(staticOutputDir, envelopes), { envelopes: envelopes.length });
|
|
107
109
|
}
|
|
108
110
|
await startupProfile.measureAsync('rewrite_soft_navigation_base_path', () => rewriteSoftNavigationHrefBasePathInHtmlFiles(staticOutputDir, basePath));
|
|
109
111
|
const { manifest: imageManifest } = await startupProfile.measureAsync('build_image_artifacts', () => buildImageArtifacts({
|