@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,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,317 +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 for 'with' statement
263
- const contextCode = contextParts.length > 0
264
- ? `const __ctx = Object.assign({}, ${contextParts.join(', ')});\n with (__ctx) {`
265
- : 'with (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
- return `
277
- // Expression: ${commentCode}${code.length > 100 ? '...' : ''}
278
- // Dependencies: ${JSON.stringify({
279
- loaderData: dependencies.usesLoaderData,
280
- props: dependencies.usesProps,
281
- stores: dependencies.usesStores,
282
- state: dependencies.usesState
283
- })}
284
- const ${id} = (${paramList}) => {
285
- try {
286
- ${contextCode}
287
- return ${transformedCode};
288
- }
289
- } catch (e) {
290
- console.warn('[Zenith] Expression evaluation error:', ${jsonEscapedCode}, e);
291
- return undefined;
292
- }
293
- };`
294
- }
295
-
296
- /**
297
- * Analyze all expressions in a template
298
- */
299
- export function analyzeAllExpressions(
300
- expressions: ExpressionIR[],
301
- filePath: string,
302
- declaredLoaderProps: string[] = [],
303
- declaredProps: string[] = [],
304
- declaredStores: string[] = []
305
- ): ExpressionDataDependencies[] {
306
- const dependencies = expressions.map(expr =>
307
- analyzeExpressionDependencies(expr, declaredLoaderProps, declaredProps, declaredStores)
308
- )
309
-
310
- // Validate all dependencies
311
- for (const dep of dependencies) {
312
- validateDataDependencies(dep, filePath, declaredLoaderProps, declaredProps, declaredStores)
313
- }
314
-
315
- return dependencies
316
- }
317
-