@zenithbuild/core 0.1.0 → 0.3.1
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/LICENSE +1 -1
- package/README.md +24 -40
- package/bin/zen-build.ts +2 -0
- package/bin/zen-dev.ts +2 -0
- package/bin/zen-preview.ts +2 -0
- package/bin/zenith.ts +2 -0
- package/cli/commands/add.ts +37 -0
- package/cli/commands/build.ts +37 -0
- package/cli/commands/create.ts +702 -0
- package/cli/commands/dev.ts +197 -0
- package/cli/commands/index.ts +112 -0
- package/cli/commands/preview.ts +62 -0
- package/cli/commands/remove.ts +33 -0
- package/cli/index.ts +10 -0
- package/cli/main.ts +101 -0
- package/cli/utils/branding.ts +153 -0
- package/cli/utils/logger.ts +40 -0
- package/cli/utils/plugin-manager.ts +114 -0
- package/cli/utils/project.ts +71 -0
- package/compiler/build-analyzer.ts +122 -0
- package/compiler/discovery/layouts.ts +61 -0
- package/compiler/index.ts +40 -24
- package/compiler/ir/types.ts +1 -0
- package/compiler/parse/parseScript.ts +29 -5
- package/compiler/parse/parseTemplate.ts +96 -58
- package/compiler/parse/scriptAnalysis.ts +77 -0
- package/compiler/runtime/dataExposure.ts +49 -31
- package/compiler/runtime/generateDOM.ts +18 -17
- package/compiler/runtime/generateHydrationBundle.ts +24 -5
- package/compiler/runtime/transformIR.ts +140 -49
- package/compiler/runtime/wrapExpressionWithLoop.ts +11 -11
- package/compiler/spa-build.ts +70 -153
- package/compiler/ssg-build.ts +412 -0
- package/compiler/transform/layoutProcessor.ts +132 -0
- package/compiler/transform/transformNode.ts +19 -19
- package/dist/cli.js +11648 -0
- package/dist/zen-build.js +11659 -0
- package/dist/zen-dev.js +11659 -0
- package/dist/zen-preview.js +11659 -0
- package/dist/zenith.js +11659 -0
- package/package.json +22 -2
- package/runtime/bundle-generator.ts +416 -0
- package/runtime/client-runtime.ts +532 -0
- package/.eslintignore +0 -15
- package/.gitattributes +0 -2
- package/.github/ISSUE_TEMPLATE/compiler-errors-for-invalid-state-declarations.md +0 -25
- package/.github/ISSUE_TEMPLATE/new_ticket.yaml +0 -34
- package/.github/pull_request_template.md +0 -15
- package/.github/workflows/discord-changelog.yml +0 -141
- package/.github/workflows/discord-notify.yml +0 -242
- package/.github/workflows/discord-version.yml +0 -195
- package/.prettierignore +0 -13
- package/.prettierrc +0 -21
- package/.zen.d.ts +0 -15
- package/app/components/Button.zen +0 -46
- package/app/components/Link.zen +0 -11
- package/app/favicon.ico +0 -0
- package/app/layouts/Main.zen +0 -59
- package/app/pages/about.zen +0 -23
- package/app/pages/blog/[id].zen +0 -53
- package/app/pages/blog/index.zen +0 -32
- package/app/pages/dynamic-dx.zen +0 -712
- package/app/pages/dynamic-primitives.zen +0 -453
- package/app/pages/index.zen +0 -154
- package/app/pages/navigation-demo.zen +0 -229
- package/app/pages/posts/[...slug].zen +0 -61
- package/app/pages/primitives-demo.zen +0 -273
- package/assets/logos/0E3B5DDD-605C-4839-BB2E-DFCA8ADC9604.PNG +0 -0
- package/assets/logos/760971E5-79A1-44F9-90B9-925DF30F4278.PNG +0 -0
- package/assets/logos/8A06ED80-9ED2-4689-BCBD-13B2E95EE8E4.JPG +0 -0
- package/assets/logos/C691FF58-ED13-4E8D-B6A3-02E835849340.PNG +0 -0
- package/assets/logos/C691FF58-ED13-4E8D-B6A3-02E835849340.svg +0 -601
- package/assets/logos/README.md +0 -54
- package/assets/logos/zen.icns +0 -0
- package/bun.lock +0 -39
- package/compiler/legacy/binding.ts +0 -254
- package/compiler/legacy/bindings.ts +0 -338
- package/compiler/legacy/component-process.ts +0 -1208
- package/compiler/legacy/component.ts +0 -301
- package/compiler/legacy/event.ts +0 -50
- package/compiler/legacy/expression.ts +0 -1149
- package/compiler/legacy/mutation.ts +0 -280
- package/compiler/legacy/parse.ts +0 -299
- package/compiler/legacy/split.ts +0 -608
- package/compiler/legacy/types.ts +0 -32
- package/docs/COMMENTS.md +0 -111
- package/docs/COMMITS.md +0 -36
- package/docs/CONTRIBUTING.md +0 -116
- package/docs/STYLEGUIDE.md +0 -62
- package/scripts/webhook-proxy.ts +0 -213
|
@@ -17,7 +17,7 @@ export function generateDOMCode(
|
|
|
17
17
|
varCounter: { count: number } = { count: 0 }
|
|
18
18
|
): { code: string; varName: string } {
|
|
19
19
|
const varName = `node_${varCounter.count++}`
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
switch (node.type) {
|
|
22
22
|
case 'text': {
|
|
23
23
|
const textNode = node as TextNode
|
|
@@ -27,14 +27,14 @@ export function generateDOMCode(
|
|
|
27
27
|
varName
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
-
|
|
30
|
+
|
|
31
31
|
case 'expression': {
|
|
32
32
|
const exprNode = node as ExpressionNode
|
|
33
33
|
const expr = expressions.find(e => e.id === exprNode.expression)
|
|
34
34
|
if (!expr) {
|
|
35
35
|
throw new Error(`Expression ${exprNode.expression} not found`)
|
|
36
36
|
}
|
|
37
|
-
|
|
37
|
+
|
|
38
38
|
// Create a span element to hold the expression result
|
|
39
39
|
return {
|
|
40
40
|
code: `${indent}const ${varName} = document.createElement('span');
|
|
@@ -43,13 +43,13 @@ ${indent}${varName}.setAttribute('data-zen-expr', '${exprNode.expression}');`,
|
|
|
43
43
|
varName
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
|
-
|
|
46
|
+
|
|
47
47
|
case 'element': {
|
|
48
48
|
const elNode = node as ElementNode
|
|
49
49
|
const tag = elNode.tag
|
|
50
|
-
|
|
50
|
+
|
|
51
51
|
let code = `${indent}const ${varName} = document.createElement('${tag}');\n`
|
|
52
|
-
|
|
52
|
+
|
|
53
53
|
// Handle attributes
|
|
54
54
|
for (const attr of elNode.attributes) {
|
|
55
55
|
if (typeof attr.value === 'string') {
|
|
@@ -60,7 +60,7 @@ ${indent}${varName}.setAttribute('data-zen-expr', '${exprNode.expression}');`,
|
|
|
60
60
|
// Expression attribute
|
|
61
61
|
const expr = attr.value as ExpressionIR
|
|
62
62
|
const attrName = attr.name === 'className' ? 'class' : attr.name
|
|
63
|
-
|
|
63
|
+
|
|
64
64
|
// Handle special attributes
|
|
65
65
|
if (attrName === 'class' || attrName === 'className') {
|
|
66
66
|
code += `${indent}${varName}.className = String(${expr.id}(state) ?? '');\n`
|
|
@@ -70,9 +70,10 @@ ${indent}if (typeof styleValue_${varCounter.count} === 'string') {
|
|
|
70
70
|
${indent} ${varName}.style.cssText = styleValue_${varCounter.count};
|
|
71
71
|
${indent}}\n`
|
|
72
72
|
} else if (attrName.startsWith('on')) {
|
|
73
|
-
// Event handler - store handler name, will be bound later
|
|
73
|
+
// Event handler - store handler name/id, will be bound later
|
|
74
74
|
const eventType = attrName.slice(2).toLowerCase() // Remove 'on' prefix
|
|
75
|
-
|
|
75
|
+
const value = typeof attr.value === 'string' ? attr.value : (attr.value as ExpressionIR).id
|
|
76
|
+
code += `${indent}${varName}.setAttribute('data-zen-${eventType}', ${JSON.stringify(value)});\n`
|
|
76
77
|
} else {
|
|
77
78
|
const tempVar = `attr_${varCounter.count++}`
|
|
78
79
|
code += `${indent}const ${tempVar} = ${expr.id}(state);
|
|
@@ -82,7 +83,7 @@ ${indent}}\n`
|
|
|
82
83
|
}
|
|
83
84
|
}
|
|
84
85
|
}
|
|
85
|
-
|
|
86
|
+
|
|
86
87
|
// Handle children
|
|
87
88
|
if (elNode.children.length > 0) {
|
|
88
89
|
for (const child of elNode.children) {
|
|
@@ -91,7 +92,7 @@ ${indent}}\n`
|
|
|
91
92
|
code += `${indent}${varName}.appendChild(${childResult.varName});\n`
|
|
92
93
|
}
|
|
93
94
|
}
|
|
94
|
-
|
|
95
|
+
|
|
95
96
|
return { code, varName }
|
|
96
97
|
}
|
|
97
98
|
}
|
|
@@ -112,11 +113,11 @@ export function generateDOMFunction(
|
|
|
112
113
|
return fragment;
|
|
113
114
|
}`
|
|
114
115
|
}
|
|
115
|
-
|
|
116
|
+
|
|
116
117
|
const varCounter = { count: 0 }
|
|
117
118
|
let code = `function ${functionName}(state) {
|
|
118
119
|
`
|
|
119
|
-
|
|
120
|
+
|
|
120
121
|
if (nodes.length === 1) {
|
|
121
122
|
const node = nodes[0]
|
|
122
123
|
if (!node) {
|
|
@@ -127,18 +128,18 @@ export function generateDOMFunction(
|
|
|
127
128
|
code += `\n return ${result.varName};\n}`
|
|
128
129
|
return code
|
|
129
130
|
}
|
|
130
|
-
|
|
131
|
+
|
|
131
132
|
// Multiple nodes - create a fragment
|
|
132
133
|
code += ` const fragment = document.createDocumentFragment();\n`
|
|
133
|
-
|
|
134
|
+
|
|
134
135
|
for (const node of nodes) {
|
|
135
136
|
const result = generateDOMCode(node, expressions, ' ', varCounter)
|
|
136
137
|
code += `${result.code}\n`
|
|
137
138
|
code += ` fragment.appendChild(${result.varName});\n`
|
|
138
139
|
}
|
|
139
|
-
|
|
140
|
+
|
|
140
141
|
code += ` return fragment;
|
|
141
142
|
}`
|
|
142
|
-
|
|
143
|
+
|
|
143
144
|
return code
|
|
144
145
|
}
|
|
@@ -255,10 +255,29 @@ export function generateHydrationRuntime(): string {
|
|
|
255
255
|
// Create new handler
|
|
256
256
|
const handler = function(event) {
|
|
257
257
|
try {
|
|
258
|
-
//
|
|
259
|
-
|
|
258
|
+
// 1. Try to find handler function on window (for named functions)
|
|
259
|
+
let handlerFunc = window[handlerName];
|
|
260
|
+
|
|
261
|
+
// 2. If not found, try the expression registry (for inline expressions)
|
|
262
|
+
if (typeof handlerFunc !== 'function' && window.__ZENITH_EXPRESSIONS__) {
|
|
263
|
+
handlerFunc = window.__ZENITH_EXPRESSIONS__.get(handlerName);
|
|
264
|
+
}
|
|
265
|
+
|
|
260
266
|
if (typeof handlerFunc === 'function') {
|
|
261
|
-
|
|
267
|
+
// Call the handler. For expressions, we pass the current state.
|
|
268
|
+
// Note: Phase 6 handles passing loaderData, props, etc. if needed.
|
|
269
|
+
const state = window.__ZENITH_STATE__ || {};
|
|
270
|
+
const loaderData = window.__ZENITH_LOADER_DATA__ || {};
|
|
271
|
+
const props = window.__ZENITH_PROPS__ || {};
|
|
272
|
+
const stores = window.__ZENITH_STORES__ || {};
|
|
273
|
+
|
|
274
|
+
if (handlerFunc.length === 1) {
|
|
275
|
+
// Legacy or simple handler
|
|
276
|
+
handlerFunc(event, element);
|
|
277
|
+
} else {
|
|
278
|
+
// Full context handler
|
|
279
|
+
handlerFunc(event, element, state, loaderData, props, stores);
|
|
280
|
+
}
|
|
262
281
|
} else {
|
|
263
282
|
console.warn('[Zenith] Event handler "' + handlerName + '" not found for ' + eventType + ' event');
|
|
264
283
|
}
|
|
@@ -366,11 +385,11 @@ export function generateExpressionRegistry(expressions: ExpressionIR[]): string
|
|
|
366
385
|
// Registry already initialized
|
|
367
386
|
}`
|
|
368
387
|
}
|
|
369
|
-
|
|
388
|
+
|
|
370
389
|
const registryCode = expressions.map(expr => {
|
|
371
390
|
return ` window.__ZENITH_EXPRESSIONS__.set('${expr.id}', ${expr.id});`
|
|
372
391
|
}).join('\n')
|
|
373
|
-
|
|
392
|
+
|
|
374
393
|
return `
|
|
375
394
|
// Initialize expression registry
|
|
376
395
|
if (typeof window !== 'undefined') {
|
|
@@ -8,9 +8,9 @@ import type { ZenIR } from '../ir/types'
|
|
|
8
8
|
import { generateExpressionWrappers } from './wrapExpression'
|
|
9
9
|
import { generateDOMFunction } from './generateDOM'
|
|
10
10
|
import { generateHydrationRuntime, generateExpressionRegistry } from './generateHydrationBundle'
|
|
11
|
-
import { analyzeAllExpressions
|
|
11
|
+
import { analyzeAllExpressions } from './dataExposure'
|
|
12
12
|
import { generateNavigationRuntime } from './navigation'
|
|
13
|
-
import { extractStateDeclarations } from '../
|
|
13
|
+
import { extractStateDeclarations, extractProps, transformStateDeclarations } from '../parse/scriptAnalysis'
|
|
14
14
|
|
|
15
15
|
export interface RuntimeCode {
|
|
16
16
|
expressions: string // Expression wrapper functions
|
|
@@ -30,44 +30,46 @@ export function transformIR(ir: ZenIR): RuntimeCode {
|
|
|
30
30
|
const expressionDependencies = analyzeAllExpressions(
|
|
31
31
|
ir.template.expressions,
|
|
32
32
|
ir.filePath,
|
|
33
|
-
[], // declaredLoaderProps
|
|
34
|
-
[]
|
|
35
|
-
[] // declaredStores
|
|
33
|
+
[], // declaredLoaderProps
|
|
34
|
+
ir.script?.attributes['props'] ? ir.script.attributes['props'].split(',') : [], // declaredProps
|
|
35
|
+
[] // declaredStores
|
|
36
36
|
)
|
|
37
|
-
|
|
37
|
+
|
|
38
38
|
// Generate expression wrappers with dependencies
|
|
39
39
|
const expressions = generateExpressionWrappers(ir.template.expressions, expressionDependencies)
|
|
40
|
-
|
|
40
|
+
|
|
41
41
|
// Generate DOM creation code
|
|
42
42
|
const renderFunction = generateDOMFunction(
|
|
43
43
|
ir.template.nodes,
|
|
44
44
|
ir.template.expressions,
|
|
45
45
|
'renderDynamicPage'
|
|
46
46
|
)
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
// Generate hydrate function (legacy, for reference)
|
|
49
49
|
const hydrateFunction = generateHydrateFunction()
|
|
50
|
-
|
|
50
|
+
|
|
51
51
|
// Generate Phase 5 hydration runtime
|
|
52
52
|
const hydrationRuntime = generateHydrationRuntime()
|
|
53
|
-
|
|
53
|
+
|
|
54
54
|
// Generate Phase 7 navigation runtime
|
|
55
55
|
const navigationRuntime = generateNavigationRuntime()
|
|
56
|
-
|
|
56
|
+
|
|
57
57
|
// Generate expression registry initialization
|
|
58
58
|
const expressionRegistry = generateExpressionRegistry(ir.template.expressions)
|
|
59
|
-
|
|
59
|
+
|
|
60
60
|
// Generate style injection code
|
|
61
61
|
const stylesCode = generateStyleInjection(ir.styles)
|
|
62
|
-
|
|
63
|
-
// Extract state
|
|
62
|
+
|
|
63
|
+
// Extract state and prop declarations
|
|
64
64
|
const scriptContent = ir.script?.raw || ''
|
|
65
65
|
const stateDeclarations = extractStateDeclarations(scriptContent)
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
66
|
+
const propKeys = Object.keys(ir.script?.attributes || {}).filter(k => k !== 'setup' && k !== 'lang')
|
|
67
|
+
const propDeclarations = extractProps(scriptContent)
|
|
68
|
+
const stateInitCode = generateStateInitialization(stateDeclarations, [...propDeclarations, ...propKeys])
|
|
69
|
+
|
|
70
|
+
// Transform script (remove state and prop declarations, they're handled by runtime)
|
|
71
|
+
const scriptCode = transformStateDeclarations(scriptContent)
|
|
72
|
+
|
|
71
73
|
// Generate complete runtime bundle
|
|
72
74
|
const bundle = generateRuntimeBundle({
|
|
73
75
|
expressions,
|
|
@@ -78,7 +80,7 @@ export function transformIR(ir: ZenIR): RuntimeCode {
|
|
|
78
80
|
scriptCode,
|
|
79
81
|
stateInitCode
|
|
80
82
|
})
|
|
81
|
-
|
|
83
|
+
|
|
82
84
|
return {
|
|
83
85
|
expressions,
|
|
84
86
|
render: renderFunction,
|
|
@@ -102,6 +104,9 @@ function generateRuntimeBundle(parts: {
|
|
|
102
104
|
scriptCode: string
|
|
103
105
|
stateInitCode: string
|
|
104
106
|
}): string {
|
|
107
|
+
// Extract function declarations from script code to register on window
|
|
108
|
+
const functionRegistrations = extractFunctionRegistrations(parts.scriptCode)
|
|
109
|
+
|
|
105
110
|
return `// Zenith Runtime Bundle (Phase 5)
|
|
106
111
|
// Generated at compile time - no .zen parsing in browser
|
|
107
112
|
|
|
@@ -119,8 +124,14 @@ ${parts.stateInitCode}` : ''}
|
|
|
119
124
|
${parts.stylesCode ? `// Style injection
|
|
120
125
|
${parts.stylesCode}` : ''}
|
|
121
126
|
|
|
122
|
-
|
|
123
|
-
|
|
127
|
+
// User script code and function registration
|
|
128
|
+
(function() {
|
|
129
|
+
'use strict';
|
|
130
|
+
|
|
131
|
+
${parts.scriptCode ? parts.scriptCode : ''}
|
|
132
|
+
|
|
133
|
+
${functionRegistrations}
|
|
134
|
+
})();
|
|
124
135
|
|
|
125
136
|
// Export hydration functions
|
|
126
137
|
if (typeof window !== 'undefined') {
|
|
@@ -137,9 +148,95 @@ if (typeof window !== 'undefined') {
|
|
|
137
148
|
console.warn('[Zenith] Cleanup runtime not loaded');
|
|
138
149
|
};
|
|
139
150
|
}
|
|
151
|
+
|
|
152
|
+
// Auto-hydrate on page mount
|
|
153
|
+
(function() {
|
|
154
|
+
'use strict';
|
|
155
|
+
|
|
156
|
+
function autoHydrate() {
|
|
157
|
+
// Initialize state object
|
|
158
|
+
const state = window.__ZENITH_STATE__ || {};
|
|
159
|
+
|
|
160
|
+
// Run state initialization if defined
|
|
161
|
+
if (typeof initializeState === 'function') {
|
|
162
|
+
initializeState(state);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Store state globally
|
|
166
|
+
window.__ZENITH_STATE__ = state;
|
|
167
|
+
|
|
168
|
+
// Expose state variables on window with reactive getters/setters
|
|
169
|
+
// This allows user functions (like increment) to access state variables directly
|
|
170
|
+
for (const key in state) {
|
|
171
|
+
if (state.hasOwnProperty(key) && !window.hasOwnProperty(key)) {
|
|
172
|
+
Object.defineProperty(window, key, {
|
|
173
|
+
get: function() { return window.__ZENITH_STATE__[key]; },
|
|
174
|
+
set: function(value) {
|
|
175
|
+
window.__ZENITH_STATE__[key] = value;
|
|
176
|
+
// Trigger reactive update
|
|
177
|
+
if (window.__zenith_update) {
|
|
178
|
+
window.__zenith_update(window.__ZENITH_STATE__);
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
configurable: true
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Inject styles if defined
|
|
187
|
+
if (typeof injectStyles === 'function') {
|
|
188
|
+
injectStyles();
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Get the router outlet or body
|
|
192
|
+
const container = document.querySelector('#app') || document.body;
|
|
193
|
+
|
|
194
|
+
// Hydrate with state
|
|
195
|
+
if (window.__zenith_hydrate) {
|
|
196
|
+
window.__zenith_hydrate(state, {}, {}, {}, container);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Run on DOM ready
|
|
201
|
+
if (document.readyState === 'loading') {
|
|
202
|
+
document.addEventListener('DOMContentLoaded', autoHydrate);
|
|
203
|
+
} else {
|
|
204
|
+
// DOM already loaded, run on next tick to ensure all scripts are executed
|
|
205
|
+
setTimeout(autoHydrate, 0);
|
|
206
|
+
}
|
|
207
|
+
})();
|
|
140
208
|
`
|
|
141
209
|
}
|
|
142
210
|
|
|
211
|
+
/**
|
|
212
|
+
* Extract function declarations and generate window registration code
|
|
213
|
+
*/
|
|
214
|
+
function extractFunctionRegistrations(scriptCode: string): string {
|
|
215
|
+
if (!scriptCode) return ''
|
|
216
|
+
|
|
217
|
+
// Match function declarations: function name(...) { ... }
|
|
218
|
+
const functionPattern = /function\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\(/g
|
|
219
|
+
const functionNames: string[] = []
|
|
220
|
+
let match
|
|
221
|
+
|
|
222
|
+
while ((match = functionPattern.exec(scriptCode)) !== null) {
|
|
223
|
+
if (match[1]) {
|
|
224
|
+
functionNames.push(match[1])
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (functionNames.length === 0) {
|
|
229
|
+
return ''
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Generate window registration for each function
|
|
233
|
+
const registrations = functionNames.map(name =>
|
|
234
|
+
` if (typeof ${name} === 'function') window.${name} = ${name};`
|
|
235
|
+
).join('\n')
|
|
236
|
+
|
|
237
|
+
return `// Register functions on window for event handlers\n${registrations}`
|
|
238
|
+
}
|
|
239
|
+
|
|
143
240
|
/**
|
|
144
241
|
* Generate hydrate function that mounts the DOM with reactivity
|
|
145
242
|
*/
|
|
@@ -204,7 +301,7 @@ function generateStyleInjection(styles: Array<{ raw: string }>): string {
|
|
|
204
301
|
if (styles.length === 0) {
|
|
205
302
|
return ''
|
|
206
303
|
}
|
|
207
|
-
|
|
304
|
+
|
|
208
305
|
const styleBlocks = styles.map((style, index) => {
|
|
209
306
|
const escapedStyle = style.raw.replace(/`/g, '\\`').replace(/\$/g, '\\$')
|
|
210
307
|
return `
|
|
@@ -212,45 +309,39 @@ function generateStyleInjection(styles: Array<{ raw: string }>): string {
|
|
|
212
309
|
style${index}.textContent = \`${escapedStyle}\`;
|
|
213
310
|
document.head.appendChild(style${index});`
|
|
214
311
|
}).join('')
|
|
215
|
-
|
|
312
|
+
|
|
216
313
|
return `function injectStyles() {${styleBlocks}
|
|
217
314
|
}`
|
|
218
315
|
}
|
|
219
316
|
|
|
220
317
|
/**
|
|
221
318
|
* Generate state initialization code
|
|
319
|
+
* In Phase 9: Also handles props passing
|
|
222
320
|
*/
|
|
223
|
-
function generateStateInitialization(stateDeclarations: Map<string, string
|
|
224
|
-
|
|
225
|
-
return ''
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
const initCode = Array.from(stateDeclarations.entries()).map(([name, value]) => {
|
|
321
|
+
function generateStateInitialization(stateDeclarations: Map<string, string>, propDeclarations: string[]): string {
|
|
322
|
+
const stateInit = Array.from(stateDeclarations.entries()).map(([name, value]) => {
|
|
229
323
|
return `
|
|
230
324
|
// Initialize state: ${name}
|
|
231
|
-
if (
|
|
325
|
+
if (typeof state.${name} === 'undefined') {
|
|
232
326
|
state.${name} = ${value};
|
|
233
327
|
}`
|
|
234
328
|
}).join('')
|
|
235
|
-
|
|
236
|
-
|
|
329
|
+
|
|
330
|
+
const legacyPropInit = propDeclarations.includes('props') ? `
|
|
331
|
+
// Initialize props object (legacy)
|
|
332
|
+
if (typeof window.__ZEN_PROPS__ !== 'undefined') {
|
|
333
|
+
state.props = window.__ZEN_PROPS__;
|
|
334
|
+
}` : ''
|
|
335
|
+
|
|
336
|
+
const individualPropInit = propDeclarations.filter(p => p !== 'props').map(prop => `
|
|
337
|
+
// Initialize prop: ${prop}
|
|
338
|
+
if (typeof state.${prop} === 'undefined' && typeof window.__ZEN_PROPS__ !== 'undefined' && typeof window.__ZEN_PROPS__.${prop} !== 'undefined') {
|
|
339
|
+
state.${prop} = window.__ZEN_PROPS__.${prop};
|
|
340
|
+
}`).join('')
|
|
341
|
+
|
|
342
|
+
return `function initializeState(state) {${stateInit}${legacyPropInit}${individualPropInit}
|
|
237
343
|
}`
|
|
238
344
|
}
|
|
239
345
|
|
|
240
|
-
|
|
241
|
-
* Transform script content
|
|
242
|
-
* Removes state declarations (they're handled by state initialization)
|
|
243
|
-
*/
|
|
244
|
-
function transformScript(scriptContent: string, stateDeclarations: Map<string, string>): string {
|
|
245
|
-
// Remove state declarations - they're handled by initializeState
|
|
246
|
-
let transformed = scriptContent
|
|
247
|
-
|
|
248
|
-
for (const [name] of stateDeclarations.entries()) {
|
|
249
|
-
// Remove "state name = value" declarations
|
|
250
|
-
const stateRegex = new RegExp(`state\\s+${name}\\s*=[^;]*;?`, 'g')
|
|
251
|
-
transformed = transformed.replace(stateRegex, '')
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
return transformed.trim()
|
|
255
|
-
}
|
|
346
|
+
// Note: transformScript is now handled by transformStateDeclarations in legacy/parse.ts
|
|
256
347
|
|
|
@@ -23,42 +23,42 @@ export function wrapExpressionWithLoopContext(
|
|
|
23
23
|
): string {
|
|
24
24
|
const { id, code } = expr
|
|
25
25
|
const escapedCode = code.replace(/`/g, '\\`').replace(/\$/g, '\\$')
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
if (!loopContext || loopContext.variables.length === 0) {
|
|
28
28
|
// No loop context - use standard wrapper (will be handled by wrapExpression)
|
|
29
29
|
return ''
|
|
30
30
|
}
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
// Determine arguments based on dependencies
|
|
33
33
|
const args: string[] = []
|
|
34
|
-
if (dependencies?.usesState || dependencies?.stateProperties.length > 0) args.push('state')
|
|
34
|
+
if (dependencies?.usesState || (dependencies?.stateProperties && dependencies.stateProperties.length > 0)) args.push('state')
|
|
35
35
|
if (dependencies?.usesLoaderData) args.push('loaderData')
|
|
36
36
|
if (dependencies?.usesProps) args.push('props')
|
|
37
37
|
if (dependencies?.usesStores) args.push('stores')
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
// Phase 7: Always add loopContext as the last argument
|
|
40
40
|
args.push('loopContext')
|
|
41
|
-
|
|
41
|
+
|
|
42
42
|
const argsStr = args.join(', ')
|
|
43
|
-
|
|
43
|
+
|
|
44
44
|
// Generate function that merges state and loop context
|
|
45
45
|
// Loop context variables take precedence over state properties with the same name
|
|
46
46
|
const loopVarsDecl = loopContext.variables.map(v => ` const ${v} = loopContext?.${v};`).join('\n')
|
|
47
47
|
const loopVarsObject = `{ ${loopContext.variables.join(', ')} }`
|
|
48
|
-
|
|
48
|
+
|
|
49
49
|
// Create merged context for expression evaluation
|
|
50
50
|
// Order: loopContext > stores > props > loaderData > state
|
|
51
51
|
const contextMerge: string[] = []
|
|
52
|
-
if (dependencies?.usesState || dependencies?.stateProperties.length > 0) contextMerge.push('state')
|
|
52
|
+
if (dependencies?.usesState || (dependencies?.stateProperties && dependencies.stateProperties.length > 0)) contextMerge.push('state')
|
|
53
53
|
if (dependencies?.usesStores) contextMerge.push('stores')
|
|
54
54
|
if (dependencies?.usesProps) contextMerge.push('props')
|
|
55
55
|
if (dependencies?.usesLoaderData) contextMerge.push('loaderData')
|
|
56
56
|
if (loopContext) contextMerge.push('loopContext')
|
|
57
|
-
|
|
58
|
-
const contextObject = contextMerge.length > 0
|
|
57
|
+
|
|
58
|
+
const contextObject = contextMerge.length > 0
|
|
59
59
|
? `const __ctx = Object.assign({}, ${contextMerge.join(', ')});`
|
|
60
60
|
: `const __ctx = loopContext || {};`
|
|
61
|
-
|
|
61
|
+
|
|
62
62
|
return `
|
|
63
63
|
// Expression with loop context: ${escapedCode}
|
|
64
64
|
// Loop variables: ${loopContext.variables.join(', ')}
|