@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,444 +0,0 @@
1
- /**
2
- * Expression Classification
3
- *
4
- * Analyzes expression code to determine output type for structural lowering.
5
- *
6
- * JSX expressions are allowed if — and only if — the compiler can statically
7
- * enumerate all possible DOM shapes and lower them at compile time.
8
- */
9
-
10
- /**
11
- * Expression output types
12
- *
13
- * - primitive: string, number, boolean → text binding
14
- * - conditional: cond ? <A /> : <B /> → ConditionalFragmentNode
15
- * - optional: cond && <A /> → OptionalFragmentNode
16
- * - loop: arr.map(i => <JSX />) → LoopFragmentNode
17
- * - fragment: <A /> or <><A /><B /></> → inline fragment
18
- * - unknown: cannot be statically determined → COMPILE ERROR
19
- */
20
- export type ExpressionOutputType =
21
- | 'primitive'
22
- | 'conditional'
23
- | 'optional'
24
- | 'loop'
25
- | 'fragment'
26
- | 'unknown'
27
-
28
- /**
29
- * Classification result with extracted metadata
30
- */
31
- export interface ExpressionClassification {
32
- type: ExpressionOutputType
33
- // For conditional expressions
34
- condition?: string
35
- consequent?: string
36
- alternate?: string
37
- // For optional expressions
38
- optionalCondition?: string
39
- optionalFragment?: string
40
- // For loop expressions
41
- loopSource?: string
42
- loopItemVar?: string
43
- loopIndexVar?: string
44
- loopBody?: string
45
- // For inline fragments
46
- fragmentCode?: string
47
- }
48
-
49
- /**
50
- * Check if code contains JSX-like tags
51
- */
52
- function containsJSX(code: string): boolean {
53
- // Match opening JSX tags: <Tag or <tag
54
- return /<[a-zA-Z]/.test(code)
55
- }
56
-
57
- /**
58
- * Check if expression starts with a JSX element
59
- */
60
- function startsWithJSX(code: string): boolean {
61
- const trimmed = code.trim()
62
- return /^<[a-zA-Z]/.test(trimmed) || /^<>/.test(trimmed)
63
- }
64
-
65
- /**
66
- * Classify expression output type
67
- *
68
- * @param code - The expression code to classify
69
- * @returns Classification result with metadata
70
- */
71
- export function classifyExpression(code: string): ExpressionClassification {
72
- const trimmed = code.trim()
73
-
74
- // Check for .map() expressions with JSX body
75
- const mapMatch = parseMapExpression(trimmed)
76
- if (mapMatch) {
77
- return {
78
- type: 'loop',
79
- loopSource: mapMatch.source,
80
- loopItemVar: mapMatch.itemVar,
81
- loopIndexVar: mapMatch.indexVar,
82
- loopBody: mapMatch.body
83
- }
84
- }
85
-
86
- // Check for ternary with JSX branches: condition ? <A /> : <B />
87
- const ternaryMatch = parseTernaryExpression(trimmed)
88
- if (ternaryMatch && (containsJSX(ternaryMatch.consequent) || containsJSX(ternaryMatch.alternate))) {
89
- return {
90
- type: 'conditional',
91
- condition: ternaryMatch.condition,
92
- consequent: ternaryMatch.consequent,
93
- alternate: ternaryMatch.alternate
94
- }
95
- }
96
-
97
- // Check for logical AND with JSX: condition && <A />
98
- const logicalAndMatch = parseLogicalAndExpression(trimmed)
99
- if (logicalAndMatch && containsJSX(logicalAndMatch.fragment)) {
100
- return {
101
- type: 'optional',
102
- optionalCondition: logicalAndMatch.condition,
103
- optionalFragment: logicalAndMatch.fragment
104
- }
105
- }
106
-
107
- // All other expressions (including inline JSX like {<span>text</span>})
108
- // are treated as primitive and handled by the existing expression transformer
109
- // which converts JSX to __zenith.h() calls at runtime
110
- return { type: 'primitive' }
111
- }
112
-
113
- /**
114
- * Parse .map() expression
115
- *
116
- * Matches:
117
- * - source.map(item => body)
118
- * - source.map((item, index) => body)
119
- */
120
- function parseMapExpression(code: string): {
121
- source: string
122
- itemVar: string
123
- indexVar?: string
124
- body: string
125
- } | null {
126
- // Pattern: source.map(item => body)
127
- // Pattern: source.map((item) => body)
128
- // Pattern: source.map((item, index) => body)
129
-
130
- // Find .map(
131
- const mapIndex = code.indexOf('.map(')
132
- if (mapIndex === -1) return null
133
-
134
- const source = code.slice(0, mapIndex).trim()
135
- if (!source) return null
136
-
137
- // Find the arrow function parameters
138
- let afterMap = code.slice(mapIndex + 5) // after ".map("
139
-
140
- // Skip whitespace
141
- afterMap = afterMap.trimStart()
142
-
143
- // Check for parenthesized params: (item) or (item, index)
144
- let itemVar: string
145
- let indexVar: string | undefined
146
- let bodyStart: number
147
-
148
- if (afterMap.startsWith('(')) {
149
- // Find closing paren
150
- const closeParenIndex = findBalancedParen(afterMap, 0)
151
- if (closeParenIndex === -1) return null
152
-
153
- const paramsStr = afterMap.slice(1, closeParenIndex)
154
- const params = paramsStr.split(',').map(p => p.trim())
155
-
156
- itemVar = params[0] || ''
157
- indexVar = params[1]
158
-
159
- // Find arrow
160
- const afterParams = afterMap.slice(closeParenIndex + 1).trimStart()
161
- if (!afterParams.startsWith('=>')) return null
162
-
163
- bodyStart = mapIndex + 5 + (afterMap.length - afterParams.length) + 2
164
- } else {
165
- // Simple param: item => body
166
- const arrowIndex = afterMap.indexOf('=>')
167
- if (arrowIndex === -1) return null
168
-
169
- itemVar = afterMap.slice(0, arrowIndex).trim()
170
- bodyStart = mapIndex + 5 + arrowIndex + 2
171
- }
172
-
173
- if (!itemVar) return null
174
-
175
- // Extract body (everything after => until the closing paren of .map())
176
- let body = code.slice(bodyStart).trim()
177
-
178
- // Remove trailing ) from .map()
179
- if (body.endsWith(')')) {
180
- body = body.slice(0, -1).trim()
181
- }
182
-
183
- // Check if body contains JSX
184
- if (!containsJSX(body)) return null
185
-
186
- return { source, itemVar, indexVar, body }
187
- }
188
-
189
- /**
190
- * Find matching closing parenthesis
191
- */
192
- function findBalancedParen(code: string, startIndex: number): number {
193
- if (code[startIndex] !== '(') return -1
194
-
195
- let depth = 1
196
- let i = startIndex + 1
197
-
198
- while (i < code.length && depth > 0) {
199
- if (code[i] === '(') depth++
200
- else if (code[i] === ')') depth--
201
- i++
202
- }
203
-
204
- return depth === 0 ? i - 1 : -1
205
- }
206
-
207
- /**
208
- * Parse ternary expression
209
- *
210
- * Matches: condition ? consequent : alternate
211
- */
212
- function parseTernaryExpression(code: string): {
213
- condition: string
214
- consequent: string
215
- alternate: string
216
- } | null {
217
- // Find the ? that's not inside JSX or strings
218
- const questionIndex = findTernaryOperator(code)
219
- if (questionIndex === -1) return null
220
-
221
- const condition = code.slice(0, questionIndex).trim()
222
- const afterQuestion = code.slice(questionIndex + 1)
223
-
224
- // Find the : that matches this ternary
225
- const colonIndex = findTernaryColon(afterQuestion)
226
- if (colonIndex === -1) return null
227
-
228
- const consequent = afterQuestion.slice(0, colonIndex).trim()
229
- const alternate = afterQuestion.slice(colonIndex + 1).trim()
230
-
231
- if (!condition || !consequent || !alternate) return null
232
-
233
- return { condition, consequent, alternate }
234
- }
235
-
236
- /**
237
- * Find ternary ? operator (not inside JSX or nested ternaries)
238
- */
239
- function findTernaryOperator(code: string): number {
240
- let depth = 0
241
- let inString = false
242
- let stringChar = ''
243
- let inTemplate = false
244
- let jsxDepth = 0
245
-
246
- for (let i = 0; i < code.length; i++) {
247
- const char = code[i]
248
- const prevChar = i > 0 ? code[i - 1] : ''
249
-
250
- // Handle escape
251
- if (prevChar === '\\') continue
252
-
253
- // Handle strings
254
- if (!inString && !inTemplate && (char === '"' || char === "'")) {
255
- inString = true
256
- stringChar = char
257
- continue
258
- }
259
- if (inString && char === stringChar) {
260
- inString = false
261
- continue
262
- }
263
-
264
- // Handle template literals
265
- if (!inString && !inTemplate && char === '`') {
266
- inTemplate = true
267
- continue
268
- }
269
- if (inTemplate && char === '`') {
270
- inTemplate = false
271
- continue
272
- }
273
-
274
- if (inString || inTemplate) continue
275
-
276
- // Track JSX depth
277
- if (char === '<' && /[a-zA-Z>]/.test(code[i + 1] || '')) {
278
- jsxDepth++
279
- }
280
- if (char === '>' && prevChar === '/') {
281
- jsxDepth = Math.max(0, jsxDepth - 1)
282
- }
283
- if (char === '/' && code[i + 1] === '>') {
284
- // self-closing tag, depth handled when we see >
285
- }
286
- if (char === '<' && code[i + 1] === '/') {
287
- // closing tag coming
288
- }
289
- if (char === '>' && jsxDepth > 0 && prevChar !== '/' && code.slice(0, i).includes('</')) {
290
- jsxDepth = Math.max(0, jsxDepth - 1)
291
- }
292
-
293
- // Track parens
294
- if (char === '(' || char === '{' || char === '[') depth++
295
- if (char === ')' || char === '}' || char === ']') depth--
296
-
297
- // Found ternary operator at top level
298
- if (char === '?' && depth === 0 && jsxDepth === 0) {
299
- return i
300
- }
301
- }
302
-
303
- return -1
304
- }
305
-
306
- /**
307
- * Find ternary : operator (matching the ?)
308
- */
309
- function findTernaryColon(code: string): number {
310
- let depth = 0
311
- let ternaryDepth = 0
312
- let inString = false
313
- let stringChar = ''
314
- let inTemplate = false
315
- let jsxDepth = 0
316
-
317
- for (let i = 0; i < code.length; i++) {
318
- const char = code[i]
319
- const prevChar = i > 0 ? code[i - 1] : ''
320
-
321
- // Handle escape
322
- if (prevChar === '\\') continue
323
-
324
- // Handle strings
325
- if (!inString && !inTemplate && (char === '"' || char === "'")) {
326
- inString = true
327
- stringChar = char
328
- continue
329
- }
330
- if (inString && char === stringChar) {
331
- inString = false
332
- continue
333
- }
334
-
335
- // Handle template literals
336
- if (!inString && !inTemplate && char === '`') {
337
- inTemplate = true
338
- continue
339
- }
340
- if (inTemplate && char === '`') {
341
- inTemplate = false
342
- continue
343
- }
344
-
345
- if (inString || inTemplate) continue
346
-
347
- // Track JSX depth (simplified)
348
- if (char === '<' && /[a-zA-Z>]/.test(code[i + 1] || '')) {
349
- jsxDepth++
350
- }
351
- if (char === '>' && (prevChar === '/' || jsxDepth > 0)) {
352
- jsxDepth = Math.max(0, jsxDepth - 1)
353
- }
354
-
355
- // Track parens
356
- if (char === '(' || char === '{' || char === '[') depth++
357
- if (char === ')' || char === '}' || char === ']') depth--
358
-
359
- // Track nested ternaries
360
- if (char === '?') ternaryDepth++
361
- if (char === ':' && ternaryDepth > 0) {
362
- ternaryDepth--
363
- continue
364
- }
365
-
366
- // Found matching colon at top level
367
- if (char === ':' && depth === 0 && ternaryDepth === 0 && jsxDepth === 0) {
368
- return i
369
- }
370
- }
371
-
372
- return -1
373
- }
374
-
375
- /**
376
- * Parse logical AND expression
377
- *
378
- * Matches: condition && fragment
379
- */
380
- function parseLogicalAndExpression(code: string): {
381
- condition: string
382
- fragment: string
383
- } | null {
384
- // Find && at top level
385
- let depth = 0
386
- let inString = false
387
- let stringChar = ''
388
- let inTemplate = false
389
-
390
- for (let i = 0; i < code.length - 1; i++) {
391
- const char = code[i]
392
- const nextChar = code[i + 1]
393
- const prevChar = i > 0 ? code[i - 1] : ''
394
-
395
- // Handle escape
396
- if (prevChar === '\\') continue
397
-
398
- // Handle strings
399
- if (!inString && !inTemplate && (char === '"' || char === "'")) {
400
- inString = true
401
- stringChar = char
402
- continue
403
- }
404
- if (inString && char === stringChar) {
405
- inString = false
406
- continue
407
- }
408
-
409
- // Handle template literals
410
- if (!inString && !inTemplate && char === '`') {
411
- inTemplate = true
412
- continue
413
- }
414
- if (inTemplate && char === '`') {
415
- inTemplate = false
416
- continue
417
- }
418
-
419
- if (inString || inTemplate) continue
420
-
421
- // Track parens
422
- if (char === '(' || char === '{' || char === '[') depth++
423
- if (char === ')' || char === '}' || char === ']') depth--
424
-
425
- // Found && at top level
426
- if (char === '&' && nextChar === '&' && depth === 0) {
427
- const condition = code.slice(0, i).trim()
428
- const fragment = code.slice(i + 2).trim()
429
-
430
- if (condition && fragment) {
431
- return { condition, fragment }
432
- }
433
- }
434
- }
435
-
436
- return null
437
- }
438
-
439
- /**
440
- * Check if an expression type requires structural lowering
441
- */
442
- export function requiresStructuralLowering(type: ExpressionOutputType): boolean {
443
- return type === 'conditional' || type === 'optional' || type === 'loop' || type === 'fragment'
444
- }