@zenithbuild/core 1.2.2 → 1.2.3

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 (83) 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 +93 -73
  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 +1 -20118
  23. package/dist/zen-dev.js +1 -20118
  24. package/dist/zen-preview.js +1 -20118
  25. package/dist/zenith.js +1 -20118
  26. package/package.json +11 -20
  27. package/compiler/README.md +0 -380
  28. package/compiler/build-analyzer.ts +0 -122
  29. package/compiler/css/index.ts +0 -317
  30. package/compiler/discovery/componentDiscovery.ts +0 -242
  31. package/compiler/discovery/layouts.ts +0 -70
  32. package/compiler/errors/compilerError.ts +0 -56
  33. package/compiler/finalize/finalizeOutput.ts +0 -192
  34. package/compiler/finalize/generateFinalBundle.ts +0 -82
  35. package/compiler/index.ts +0 -83
  36. package/compiler/ir/types.ts +0 -174
  37. package/compiler/output/types.ts +0 -48
  38. package/compiler/parse/detectMapExpressions.ts +0 -102
  39. package/compiler/parse/importTypes.ts +0 -78
  40. package/compiler/parse/parseImports.ts +0 -309
  41. package/compiler/parse/parseScript.ts +0 -46
  42. package/compiler/parse/parseTemplate.ts +0 -628
  43. package/compiler/parse/parseZenFile.ts +0 -66
  44. package/compiler/parse/scriptAnalysis.ts +0 -91
  45. package/compiler/parse/trackLoopContext.ts +0 -82
  46. package/compiler/runtime/dataExposure.ts +0 -332
  47. package/compiler/runtime/generateDOM.ts +0 -255
  48. package/compiler/runtime/generateHydrationBundle.ts +0 -407
  49. package/compiler/runtime/hydration.ts +0 -309
  50. package/compiler/runtime/navigation.ts +0 -432
  51. package/compiler/runtime/thinRuntime.ts +0 -160
  52. package/compiler/runtime/transformIR.ts +0 -406
  53. package/compiler/runtime/wrapExpression.ts +0 -114
  54. package/compiler/runtime/wrapExpressionWithLoop.ts +0 -97
  55. package/compiler/spa-build.ts +0 -917
  56. package/compiler/ssg-build.ts +0 -486
  57. package/compiler/test/component-stacking.test.ts +0 -365
  58. package/compiler/test/map-lowering.test.ts +0 -130
  59. package/compiler/test/validate-test.ts +0 -104
  60. package/compiler/transform/classifyExpression.ts +0 -444
  61. package/compiler/transform/componentResolver.ts +0 -350
  62. package/compiler/transform/componentScriptTransformer.ts +0 -303
  63. package/compiler/transform/expressionTransformer.ts +0 -385
  64. package/compiler/transform/fragmentLowering.ts +0 -819
  65. package/compiler/transform/generateBindings.ts +0 -68
  66. package/compiler/transform/generateHTML.ts +0 -28
  67. package/compiler/transform/layoutProcessor.ts +0 -132
  68. package/compiler/transform/slotResolver.ts +0 -292
  69. package/compiler/transform/transformNode.ts +0 -314
  70. package/compiler/transform/transformTemplate.ts +0 -38
  71. package/compiler/validate/invariants.ts +0 -292
  72. package/compiler/validate/validateExpressions.ts +0 -168
  73. package/core/config/index.ts +0 -18
  74. package/core/config/loader.ts +0 -69
  75. package/core/config/types.ts +0 -119
  76. package/core/plugins/bridge.ts +0 -193
  77. package/core/plugins/index.ts +0 -7
  78. package/core/plugins/registry.ts +0 -126
  79. package/dist/cli.js +0 -11675
  80. package/runtime/build.ts +0 -17
  81. package/runtime/bundle-generator.ts +0 -1266
  82. package/runtime/client-runtime.ts +0 -891
  83. package/runtime/serve.ts +0 -93
@@ -1,91 +0,0 @@
1
- /**
2
- * Script Analysis Utilities
3
- *
4
- * Extracts state and prop declarations from <script> blocks
5
- */
6
-
7
- export interface StateInfo {
8
- name: string
9
- value: string
10
- }
11
-
12
- /**
13
- * Extract state declarations: state name = value
14
- */
15
- export function extractStateDeclarations(script: string): Map<string, string> {
16
- const states = new Map<string, string>()
17
- const statePattern = /state\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=\s*([^;]+?)(?:\s*;|\s*$)/gm
18
- let match
19
-
20
- while ((match = statePattern.exec(script)) !== null) {
21
- if (match[1] && match[2]) {
22
- states.set(match[1], match[2].trim())
23
- }
24
- }
25
-
26
- return states
27
- }
28
-
29
- /**
30
- * Extract prop declarations: export let props: Props;
31
- */
32
- export function extractProps(script: string): string[] {
33
- const props: string[] = []
34
- const propPattern = /export\s+let\s+props(?:\s*:\s*([^;]+))?[ \t]*;?/g
35
- let match
36
-
37
- while ((match = propPattern.exec(script)) !== null) {
38
- if (!props.includes('props')) {
39
- props.push('props')
40
- }
41
- }
42
-
43
- return props
44
- }
45
-
46
- /**
47
- * Transform script by removing state and prop declarations
48
- * Also strips .zen imports (resolved at compile time) and other compile-time-only imports
49
- */
50
- export function transformStateDeclarations(script: string): string {
51
- let transformed = script
52
-
53
- // Remove state declarations (state count = 0)
54
- transformed = transformed.replace(/state\s+([a-zA-Z_$][a-zA-Z0-9_$]*)[ \t]*=[ \t]*([^;]+?)(?:[ \t]*;|\s*$)/gm, '')
55
-
56
- // Remove export let props (legacy)
57
- transformed = transformed.replace(/export\s+let\s+props(?:\s*:\s*([^;]+))?\s*;?[ \t]*/g, '')
58
-
59
- // Remove type/interface Props (carefully handling comments)
60
- // We search for the start of the word 'type' or 'interface' and match until the closing brace
61
- transformed = transformed.replace(/(?:type|interface)\s+Props\s*=?\s*\{[^}]*(?:\{[^}]*\}[^}]*)*\}[ \t]*;?/gs, '')
62
-
63
- // Remove zenith/runtime imports
64
- transformed = transformed.replace(/import\s+{[^}]+}\s+from\s+['"]zenith\/runtime['"]\s*;?[ \t]*/g, '')
65
-
66
- // Remove .zen file imports (resolved at compile time)
67
- // Matches: import Name from '.../file.zen'; or import Name from '.../file.zen'
68
- transformed = transformed.replace(/import\s+\w+\s+from\s+['"][^'"]*\.zen['"];?\s*/g, '')
69
-
70
- // Remove relative imports with destructuring (components are inlined)
71
- transformed = transformed.replace(/import\s+{[^}]*}\s+from\s+['"][^'"]+\.zen['"];?\s*/g, '')
72
-
73
- // Transform zenith:content imports to global lookups
74
- transformed = transformed.replace(
75
- /import\s*{\s*([^}]+)\s*}\s*from\s*['"]zenith:content['"]\s*;?/g,
76
- (_, imports) => `const { ${imports.trim()} } = window.__zenith;`
77
- )
78
-
79
- return transformed.trim()
80
- }
81
-
82
- /**
83
- * Inject props into a setup script as top-level variables
84
- */
85
- export function injectPropsIntoSetup(script: string, props: Record<string, any>): string {
86
- const propDeclarations = Object.entries(props)
87
- .map(([key, value]) => `const ${key} = ${typeof value === 'string' ? `'${value}'` : JSON.stringify(value)};`)
88
- .join('\n')
89
-
90
- return `${propDeclarations}\n\n${script}`
91
- }
@@ -1,82 +0,0 @@
1
- /**
2
- * Loop Context Tracking
3
- *
4
- * Phase 7: Utilities for tracking and propagating loop context through the parse tree
5
- */
6
-
7
- import type { LoopContext, ExpressionIR } from '../ir/types'
8
- import { detectMapExpression, referencesLoopVariable } from './detectMapExpressions'
9
-
10
- /**
11
- * Check if an expression should have loop context attached
12
- * Returns the loop context if the expression references loop variables
13
- */
14
- export function shouldAttachLoopContext(
15
- expr: ExpressionIR,
16
- parentLoopContext?: LoopContext
17
- ): LoopContext | undefined {
18
- if (!parentLoopContext) {
19
- return undefined
20
- }
21
-
22
- // Check if this expression references any loop variables
23
- if (referencesLoopVariable(expr.code, parentLoopContext.variables)) {
24
- return parentLoopContext
25
- }
26
-
27
- return undefined
28
- }
29
-
30
- /**
31
- * Merge loop contexts for nested loops
32
- * Inner loops inherit outer loop variables
33
- */
34
- export function mergeLoopContext(
35
- outer?: LoopContext,
36
- inner?: LoopContext
37
- ): LoopContext | undefined {
38
- if (!inner) {
39
- return outer
40
- }
41
-
42
- if (!outer) {
43
- return inner
44
- }
45
-
46
- // Merge variables: outer variables come first, then inner
47
- // This allows expressions to reference both outer and inner loop variables
48
- return {
49
- variables: [...outer.variables, ...inner.variables],
50
- mapSource: inner.mapSource || outer.mapSource
51
- }
52
- }
53
-
54
- /**
55
- * Detect if an expression is a map expression and extract its loop context
56
- */
57
- export function extractLoopContextFromExpression(expr: ExpressionIR): LoopContext | undefined {
58
- const mapInfo = detectMapExpression(expr)
59
-
60
- if (!mapInfo.isMap) {
61
- return undefined
62
- }
63
-
64
- // extractLoopVariables expects a MapExpressionInfo, not a string
65
- const variables: string[] = []
66
- if (mapInfo.itemVariable) {
67
- variables.push(mapInfo.itemVariable)
68
- }
69
- if (mapInfo.indexVariable) {
70
- variables.push(mapInfo.indexVariable)
71
- }
72
-
73
- if (variables.length === 0) {
74
- return undefined
75
- }
76
-
77
- return {
78
- variables,
79
- mapSource: mapInfo.arraySource
80
- }
81
- }
82
-
@@ -1,332 +0,0 @@
1
- /**
2
- * Explicit Data Exposure Analysis
3
- *
4
- * Phase 6: Analyzes expressions to detect data dependencies and ensure
5
- * all data references are explicit (loader, props, stores) rather than implicit globals
6
- */
7
-
8
- import type { ExpressionIR } from '../ir/types'
9
- import { CompilerError } from '../errors/compilerError'
10
- import { transformExpressionJSX } from '../transform/expressionTransformer'
11
-
12
- /**
13
- * Data dependency information for an expression
14
- */
15
- export interface ExpressionDataDependencies {
16
- expressionId: string
17
- usesLoaderData: boolean
18
- usesProps: boolean
19
- usesStores: boolean
20
- usesState: boolean
21
- loaderProperties: string[] // e.g., ['user', 'user.name']
22
- propNames: string[] // e.g., ['title', 'showWelcome']
23
- storeNames: string[] // e.g., ['cart', 'notifications']
24
- stateProperties: string[] // e.g., ['count', 'isLoading']
25
- }
26
-
27
- /**
28
- * Analyze an expression to detect its data dependencies
29
- *
30
- * This is a simple heuristic-based analyzer that looks for patterns like:
31
- * - user.name, user.email → loader data
32
- * - props.title, props.showWelcome → props
33
- * - stores.cart, stores.notifications → stores
34
- * - count, isLoading → state (top-level properties)
35
- */
36
- export function analyzeExpressionDependencies(
37
- expr: ExpressionIR,
38
- declaredLoaderProps: string[] = [],
39
- declaredProps: string[] = [],
40
- declaredStores: string[] = []
41
- ): ExpressionDataDependencies {
42
- const { id, code } = expr
43
-
44
- const dependencies: ExpressionDataDependencies = {
45
- expressionId: id,
46
- usesLoaderData: false,
47
- usesProps: false,
48
- usesStores: false,
49
- usesState: false,
50
- loaderProperties: [],
51
- propNames: [],
52
- storeNames: [],
53
- stateProperties: []
54
- }
55
-
56
- // Simple pattern matching (for Phase 6 - can be enhanced with proper AST parsing later)
57
-
58
- // Check for loader data references (loaderData.property or direct property access)
59
- // We assume properties not starting with props/stores/state are loader data
60
- const loaderPattern = /\b(loaderData\.(\w+(?:\.\w+)*)|(?<!props\.|stores\.|state\.)(\w+)\.(\w+))/g
61
- let match
62
-
63
- // Check for explicit loaderData references
64
- if (/loaderData\./.test(code)) {
65
- dependencies.usesLoaderData = true
66
- while ((match = loaderPattern.exec(code)) !== null) {
67
- if (match[1]?.startsWith('loaderData.')) {
68
- const propPath = match[1].replace('loaderData.', '')
69
- if (!dependencies.loaderProperties.includes(propPath)) {
70
- dependencies.loaderProperties.push(propPath)
71
- }
72
- }
73
- }
74
- }
75
-
76
- // Check for props references
77
- const propsPattern = /\bprops\.(\w+)(?:\.(\w+))*/g
78
- if (/props\./.test(code)) {
79
- dependencies.usesProps = true
80
- while ((match = propsPattern.exec(code)) !== null) {
81
- const propName = match[1]
82
- if (propName && !dependencies.propNames.includes(propName)) {
83
- dependencies.propNames.push(propName)
84
- }
85
- }
86
- }
87
-
88
- // Check for stores references
89
- const storesPattern = /\bstores\.(\w+)(?:\.(\w+))*/g
90
- if (/stores\./.test(code)) {
91
- dependencies.usesStores = true
92
- while ((match = storesPattern.exec(code)) !== null) {
93
- const storeName = match[1]
94
- if (storeName && !dependencies.storeNames.includes(storeName)) {
95
- dependencies.storeNames.push(storeName)
96
- }
97
- }
98
- }
99
-
100
- // Check for state references (top-level properties)
101
- // Simple identifiers that aren't part of props/stores/loaderData paths
102
- const identifierPattern = /\b([a-zA-Z_$][a-zA-Z0-9_$]*)\b/g
103
- const reserved = ['props', 'stores', 'loaderData', 'state', 'true', 'false', 'null', 'undefined', 'this', 'window']
104
-
105
- const identifiers = new Set<string>()
106
- while ((match = identifierPattern.exec(code)) !== null) {
107
- const ident = match[1]
108
- if (ident && !reserved.includes(ident) && !ident.includes('.')) {
109
- identifiers.add(ident)
110
- }
111
- }
112
-
113
- // If we have identifiers, check if they are props or state
114
- if (identifiers.size > 0) {
115
- const propIdents: string[] = []
116
- const stateIdents: string[] = []
117
-
118
- for (const ident of identifiers) {
119
- if (declaredProps.includes(ident)) {
120
- propIdents.push(ident)
121
- } else {
122
- stateIdents.push(ident)
123
- }
124
- }
125
-
126
- if (propIdents.length > 0) {
127
- dependencies.usesProps = true
128
- dependencies.propNames = [...new Set([...dependencies.propNames, ...propIdents])]
129
- }
130
-
131
- if (stateIdents.length > 0) {
132
- dependencies.usesState = true
133
- dependencies.stateProperties = Array.from(new Set([...dependencies.stateProperties, ...stateIdents]))
134
- }
135
- }
136
-
137
- return dependencies
138
- }
139
-
140
- /**
141
- * Validate that all referenced data exists
142
- */
143
- export function validateDataDependencies(
144
- dependencies: ExpressionDataDependencies,
145
- filePath: string,
146
- declaredLoaderProps: string[] = [],
147
- declaredProps: string[] = [],
148
- declaredStores: string[] = []
149
- ): void {
150
- const errors: CompilerError[] = []
151
-
152
- // Validate loader data properties
153
- if (dependencies.usesLoaderData && dependencies.loaderProperties.length > 0) {
154
- // For Phase 6, we'll allow any loader property (can be enhanced with type checking later)
155
- // Just warn if property path is suspicious
156
- for (const prop of dependencies.loaderProperties) {
157
- if (!/^[a-zA-Z_$][a-zA-Z0-9_$.]*$/.test(prop)) {
158
- errors.push(new CompilerError(
159
- `Invalid loader data property reference: ${prop}`,
160
- filePath,
161
- 0,
162
- 0
163
- ))
164
- }
165
- }
166
- }
167
-
168
- // Validate props
169
- if (dependencies.usesProps && dependencies.propNames.length > 0) {
170
- for (const propName of dependencies.propNames) {
171
- if (declaredProps.length > 0 && !declaredProps.includes(propName)) {
172
- // This is a warning, not an error - props might be passed at runtime
173
- console.warn(`[Zenith] Prop "${propName}" referenced but not declared in component`)
174
- }
175
- }
176
- }
177
-
178
- // Validate stores
179
- if (dependencies.usesStores && dependencies.storeNames.length > 0) {
180
- for (const storeName of dependencies.storeNames) {
181
- if (declaredStores.length > 0 && !declaredStores.includes(storeName)) {
182
- errors.push(new CompilerError(
183
- `Store "${storeName}" referenced but not imported or declared`,
184
- filePath,
185
- 0,
186
- 0
187
- ))
188
- }
189
- }
190
- }
191
-
192
- if (errors.length > 0) {
193
- throw errors[0] // Throw first error (can be enhanced to collect all)
194
- }
195
- }
196
-
197
- /**
198
- * Transform expression code to use explicit data arguments
199
- *
200
- * Converts patterns like:
201
- * - user.name → loaderData.user.name
202
- * - title → props.title (if declared as prop)
203
- * - cart.items → stores.cart.items
204
- */
205
- export function transformExpressionCode(
206
- code: string,
207
- dependencies: ExpressionDataDependencies,
208
- declaredProps: string[] = []
209
- ): string {
210
- let transformed = code
211
-
212
- // For Phase 6, we keep the code as-is but ensure expressions
213
- // receive the right arguments. The actual transformation happens
214
- // in the expression wrapper function signature.
215
-
216
- // However, if the code references properties directly (without loaderData/props/stores prefix),
217
- // we need to assume they're state properties (backwards compatibility)
218
-
219
- return transformed
220
- }
221
-
222
- /**
223
- * Generate expression wrapper with explicit data arguments
224
- */
225
- export function generateExplicitExpressionWrapper(
226
- expr: ExpressionIR,
227
- dependencies: ExpressionDataDependencies
228
- ): string {
229
- const { id, code } = expr
230
-
231
- // Build function signature based on dependencies
232
- const params: string[] = ['state']
233
-
234
- if (dependencies.usesLoaderData) {
235
- params.push('loaderData')
236
- }
237
- if (dependencies.usesProps) {
238
- params.push('props')
239
- }
240
- if (dependencies.usesStores) {
241
- params.push('stores')
242
- }
243
-
244
- const paramList = params.join(', ')
245
-
246
- // Build evaluation context
247
- const contextParts: string[] = []
248
-
249
- if (dependencies.usesLoaderData) {
250
- contextParts.push('loaderData')
251
- }
252
- if (dependencies.usesProps) {
253
- contextParts.push('props')
254
- }
255
- if (dependencies.usesStores) {
256
- contextParts.push('stores')
257
- }
258
- if (dependencies.usesState) {
259
- contextParts.push('state')
260
- }
261
-
262
- // Create merged context code
263
- const contextCode = contextParts.length > 0
264
- ? `var __ctx = Object.assign({}, ${contextParts.join(', ')});`
265
- : 'var __ctx = state || {};'
266
-
267
- // Escape the code for use in a single-line comment (replace newlines with spaces)
268
- const commentCode = code.replace(/[\r\n]+/g, ' ').replace(/\s+/g, ' ').substring(0, 100)
269
-
270
- // JSON.stringify the code for error messages (properly escapes quotes, newlines, etc.)
271
- const jsonEscapedCode = JSON.stringify(code)
272
-
273
- // Transform JSX
274
- const transformedCode = transformExpressionJSX(code)
275
-
276
- // Properly escape the transformed code for use inside a string
277
- const escapedTransformedCode = transformedCode
278
- .replace(/\\/g, '\\\\')
279
- .replace(/'/g, "\\'")
280
- .replace(/\n/g, '\\n')
281
- .replace(/\r/g, '\\r')
282
-
283
- return `
284
- // Expression: ${commentCode}${code.length > 100 ? '...' : ''}
285
- // Dependencies: ${JSON.stringify({
286
- loaderData: dependencies.usesLoaderData,
287
- props: dependencies.usesProps,
288
- stores: dependencies.usesStores,
289
- state: dependencies.usesState
290
- })}
291
- const ${id} = (function() {
292
- // Create the evaluator function once (with 'with' support in sloppy mode)
293
- var evalFn = new Function('__ctx',
294
- 'with (__ctx) { return (' + '${escapedTransformedCode}' + '); }'
295
- );
296
-
297
- return function(${paramList}) {
298
- try {
299
- // Merge window globals with context (for script-level variables)
300
- var __baseCtx = Object.assign({}, window);
301
- ${contextCode.replace('var __ctx', 'var __ctx').replace('= Object.assign({},', '= Object.assign(__baseCtx,')}
302
- return evalFn(__ctx);
303
- } catch (e) {
304
- console.warn('[Zenith] Expression evaluation error:', ${jsonEscapedCode}, e);
305
- return undefined;
306
- }
307
- };
308
- })();`
309
- }
310
-
311
- /**
312
- * Analyze all expressions in a template
313
- */
314
- export function analyzeAllExpressions(
315
- expressions: ExpressionIR[],
316
- filePath: string,
317
- declaredLoaderProps: string[] = [],
318
- declaredProps: string[] = [],
319
- declaredStores: string[] = []
320
- ): ExpressionDataDependencies[] {
321
- const dependencies = expressions.map(expr =>
322
- analyzeExpressionDependencies(expr, declaredLoaderProps, declaredProps, declaredStores)
323
- )
324
-
325
- // Validate all dependencies
326
- for (const dep of dependencies) {
327
- validateDataDependencies(dep, filePath, declaredLoaderProps, declaredProps, declaredStores)
328
- }
329
-
330
- return dependencies
331
- }
332
-