@zenithbuild/core 0.6.2 → 1.0.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.
Files changed (87) hide show
  1. package/README.md +20 -19
  2. package/cli/commands/add.ts +2 -2
  3. package/cli/commands/build.ts +2 -3
  4. package/cli/commands/dev.ts +182 -103
  5. package/cli/commands/index.ts +1 -1
  6. package/cli/commands/preview.ts +1 -1
  7. package/cli/commands/remove.ts +2 -2
  8. package/cli/index.ts +1 -1
  9. package/cli/main.ts +1 -1
  10. package/cli/utils/logger.ts +1 -1
  11. package/cli/utils/plugin-manager.ts +1 -1
  12. package/cli/utils/project.ts +4 -4
  13. package/core/components/ErrorPage.zen +218 -0
  14. package/core/components/index.ts +15 -0
  15. package/core/config.ts +1 -0
  16. package/core/index.ts +29 -0
  17. package/dist/compiler-native-frej59m4.node +0 -0
  18. package/dist/core/compiler-native-frej59m4.node +0 -0
  19. package/dist/core/index.js +6293 -0
  20. package/dist/runtime/lifecycle/index.js +1 -0
  21. package/dist/runtime/reactivity/index.js +1 -0
  22. package/dist/zen-build.js +7465 -19128
  23. package/dist/zen-dev.js +7465 -19128
  24. package/dist/zen-preview.js +7465 -19128
  25. package/dist/zenith.js +7465 -19128
  26. package/package.json +21 -22
  27. package/cli/utils/content.ts +0 -112
  28. package/compiler/README.md +0 -380
  29. package/compiler/build-analyzer.ts +0 -122
  30. package/compiler/css/index.ts +0 -317
  31. package/compiler/discovery/componentDiscovery.ts +0 -178
  32. package/compiler/discovery/layouts.ts +0 -70
  33. package/compiler/errors/compilerError.ts +0 -56
  34. package/compiler/finalize/finalizeOutput.ts +0 -192
  35. package/compiler/finalize/generateFinalBundle.ts +0 -82
  36. package/compiler/index.ts +0 -83
  37. package/compiler/ir/types.ts +0 -174
  38. package/compiler/output/types.ts +0 -34
  39. package/compiler/parse/detectMapExpressions.ts +0 -102
  40. package/compiler/parse/importTypes.ts +0 -78
  41. package/compiler/parse/parseImports.ts +0 -309
  42. package/compiler/parse/parseScript.ts +0 -46
  43. package/compiler/parse/parseTemplate.ts +0 -599
  44. package/compiler/parse/parseZenFile.ts +0 -66
  45. package/compiler/parse/scriptAnalysis.ts +0 -91
  46. package/compiler/parse/trackLoopContext.ts +0 -82
  47. package/compiler/runtime/dataExposure.ts +0 -317
  48. package/compiler/runtime/generateDOM.ts +0 -246
  49. package/compiler/runtime/generateHydrationBundle.ts +0 -407
  50. package/compiler/runtime/hydration.ts +0 -309
  51. package/compiler/runtime/navigation.ts +0 -432
  52. package/compiler/runtime/thinRuntime.ts +0 -160
  53. package/compiler/runtime/transformIR.ts +0 -370
  54. package/compiler/runtime/wrapExpression.ts +0 -95
  55. package/compiler/runtime/wrapExpressionWithLoop.ts +0 -83
  56. package/compiler/spa-build.ts +0 -917
  57. package/compiler/ssg-build.ts +0 -422
  58. package/compiler/test/validate-test.ts +0 -104
  59. package/compiler/transform/classifyExpression.ts +0 -444
  60. package/compiler/transform/componentResolver.ts +0 -312
  61. package/compiler/transform/componentScriptTransformer.ts +0 -303
  62. package/compiler/transform/expressionTransformer.ts +0 -385
  63. package/compiler/transform/fragmentLowering.ts +0 -634
  64. package/compiler/transform/generateBindings.ts +0 -47
  65. package/compiler/transform/generateHTML.ts +0 -28
  66. package/compiler/transform/layoutProcessor.ts +0 -132
  67. package/compiler/transform/slotResolver.ts +0 -292
  68. package/compiler/transform/transformNode.ts +0 -126
  69. package/compiler/transform/transformTemplate.ts +0 -38
  70. package/compiler/validate/invariants.ts +0 -292
  71. package/compiler/validate/validateExpressions.ts +0 -168
  72. package/core/config/index.ts +0 -16
  73. package/core/config/loader.ts +0 -69
  74. package/core/config/types.ts +0 -89
  75. package/core/plugins/index.ts +0 -7
  76. package/core/plugins/registry.ts +0 -81
  77. package/dist/cli.js +0 -11665
  78. package/router/manifest.ts +0 -314
  79. package/router/navigation/ZenLink.zen +0 -231
  80. package/router/navigation/index.ts +0 -78
  81. package/router/navigation/zen-link.ts +0 -584
  82. package/router/runtime.ts +0 -458
  83. package/router/types.ts +0 -168
  84. package/runtime/build.ts +0 -17
  85. package/runtime/bundle-generator.ts +0 -1247
  86. package/runtime/client-runtime.ts +0 -549
  87. package/runtime/serve.ts +0 -93
@@ -1,370 +0,0 @@
1
- /**
2
- * Transform IR to Runtime Code
3
- *
4
- * Phase 4: Transform ZenIR into runtime-ready JavaScript code with full reactivity
5
- */
6
-
7
- import type { ZenIR, ScriptImport } from '../ir/types'
8
- import { generateExpressionWrappers } from './wrapExpression'
9
- import { generateDOMFunction } from './generateDOM'
10
- import { generateHydrationRuntime, generateExpressionRegistry } from './generateHydrationBundle'
11
- import { analyzeAllExpressions } from './dataExposure'
12
- import { generateNavigationRuntime } from './navigation'
13
- import { extractStateDeclarations, extractProps, transformStateDeclarations } from '../parse/scriptAnalysis'
14
- import { transformAllComponentScripts, emitImports } from '../transform/componentScriptTransformer'
15
-
16
- export interface RuntimeCode {
17
- expressions: string // Expression wrapper functions
18
- render: string // renderDynamicPage function (legacy, for reference)
19
- hydration: string // Phase 5 hydration runtime code
20
- styles: string // Style injection code
21
- script: string // Transformed script code
22
- stateInit: string // State initialization code
23
- bundle: string // Complete runtime bundle (expressions + hydration + helpers)
24
- }
25
-
26
- /**
27
- * Transform ZenIR into runtime JavaScript code
28
- */
29
- export async function transformIR(ir: ZenIR): Promise<RuntimeCode> {
30
- // Phase 6: Analyze expression dependencies for explicit data exposure
31
- const expressionDependencies = analyzeAllExpressions(
32
- ir.template.expressions,
33
- ir.filePath,
34
- [], // declaredLoaderProps
35
- ir.script?.attributes['props'] ? ir.script.attributes['props'].split(',') : [], // declaredProps
36
- [] // declaredStores
37
- )
38
-
39
- // Generate expression wrappers with dependencies
40
- const expressions = generateExpressionWrappers(ir.template.expressions, expressionDependencies)
41
-
42
- // Generate DOM creation code
43
- const renderFunction = generateDOMFunction(
44
- ir.template.nodes,
45
- ir.template.expressions,
46
- 'renderDynamicPage'
47
- )
48
-
49
- // Generate hydrate function (legacy, for reference)
50
- const hydrateFunction = generateHydrateFunction()
51
-
52
- // Generate Phase 5 hydration runtime
53
- const hydrationRuntime = generateHydrationRuntime()
54
-
55
- // Generate Phase 7 navigation runtime
56
- const navigationRuntime = generateNavigationRuntime()
57
-
58
- // Generate expression registry initialization
59
- const expressionRegistry = generateExpressionRegistry(ir.template.expressions)
60
-
61
- // Generate style injection code
62
- const stylesCode = generateStyleInjection(ir.styles)
63
-
64
- // Extract state and prop declarations
65
- const scriptContent = ir.script?.raw || ''
66
- const stateDeclarations = extractStateDeclarations(scriptContent)
67
- const propKeys = Object.keys(ir.script?.attributes || {}).filter(k => k !== 'setup' && k !== 'lang')
68
- const propDeclarations = extractProps(scriptContent)
69
- const stateInitCode = generateStateInitialization(stateDeclarations, [...propDeclarations, ...propKeys])
70
-
71
- // Transform script (remove state and prop declarations, they're handled by runtime)
72
- const scriptCode = transformStateDeclarations(scriptContent)
73
-
74
- // Transform component scripts for instance-scoped execution (synchronous - Acorn)
75
- const componentScriptResult = transformAllComponentScripts(ir.componentScripts || [])
76
-
77
- // Generate complete runtime bundle
78
- const bundle = generateRuntimeBundle({
79
- expressions,
80
- expressionRegistry,
81
- hydrationRuntime,
82
- navigationRuntime,
83
- stylesCode,
84
- scriptCode,
85
- stateInitCode,
86
- componentScriptCode: componentScriptResult.code,
87
- npmImports: componentScriptResult.imports
88
- })
89
-
90
- return {
91
- expressions,
92
- render: renderFunction,
93
- hydration: hydrationRuntime,
94
- styles: stylesCode,
95
- script: scriptCode,
96
- stateInit: stateInitCode,
97
- bundle
98
- }
99
- }
100
-
101
- /**
102
- * Generate complete runtime bundle
103
- */
104
- function generateRuntimeBundle(parts: {
105
- expressions: string
106
- expressionRegistry: string
107
- hydrationRuntime: string
108
- navigationRuntime: string
109
- stylesCode: string
110
- scriptCode: string
111
- stateInitCode: string
112
- componentScriptCode: string // Component factories
113
- npmImports: ScriptImport[] // Structured npm imports from component scripts
114
- }): string {
115
- // Extract function declarations from script code to register on window
116
- const functionRegistrations = extractFunctionRegistrations(parts.scriptCode)
117
-
118
- // Generate npm imports header (hoisted, deduplicated, deterministic)
119
- const npmImportsHeader = parts.npmImports.length > 0
120
- ? `// NPM Imports (hoisted from component scripts)\n${emitImports(parts.npmImports)}\n\n`
121
- : ''
122
-
123
- return `// Zenith Runtime Bundle (Phase 5)
124
- // Generated at compile time - no .zen parsing in browser
125
-
126
- ${npmImportsHeader}${parts.expressions}
127
-
128
- ${parts.expressionRegistry}
129
-
130
- ${parts.hydrationRuntime}
131
-
132
- ${parts.navigationRuntime}
133
-
134
- ${parts.stylesCode ? `// Style injection
135
- ${parts.stylesCode}` : ''}
136
-
137
- // User script code - executed first to define variables needed by state initialization
138
- ${parts.scriptCode ? parts.scriptCode : ''}
139
-
140
- ${functionRegistrations}
141
-
142
- ${parts.stateInitCode ? `// State initialization
143
- ${parts.stateInitCode}` : ''}
144
-
145
- ${parts.componentScriptCode ? `// Component factories (instance-scoped)
146
- ${parts.componentScriptCode}` : ''}
147
-
148
- // Export hydration functions
149
- if (typeof window !== 'undefined') {
150
- window.zenithHydrate = window.__zenith_hydrate || function(state, container) {
151
- console.warn('[Zenith] Hydration runtime not loaded');
152
- };
153
- window.zenithUpdate = window.__zenith_update || function(state) {
154
- console.warn('[Zenith] Update runtime not loaded');
155
- };
156
- window.zenithBindEvents = window.__zenith_bindEvents || function(container) {
157
- console.warn('[Zenith] Event binding runtime not loaded');
158
- };
159
- window.zenithCleanup = window.__zenith_cleanup || function(container) {
160
- console.warn('[Zenith] Cleanup runtime not loaded');
161
- };
162
- }
163
-
164
- // Auto-hydrate on page mount
165
- (function() {
166
- 'use strict';
167
-
168
- function autoHydrate() {
169
- // Initialize state object
170
- const state = window.__ZENITH_STATE__ || {};
171
-
172
- // Run state initialization if defined
173
- if (typeof initializeState === 'function') {
174
- initializeState(state);
175
- }
176
-
177
- // Store state globally
178
- window.__ZENITH_STATE__ = state;
179
-
180
- // Expose state variables on window with reactive getters/setters
181
- // This allows user functions (like increment) to access state variables directly
182
- for (const key in state) {
183
- if (state.hasOwnProperty(key) && !window.hasOwnProperty(key)) {
184
- Object.defineProperty(window, key, {
185
- get: function() { return window.__ZENITH_STATE__[key]; },
186
- set: function(value) {
187
- window.__ZENITH_STATE__[key] = value;
188
- // Trigger reactive update
189
- if (window.__zenith_update) {
190
- window.__zenith_update(window.__ZENITH_STATE__);
191
- }
192
- },
193
- configurable: true
194
- });
195
- }
196
- }
197
-
198
- // Inject styles if defined
199
- if (typeof injectStyles === 'function') {
200
- injectStyles();
201
- }
202
-
203
- // Get the router outlet or body
204
- const container = document.querySelector('#app') || document.body;
205
-
206
- // Hydrate with state (expressions, bindings)
207
- if (window.__zenith_hydrate) {
208
- window.__zenith_hydrate(state, {}, {}, {}, container);
209
- }
210
-
211
- // Hydrate components by discovering data-zen-component markers
212
- // This is the ONLY place component instantiation happens - driven by DOM markers
213
- if (window.__zenith && window.__zenith.hydrateComponents) {
214
- window.__zenith.hydrateComponents(container);
215
- }
216
-
217
- // Trigger page-level mount lifecycle
218
- if (window.__zenith && window.__zenith.triggerMount) {
219
- window.__zenith.triggerMount();
220
- }
221
- }
222
-
223
- // Run on DOM ready
224
- if (document.readyState === 'loading') {
225
- document.addEventListener('DOMContentLoaded', autoHydrate);
226
- } else {
227
- // DOM already loaded, hydrate immediately
228
- autoHydrate();
229
- }
230
- })();
231
- `
232
- }
233
-
234
- /**
235
- * Extract function declarations and generate window registration code
236
- */
237
- function extractFunctionRegistrations(scriptCode: string): string {
238
- if (!scriptCode) return ''
239
-
240
- // Match function declarations: function name(...) { ... }
241
- const functionPattern = /function\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\(/g
242
- const functionNames: string[] = []
243
- let match
244
-
245
- while ((match = functionPattern.exec(scriptCode)) !== null) {
246
- if (match[1]) {
247
- functionNames.push(match[1])
248
- }
249
- }
250
-
251
- if (functionNames.length === 0) {
252
- return ''
253
- }
254
-
255
- // Generate window registration for each function
256
- const registrations = functionNames.map(name =>
257
- ` if (typeof ${name} === 'function') window.${name} = ${name};`
258
- ).join('\n')
259
-
260
- return `// Register functions on window for event handlers\n${registrations}`
261
- }
262
-
263
- /**
264
- * Generate hydrate function that mounts the DOM with reactivity
265
- */
266
- function generateHydrateFunction(): string {
267
- return `function hydrate(root, state) {
268
- if (!root) {
269
- // SSR fallback - return initial HTML string
270
- console.warn('[Zenith] hydrate called without root element - SSR mode');
271
- return '';
272
- }
273
-
274
- // Clear root
275
- root.innerHTML = '';
276
-
277
- // Render template
278
- const dom = renderDynamicPage(state);
279
-
280
- // Append to root
281
- if (dom instanceof DocumentFragment) {
282
- root.appendChild(dom);
283
- } else if (dom instanceof Node) {
284
- root.appendChild(dom);
285
- }
286
-
287
- // Bind event handlers
288
- bindEventHandlers(root, state);
289
-
290
- // Set up reactive updates (if state is reactive)
291
- setupReactiveUpdates(root, state);
292
-
293
- return root;
294
- }
295
-
296
- function bindEventHandlers(root, state) {
297
- // Find all elements with data-zen-* event attributes
298
- const eventTypes = ['click', 'change', 'input', 'submit', 'focus', 'blur'];
299
-
300
- for (const eventType of eventTypes) {
301
- const elements = root.querySelectorAll(\`[data-zen-\${eventType}]\`);
302
- for (const el of elements) {
303
- const handlerName = el.getAttribute(\`data-zen-\${eventType}\`);
304
- if (handlerName && typeof window[handlerName] === 'function') {
305
- el.addEventListener(eventType, (e) => {
306
- window[handlerName](e, el);
307
- });
308
- }
309
- }
310
- }
311
- }
312
-
313
- function setupReactiveUpdates(root, state) {
314
- // For now, reactive updates are handled by the existing binding system
315
- // This is a placeholder for future reactive DOM updates
316
- // The existing runtime handles reactivity via state property setters
317
- }`
318
- }
319
-
320
- /**
321
- * Generate style injection code
322
- */
323
- function generateStyleInjection(styles: Array<{ raw: string }>): string {
324
- if (styles.length === 0) {
325
- return ''
326
- }
327
-
328
- const styleBlocks = styles.map((style, index) => {
329
- const escapedStyle = style.raw.replace(/`/g, '\\`').replace(/\$/g, '\\$')
330
- return `
331
- const style${index} = document.createElement('style');
332
- style${index}.textContent = \`${escapedStyle}\`;
333
- document.head.appendChild(style${index});`
334
- }).join('')
335
-
336
- return `function injectStyles() {${styleBlocks}
337
- }`
338
- }
339
-
340
- /**
341
- * Generate state initialization code
342
- * In Phase 9: Also handles props passing
343
- */
344
- function generateStateInitialization(stateDeclarations: Map<string, string>, propDeclarations: string[]): string {
345
- const stateInit = Array.from(stateDeclarations.entries()).map(([name, value]) => {
346
- return `
347
- // Initialize state: ${name}
348
- if (typeof state.${name} === 'undefined') {
349
- state.${name} = ${value};
350
- }`
351
- }).join('')
352
-
353
- const legacyPropInit = propDeclarations.includes('props') ? `
354
- // Initialize props object (legacy)
355
- if (typeof window.__ZEN_PROPS__ !== 'undefined') {
356
- state.props = window.__ZEN_PROPS__;
357
- }` : ''
358
-
359
- const individualPropInit = propDeclarations.filter(p => p !== 'props').map(prop => `
360
- // Initialize prop: ${prop}
361
- if (typeof state.${prop} === 'undefined' && typeof window.__ZEN_PROPS__ !== 'undefined' && typeof window.__ZEN_PROPS__.${prop} !== 'undefined') {
362
- state.${prop} = window.__ZEN_PROPS__.${prop};
363
- }`).join('')
364
-
365
- return `function initializeState(state) {${stateInit}${legacyPropInit}${individualPropInit}
366
- }`
367
- }
368
-
369
- // Note: transformScript is now handled by transformStateDeclarations in legacy/parse.ts
370
-
@@ -1,95 +0,0 @@
1
- /**
2
- * Expression Wrapper
3
- *
4
- * Wraps extracted expressions into runtime functions with explicit data arguments
5
- *
6
- * Phase 6: Expressions now accept explicit loaderData, props, stores arguments
7
- * instead of relying on implicit globals
8
- */
9
-
10
- import type { ExpressionIR, LoopContext } from '../ir/types'
11
- import type { ExpressionDataDependencies } from './dataExposure'
12
- import { generateExplicitExpressionWrapper } from './dataExposure'
13
- import { wrapExpressionWithLoopContext } from './wrapExpressionWithLoop'
14
-
15
- import { transformExpressionJSX } from '../transform/expressionTransformer'
16
-
17
- /**
18
- * Wrap an expression into a runtime function with explicit data arguments
19
- *
20
- * Phase 6: Supports explicit loaderData, props, stores arguments
21
- * Phase 7: Supports loop context for expressions inside map iterations
22
- */
23
- export function wrapExpression(
24
- expr: ExpressionIR,
25
- dependencies?: ExpressionDataDependencies,
26
- loopContext?: LoopContext // Phase 7: Loop context for map expressions
27
- ): string {
28
- const { id, code } = expr
29
-
30
- // Phase 7: If loop context is provided, use loop-aware wrapper
31
- if (loopContext && loopContext.variables.length > 0) {
32
- return wrapExpressionWithLoopContext(expr, loopContext, dependencies)
33
- }
34
-
35
- // If dependencies are provided, use explicit wrapper (Phase 6)
36
- if (dependencies) {
37
- return generateExplicitExpressionWrapper(expr, dependencies)
38
- }
39
-
40
- // Fallback to legacy wrapper (backwards compatibility)
41
- // Transform JSX-like tags inside expression code
42
- const transformedCode = transformExpressionJSX(code)
43
- // Escape the code for use in a single-line comment (replace newlines with spaces)
44
- const commentCode = code.replace(/[\r\n]+/g, ' ').replace(/\s+/g, ' ').substring(0, 100)
45
- const jsonEscapedCode = JSON.stringify(code)
46
-
47
- return `
48
- // Expression: ${commentCode}${code.length > 100 ? '...' : ''}
49
- const ${id} = (state) => {
50
- try {
51
- // Expose zenith helpers for JSX and content
52
- const __zenith = window.__zenith || {};
53
- const zenCollection = __zenith.zenCollection || ((name) => ({ get: () => [] }));
54
-
55
- with (state) {
56
- return ${transformedCode};
57
- }
58
- } catch (e) {
59
- console.warn('[Zenith] Expression evaluation error:', ${jsonEscapedCode}, e);
60
- return undefined;
61
- }
62
- };`
63
- }
64
-
65
- /**
66
- * Generate all expression wrappers for a set of expressions
67
- *
68
- * Phase 6: Accepts dependencies array for explicit data exposure
69
- * Phase 7: Accepts loop contexts for expressions inside map iterations
70
- */
71
- export function generateExpressionWrappers(
72
- expressions: ExpressionIR[],
73
- dependencies?: ExpressionDataDependencies[],
74
- loopContexts?: (LoopContext | undefined)[] // Phase 7: Loop contexts for each expression
75
- ): string {
76
- if (expressions.length === 0) {
77
- return ''
78
- }
79
-
80
- if (dependencies && dependencies.length === expressions.length) {
81
- // Use explicit wrappers with dependencies and optional loop contexts
82
- return expressions
83
- .map((expr, index) => {
84
- const loopCtx = loopContexts && loopContexts[index] !== undefined
85
- ? loopContexts[index]
86
- : undefined
87
- return wrapExpression(expr, dependencies[index], loopCtx)
88
- })
89
- .join('\n')
90
- }
91
-
92
- // Fallback to legacy wrappers (no dependencies, no loop contexts)
93
- return expressions.map(expr => wrapExpression(expr)).join('\n')
94
- }
95
-
@@ -1,83 +0,0 @@
1
- /**
2
- * Expression Wrapper with Loop Context Support
3
- *
4
- * Phase 7: Wraps expressions that reference loop variables from map iterations
5
- *
6
- * Generates runtime functions that accept (state, loaderData, props, stores, loopContext)
7
- * and evaluate expressions with both global state and loop-scoped variables available
8
- */
9
-
10
- import type { ExpressionIR, LoopContext } from '../ir/types'
11
- import type { ExpressionDataDependencies } from './dataExposure'
12
- import { transformExpressionJSX } from '../transform/expressionTransformer'
13
-
14
- /**
15
- * Generate an expression wrapper that accepts loop context
16
- *
17
- * Phase 7: Expressions inside map loops need access to loop variables (e.g., todo, index)
18
- * in addition to global state (state, loaderData, props, stores)
19
- */
20
- export function wrapExpressionWithLoopContext(
21
- expr: ExpressionIR,
22
- loopContext?: LoopContext,
23
- dependencies?: ExpressionDataDependencies
24
- ): string {
25
- const { id, code } = expr
26
- const escapedCode = code.replace(/`/g, '\\`').replace(/\$/g, '\\$')
27
-
28
- if (!loopContext || loopContext.variables.length === 0) {
29
- // No loop context - use standard wrapper (will be handled by wrapExpression)
30
- return ''
31
- }
32
-
33
- // Determine arguments based on dependencies
34
- const args: string[] = []
35
- if (dependencies?.usesState || (dependencies?.stateProperties && dependencies.stateProperties.length > 0)) args.push('state')
36
- if (dependencies?.usesLoaderData) args.push('loaderData')
37
- if (dependencies?.usesProps) args.push('props')
38
- if (dependencies?.usesStores) args.push('stores')
39
-
40
- // Phase 7: Always add loopContext as the last argument
41
- args.push('loopContext')
42
-
43
- const argsStr = args.join(', ')
44
-
45
- // Generate function that merges state and loop context
46
- // Loop context variables take precedence over state properties with the same name
47
- const loopVarsDecl = loopContext.variables.map(v => ` const ${v} = loopContext?.${v};`).join('\n')
48
- const loopVarsObject = `{ ${loopContext.variables.join(', ')} }`
49
-
50
- // Create merged context for expression evaluation
51
- // Order: loopContext > stores > props > loaderData > state
52
- const contextMerge: string[] = []
53
- if (dependencies?.usesState || (dependencies?.stateProperties && dependencies.stateProperties.length > 0)) contextMerge.push('state')
54
- if (dependencies?.usesStores) contextMerge.push('stores')
55
- if (dependencies?.usesProps) contextMerge.push('props')
56
- if (dependencies?.usesLoaderData) contextMerge.push('loaderData')
57
- if (loopContext) contextMerge.push('loopContext')
58
-
59
- const contextObject = contextMerge.length > 0
60
- ? `const __ctx = Object.assign({}, ${contextMerge.join(', ')});`
61
- : `const __ctx = loopContext || {};`
62
-
63
- // Transform JSX
64
- // The fix for 'undefined' string assignment is applied within transformExpressionJSX
65
- // by ensuring that any remaining text is properly quoted as a string literal
66
- // or recognized as an existing h() call.
67
- const transformedCode = transformExpressionJSX(code)
68
-
69
- return `
70
- // Expression with loop context: ${escapedCode}
71
- // Loop variables: ${loopContext.variables.join(', ')}
72
- const ${id} = (${argsStr}) => {
73
- try {
74
- ${contextObject}
75
- with (__ctx) {
76
- return ${transformedCode};
77
- }
78
- } catch (e) {
79
- console.warn('[Zenith] Expression evaluation error for "${escapedCode}":', e);
80
- return undefined;
81
- }
82
- };`
83
- }