@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,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
- }