@zenithbuild/core 0.4.7 → 0.5.0-beta.2.2

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 (110) hide show
  1. package/CORE_CONTRACT.md +143 -0
  2. package/README.md +11 -31
  3. package/bin/zenith.js +68 -0
  4. package/package.json +41 -53
  5. package/src/config.js +134 -0
  6. package/src/core-template.js +30 -0
  7. package/src/errors.js +54 -0
  8. package/src/guards.js +61 -0
  9. package/src/hash.js +52 -0
  10. package/src/index.js +26 -0
  11. package/src/ir/index.js +1 -0
  12. package/src/order.js +69 -0
  13. package/src/path.js +131 -0
  14. package/src/schema.js +28 -0
  15. package/src/version.js +67 -0
  16. package/bin/zen-build.ts +0 -2
  17. package/bin/zen-dev.ts +0 -2
  18. package/bin/zen-preview.ts +0 -2
  19. package/bin/zenith.ts +0 -2
  20. package/cli/commands/add.ts +0 -37
  21. package/cli/commands/build.ts +0 -37
  22. package/cli/commands/create.ts +0 -702
  23. package/cli/commands/dev.ts +0 -335
  24. package/cli/commands/index.ts +0 -112
  25. package/cli/commands/preview.ts +0 -62
  26. package/cli/commands/remove.ts +0 -33
  27. package/cli/index.ts +0 -10
  28. package/cli/main.ts +0 -101
  29. package/cli/utils/branding.ts +0 -178
  30. package/cli/utils/content.ts +0 -112
  31. package/cli/utils/logger.ts +0 -46
  32. package/cli/utils/plugin-manager.ts +0 -114
  33. package/cli/utils/project.ts +0 -77
  34. package/compiler/README.md +0 -380
  35. package/compiler/build-analyzer.ts +0 -122
  36. package/compiler/css/index.ts +0 -317
  37. package/compiler/discovery/componentDiscovery.ts +0 -178
  38. package/compiler/discovery/layouts.ts +0 -70
  39. package/compiler/errors/compilerError.ts +0 -56
  40. package/compiler/finalize/finalizeOutput.ts +0 -192
  41. package/compiler/finalize/generateFinalBundle.ts +0 -82
  42. package/compiler/index.ts +0 -82
  43. package/compiler/ir/types.ts +0 -162
  44. package/compiler/output/types.ts +0 -34
  45. package/compiler/parse/detectMapExpressions.ts +0 -102
  46. package/compiler/parse/parseScript.ts +0 -46
  47. package/compiler/parse/parseTemplate.ts +0 -599
  48. package/compiler/parse/parseZenFile.ts +0 -66
  49. package/compiler/parse/scriptAnalysis.ts +0 -91
  50. package/compiler/parse/trackLoopContext.ts +0 -82
  51. package/compiler/runtime/dataExposure.ts +0 -317
  52. package/compiler/runtime/generateDOM.ts +0 -246
  53. package/compiler/runtime/generateHydrationBundle.ts +0 -407
  54. package/compiler/runtime/hydration.ts +0 -309
  55. package/compiler/runtime/navigation.ts +0 -432
  56. package/compiler/runtime/thinRuntime.ts +0 -160
  57. package/compiler/runtime/transformIR.ts +0 -363
  58. package/compiler/runtime/wrapExpression.ts +0 -95
  59. package/compiler/runtime/wrapExpressionWithLoop.ts +0 -83
  60. package/compiler/spa-build.ts +0 -917
  61. package/compiler/ssg-build.ts +0 -422
  62. package/compiler/test/validate-test.ts +0 -104
  63. package/compiler/transform/classifyExpression.ts +0 -444
  64. package/compiler/transform/componentResolver.ts +0 -312
  65. package/compiler/transform/componentScriptTransformer.ts +0 -147
  66. package/compiler/transform/expressionTransformer.ts +0 -385
  67. package/compiler/transform/fragmentLowering.ts +0 -634
  68. package/compiler/transform/generateBindings.ts +0 -47
  69. package/compiler/transform/generateHTML.ts +0 -28
  70. package/compiler/transform/layoutProcessor.ts +0 -132
  71. package/compiler/transform/slotResolver.ts +0 -292
  72. package/compiler/transform/transformNode.ts +0 -126
  73. package/compiler/transform/transformTemplate.ts +0 -38
  74. package/compiler/validate/invariants.ts +0 -292
  75. package/compiler/validate/validateExpressions.ts +0 -168
  76. package/core/config/index.ts +0 -16
  77. package/core/config/loader.ts +0 -69
  78. package/core/config/types.ts +0 -89
  79. package/core/index.ts +0 -135
  80. package/core/lifecycle/index.ts +0 -49
  81. package/core/lifecycle/zen-mount.ts +0 -182
  82. package/core/lifecycle/zen-unmount.ts +0 -88
  83. package/core/plugins/index.ts +0 -7
  84. package/core/plugins/registry.ts +0 -81
  85. package/core/reactivity/index.ts +0 -54
  86. package/core/reactivity/tracking.ts +0 -167
  87. package/core/reactivity/zen-batch.ts +0 -57
  88. package/core/reactivity/zen-effect.ts +0 -139
  89. package/core/reactivity/zen-memo.ts +0 -146
  90. package/core/reactivity/zen-ref.ts +0 -52
  91. package/core/reactivity/zen-signal.ts +0 -121
  92. package/core/reactivity/zen-state.ts +0 -180
  93. package/core/reactivity/zen-untrack.ts +0 -44
  94. package/dist/cli.js +0 -11659
  95. package/dist/zen-build.js +0 -15633
  96. package/dist/zen-dev.js +0 -15633
  97. package/dist/zen-preview.js +0 -15633
  98. package/dist/zenith.js +0 -15633
  99. package/router/index.ts +0 -76
  100. package/router/manifest.ts +0 -314
  101. package/router/navigation/ZenLink.zen +0 -231
  102. package/router/navigation/index.ts +0 -78
  103. package/router/navigation/zen-link.ts +0 -584
  104. package/router/runtime.ts +0 -458
  105. package/router/types.ts +0 -168
  106. package/runtime/build.ts +0 -17
  107. package/runtime/bundle-generator.ts +0 -943
  108. package/runtime/client-runtime.ts +0 -549
  109. package/runtime/serve.ts +0 -93
  110. package/tsconfig.json +0 -28
@@ -1,363 +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 } 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 } 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 function transformIR(ir: ZenIR): 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
75
- const componentScriptCode = 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 // Component factories
87
- })
88
-
89
- return {
90
- expressions,
91
- render: renderFunction,
92
- hydration: hydrationRuntime,
93
- styles: stylesCode,
94
- script: scriptCode,
95
- stateInit: stateInitCode,
96
- bundle
97
- }
98
- }
99
-
100
- /**
101
- * Generate complete runtime bundle
102
- */
103
- function generateRuntimeBundle(parts: {
104
- expressions: string
105
- expressionRegistry: string
106
- hydrationRuntime: string
107
- navigationRuntime: string
108
- stylesCode: string
109
- scriptCode: string
110
- stateInitCode: string
111
- componentScriptCode: string // Component factories
112
- }): string {
113
- // Extract function declarations from script code to register on window
114
- const functionRegistrations = extractFunctionRegistrations(parts.scriptCode)
115
-
116
- return `// Zenith Runtime Bundle (Phase 5)
117
- // Generated at compile time - no .zen parsing in browser
118
-
119
- ${parts.expressions}
120
-
121
- ${parts.expressionRegistry}
122
-
123
- ${parts.hydrationRuntime}
124
-
125
- ${parts.navigationRuntime}
126
-
127
- ${parts.stylesCode ? `// Style injection
128
- ${parts.stylesCode}` : ''}
129
-
130
- // User script code - executed first to define variables needed by state initialization
131
- ${parts.scriptCode ? parts.scriptCode : ''}
132
-
133
- ${functionRegistrations}
134
-
135
- ${parts.stateInitCode ? `// State initialization
136
- ${parts.stateInitCode}` : ''}
137
-
138
- ${parts.componentScriptCode ? `// Component factories (instance-scoped)
139
- ${parts.componentScriptCode}` : ''}
140
-
141
- // Export hydration functions
142
- if (typeof window !== 'undefined') {
143
- window.zenithHydrate = window.__zenith_hydrate || function(state, container) {
144
- console.warn('[Zenith] Hydration runtime not loaded');
145
- };
146
- window.zenithUpdate = window.__zenith_update || function(state) {
147
- console.warn('[Zenith] Update runtime not loaded');
148
- };
149
- window.zenithBindEvents = window.__zenith_bindEvents || function(container) {
150
- console.warn('[Zenith] Event binding runtime not loaded');
151
- };
152
- window.zenithCleanup = window.__zenith_cleanup || function(container) {
153
- console.warn('[Zenith] Cleanup runtime not loaded');
154
- };
155
- }
156
-
157
- // Auto-hydrate on page mount
158
- (function() {
159
- 'use strict';
160
-
161
- function autoHydrate() {
162
- // Initialize state object
163
- const state = window.__ZENITH_STATE__ || {};
164
-
165
- // Run state initialization if defined
166
- if (typeof initializeState === 'function') {
167
- initializeState(state);
168
- }
169
-
170
- // Store state globally
171
- window.__ZENITH_STATE__ = state;
172
-
173
- // Expose state variables on window with reactive getters/setters
174
- // This allows user functions (like increment) to access state variables directly
175
- for (const key in state) {
176
- if (state.hasOwnProperty(key) && !window.hasOwnProperty(key)) {
177
- Object.defineProperty(window, key, {
178
- get: function() { return window.__ZENITH_STATE__[key]; },
179
- set: function(value) {
180
- window.__ZENITH_STATE__[key] = value;
181
- // Trigger reactive update
182
- if (window.__zenith_update) {
183
- window.__zenith_update(window.__ZENITH_STATE__);
184
- }
185
- },
186
- configurable: true
187
- });
188
- }
189
- }
190
-
191
- // Inject styles if defined
192
- if (typeof injectStyles === 'function') {
193
- injectStyles();
194
- }
195
-
196
- // Get the router outlet or body
197
- const container = document.querySelector('#app') || document.body;
198
-
199
- // Hydrate with state (expressions, bindings)
200
- if (window.__zenith_hydrate) {
201
- window.__zenith_hydrate(state, {}, {}, {}, container);
202
- }
203
-
204
- // Hydrate components by discovering data-zen-component markers
205
- // This is the ONLY place component instantiation happens - driven by DOM markers
206
- if (window.__zenith && window.__zenith.hydrateComponents) {
207
- window.__zenith.hydrateComponents(container);
208
- }
209
-
210
- // Trigger page-level mount lifecycle
211
- if (window.__zenith && window.__zenith.triggerMount) {
212
- window.__zenith.triggerMount();
213
- }
214
- }
215
-
216
- // Run on DOM ready
217
- if (document.readyState === 'loading') {
218
- document.addEventListener('DOMContentLoaded', autoHydrate);
219
- } else {
220
- // DOM already loaded, hydrate immediately
221
- autoHydrate();
222
- }
223
- })();
224
- `
225
- }
226
-
227
- /**
228
- * Extract function declarations and generate window registration code
229
- */
230
- function extractFunctionRegistrations(scriptCode: string): string {
231
- if (!scriptCode) return ''
232
-
233
- // Match function declarations: function name(...) { ... }
234
- const functionPattern = /function\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\(/g
235
- const functionNames: string[] = []
236
- let match
237
-
238
- while ((match = functionPattern.exec(scriptCode)) !== null) {
239
- if (match[1]) {
240
- functionNames.push(match[1])
241
- }
242
- }
243
-
244
- if (functionNames.length === 0) {
245
- return ''
246
- }
247
-
248
- // Generate window registration for each function
249
- const registrations = functionNames.map(name =>
250
- ` if (typeof ${name} === 'function') window.${name} = ${name};`
251
- ).join('\n')
252
-
253
- return `// Register functions on window for event handlers\n${registrations}`
254
- }
255
-
256
- /**
257
- * Generate hydrate function that mounts the DOM with reactivity
258
- */
259
- function generateHydrateFunction(): string {
260
- return `function hydrate(root, state) {
261
- if (!root) {
262
- // SSR fallback - return initial HTML string
263
- console.warn('[Zenith] hydrate called without root element - SSR mode');
264
- return '';
265
- }
266
-
267
- // Clear root
268
- root.innerHTML = '';
269
-
270
- // Render template
271
- const dom = renderDynamicPage(state);
272
-
273
- // Append to root
274
- if (dom instanceof DocumentFragment) {
275
- root.appendChild(dom);
276
- } else if (dom instanceof Node) {
277
- root.appendChild(dom);
278
- }
279
-
280
- // Bind event handlers
281
- bindEventHandlers(root, state);
282
-
283
- // Set up reactive updates (if state is reactive)
284
- setupReactiveUpdates(root, state);
285
-
286
- return root;
287
- }
288
-
289
- function bindEventHandlers(root, state) {
290
- // Find all elements with data-zen-* event attributes
291
- const eventTypes = ['click', 'change', 'input', 'submit', 'focus', 'blur'];
292
-
293
- for (const eventType of eventTypes) {
294
- const elements = root.querySelectorAll(\`[data-zen-\${eventType}]\`);
295
- for (const el of elements) {
296
- const handlerName = el.getAttribute(\`data-zen-\${eventType}\`);
297
- if (handlerName && typeof window[handlerName] === 'function') {
298
- el.addEventListener(eventType, (e) => {
299
- window[handlerName](e, el);
300
- });
301
- }
302
- }
303
- }
304
- }
305
-
306
- function setupReactiveUpdates(root, state) {
307
- // For now, reactive updates are handled by the existing binding system
308
- // This is a placeholder for future reactive DOM updates
309
- // The existing runtime handles reactivity via state property setters
310
- }`
311
- }
312
-
313
- /**
314
- * Generate style injection code
315
- */
316
- function generateStyleInjection(styles: Array<{ raw: string }>): string {
317
- if (styles.length === 0) {
318
- return ''
319
- }
320
-
321
- const styleBlocks = styles.map((style, index) => {
322
- const escapedStyle = style.raw.replace(/`/g, '\\`').replace(/\$/g, '\\$')
323
- return `
324
- const style${index} = document.createElement('style');
325
- style${index}.textContent = \`${escapedStyle}\`;
326
- document.head.appendChild(style${index});`
327
- }).join('')
328
-
329
- return `function injectStyles() {${styleBlocks}
330
- }`
331
- }
332
-
333
- /**
334
- * Generate state initialization code
335
- * In Phase 9: Also handles props passing
336
- */
337
- function generateStateInitialization(stateDeclarations: Map<string, string>, propDeclarations: string[]): string {
338
- const stateInit = Array.from(stateDeclarations.entries()).map(([name, value]) => {
339
- return `
340
- // Initialize state: ${name}
341
- if (typeof state.${name} === 'undefined') {
342
- state.${name} = ${value};
343
- }`
344
- }).join('')
345
-
346
- const legacyPropInit = propDeclarations.includes('props') ? `
347
- // Initialize props object (legacy)
348
- if (typeof window.__ZEN_PROPS__ !== 'undefined') {
349
- state.props = window.__ZEN_PROPS__;
350
- }` : ''
351
-
352
- const individualPropInit = propDeclarations.filter(p => p !== 'props').map(prop => `
353
- // Initialize prop: ${prop}
354
- if (typeof state.${prop} === 'undefined' && typeof window.__ZEN_PROPS__ !== 'undefined' && typeof window.__ZEN_PROPS__.${prop} !== 'undefined') {
355
- state.${prop} = window.__ZEN_PROPS__.${prop};
356
- }`).join('')
357
-
358
- return `function initializeState(state) {${stateInit}${legacyPropInit}${individualPropInit}
359
- }`
360
- }
361
-
362
- // Note: transformScript is now handled by transformStateDeclarations in legacy/parse.ts
363
-
@@ -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
- }