@zenithbuild/compiler 1.0.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 (145) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +30 -0
  3. package/dist/build-analyzer.d.ts +44 -0
  4. package/dist/build-analyzer.js +87 -0
  5. package/dist/bundler.d.ts +31 -0
  6. package/dist/bundler.js +86 -0
  7. package/dist/core/components/index.d.ts +9 -0
  8. package/dist/core/components/index.js +13 -0
  9. package/dist/core/config/index.d.ts +11 -0
  10. package/dist/core/config/index.js +10 -0
  11. package/dist/core/config/loader.d.ts +17 -0
  12. package/dist/core/config/loader.js +60 -0
  13. package/dist/core/config/types.d.ts +98 -0
  14. package/dist/core/config/types.js +32 -0
  15. package/dist/core/index.d.ts +7 -0
  16. package/dist/core/index.js +6 -0
  17. package/dist/core/lifecycle/index.d.ts +16 -0
  18. package/dist/core/lifecycle/index.js +19 -0
  19. package/dist/core/lifecycle/zen-mount.d.ts +66 -0
  20. package/dist/core/lifecycle/zen-mount.js +151 -0
  21. package/dist/core/lifecycle/zen-unmount.d.ts +54 -0
  22. package/dist/core/lifecycle/zen-unmount.js +76 -0
  23. package/dist/core/plugins/bridge.d.ts +116 -0
  24. package/dist/core/plugins/bridge.js +121 -0
  25. package/dist/core/plugins/index.d.ts +6 -0
  26. package/dist/core/plugins/index.js +6 -0
  27. package/dist/core/plugins/registry.d.ts +67 -0
  28. package/dist/core/plugins/registry.js +113 -0
  29. package/dist/core/reactivity/index.d.ts +30 -0
  30. package/dist/core/reactivity/index.js +33 -0
  31. package/dist/core/reactivity/tracking.d.ts +74 -0
  32. package/dist/core/reactivity/tracking.js +136 -0
  33. package/dist/core/reactivity/zen-batch.d.ts +45 -0
  34. package/dist/core/reactivity/zen-batch.js +54 -0
  35. package/dist/core/reactivity/zen-effect.d.ts +48 -0
  36. package/dist/core/reactivity/zen-effect.js +98 -0
  37. package/dist/core/reactivity/zen-memo.d.ts +43 -0
  38. package/dist/core/reactivity/zen-memo.js +100 -0
  39. package/dist/core/reactivity/zen-ref.d.ts +44 -0
  40. package/dist/core/reactivity/zen-ref.js +34 -0
  41. package/dist/core/reactivity/zen-signal.d.ts +48 -0
  42. package/dist/core/reactivity/zen-signal.js +84 -0
  43. package/dist/core/reactivity/zen-state.d.ts +35 -0
  44. package/dist/core/reactivity/zen-state.js +147 -0
  45. package/dist/core/reactivity/zen-untrack.d.ts +38 -0
  46. package/dist/core/reactivity/zen-untrack.js +41 -0
  47. package/dist/css/index.d.ts +73 -0
  48. package/dist/css/index.js +246 -0
  49. package/dist/discovery/componentDiscovery.d.ts +42 -0
  50. package/dist/discovery/componentDiscovery.js +56 -0
  51. package/dist/discovery/layouts.d.ts +13 -0
  52. package/dist/discovery/layouts.js +41 -0
  53. package/dist/errors/compilerError.d.ts +31 -0
  54. package/dist/errors/compilerError.js +51 -0
  55. package/dist/finalize/finalizeOutput.d.ts +32 -0
  56. package/dist/finalize/finalizeOutput.js +62 -0
  57. package/dist/finalize/generateFinalBundle.d.ts +24 -0
  58. package/dist/finalize/generateFinalBundle.js +68 -0
  59. package/dist/index.d.ts +36 -0
  60. package/dist/index.js +51 -0
  61. package/dist/ir/types.d.ts +181 -0
  62. package/dist/ir/types.js +8 -0
  63. package/dist/output/types.d.ts +30 -0
  64. package/dist/output/types.js +6 -0
  65. package/dist/parse/detectMapExpressions.d.ts +45 -0
  66. package/dist/parse/detectMapExpressions.js +77 -0
  67. package/dist/parse/parseScript.d.ts +8 -0
  68. package/dist/parse/parseScript.js +36 -0
  69. package/dist/parse/parseTemplate.d.ts +11 -0
  70. package/dist/parse/parseTemplate.js +487 -0
  71. package/dist/parse/parseZenFile.d.ts +11 -0
  72. package/dist/parse/parseZenFile.js +50 -0
  73. package/dist/parse/scriptAnalysis.d.ts +25 -0
  74. package/dist/parse/scriptAnalysis.js +60 -0
  75. package/dist/parse/trackLoopContext.d.ts +20 -0
  76. package/dist/parse/trackLoopContext.js +62 -0
  77. package/dist/parseZenFile.d.ts +10 -0
  78. package/dist/parseZenFile.js +55 -0
  79. package/dist/runtime/analyzeAndEmit.d.ts +20 -0
  80. package/dist/runtime/analyzeAndEmit.js +70 -0
  81. package/dist/runtime/build.d.ts +6 -0
  82. package/dist/runtime/build.js +13 -0
  83. package/dist/runtime/bundle-generator.d.ts +27 -0
  84. package/dist/runtime/bundle-generator.js +1263 -0
  85. package/dist/runtime/client-runtime.d.ts +41 -0
  86. package/dist/runtime/client-runtime.js +397 -0
  87. package/dist/runtime/dataExposure.d.ts +52 -0
  88. package/dist/runtime/dataExposure.js +227 -0
  89. package/dist/runtime/generateDOM.d.ts +21 -0
  90. package/dist/runtime/generateDOM.js +194 -0
  91. package/dist/runtime/generateHydrationBundle.d.ts +15 -0
  92. package/dist/runtime/generateHydrationBundle.js +399 -0
  93. package/dist/runtime/hydration.d.ts +53 -0
  94. package/dist/runtime/hydration.js +271 -0
  95. package/dist/runtime/navigation.d.ts +58 -0
  96. package/dist/runtime/navigation.js +372 -0
  97. package/dist/runtime/serve.d.ts +13 -0
  98. package/dist/runtime/serve.js +76 -0
  99. package/dist/runtime/thinRuntime.d.ts +23 -0
  100. package/dist/runtime/thinRuntime.js +158 -0
  101. package/dist/runtime/transformIR.d.ts +19 -0
  102. package/dist/runtime/transformIR.js +285 -0
  103. package/dist/runtime/wrapExpression.d.ts +24 -0
  104. package/dist/runtime/wrapExpression.js +76 -0
  105. package/dist/runtime/wrapExpressionWithLoop.d.ts +17 -0
  106. package/dist/runtime/wrapExpressionWithLoop.js +75 -0
  107. package/dist/spa-build.d.ts +26 -0
  108. package/dist/spa-build.js +866 -0
  109. package/dist/ssg-build.d.ts +32 -0
  110. package/dist/ssg-build.js +408 -0
  111. package/dist/test/analyze-emit.test.d.ts +1 -0
  112. package/dist/test/analyze-emit.test.js +88 -0
  113. package/dist/test/bundler-contract.test.d.ts +1 -0
  114. package/dist/test/bundler-contract.test.js +137 -0
  115. package/dist/test/compiler-authority.test.d.ts +1 -0
  116. package/dist/test/compiler-authority.test.js +90 -0
  117. package/dist/test/component-instance-test.d.ts +1 -0
  118. package/dist/test/component-instance-test.js +115 -0
  119. package/dist/test/error-native-bridge.test.d.ts +1 -0
  120. package/dist/test/error-native-bridge.test.js +51 -0
  121. package/dist/test/error-serialization.test.d.ts +1 -0
  122. package/dist/test/error-serialization.test.js +38 -0
  123. package/dist/test/macro-inlining.test.d.ts +1 -0
  124. package/dist/test/macro-inlining.test.js +178 -0
  125. package/dist/test/validate-test.d.ts +6 -0
  126. package/dist/test/validate-test.js +95 -0
  127. package/dist/transform/classifyExpression.d.ts +46 -0
  128. package/dist/transform/classifyExpression.js +354 -0
  129. package/dist/transform/componentResolver.d.ts +15 -0
  130. package/dist/transform/componentResolver.js +30 -0
  131. package/dist/transform/expressionTransformer.d.ts +19 -0
  132. package/dist/transform/expressionTransformer.js +333 -0
  133. package/dist/transform/fragmentLowering.d.ts +25 -0
  134. package/dist/transform/fragmentLowering.js +468 -0
  135. package/dist/transform/layoutProcessor.d.ts +5 -0
  136. package/dist/transform/layoutProcessor.js +34 -0
  137. package/dist/transform/transformTemplate.d.ts +11 -0
  138. package/dist/transform/transformTemplate.js +33 -0
  139. package/dist/validate/invariants.d.ts +23 -0
  140. package/dist/validate/invariants.js +55 -0
  141. package/native/compiler-native/compiler-native.node +0 -0
  142. package/native/compiler-native/index.d.ts +113 -0
  143. package/native/compiler-native/index.js +19 -0
  144. package/native/compiler-native/package.json +19 -0
  145. package/package.json +49 -0
@@ -0,0 +1,333 @@
1
+ /**
2
+ * Expression JSX Transformer
3
+ *
4
+ * Transforms JSX-like tags inside Zenith expressions into __zenith.h() calls.
5
+ * This allows Zenith to support JSX semantics without a full JSX compiler like Babel.
6
+ *
7
+ * Handles:
8
+ * - Multi-line JSX expressions
9
+ * - Nested elements
10
+ * - Complex event handlers like onclick={() => fn(item)}
11
+ * - Expression attributes {expr}
12
+ * - Text interpolation {item.title}
13
+ */
14
+ /**
15
+ * Find the end of a balanced brace expression
16
+ */
17
+ function findBalancedBraceEnd(code, startIndex) {
18
+ let braceCount = 1;
19
+ let i = startIndex + 1;
20
+ let inString = false;
21
+ let stringChar = '';
22
+ let inTemplate = false;
23
+ while (i < code.length && braceCount > 0) {
24
+ const char = code[i];
25
+ const prevChar = i > 0 ? code[i - 1] : '';
26
+ // Handle escape sequences
27
+ if (prevChar === '\\') {
28
+ i++;
29
+ continue;
30
+ }
31
+ // Handle string literals
32
+ if (!inString && !inTemplate && (char === '"' || char === "'")) {
33
+ inString = true;
34
+ stringChar = char;
35
+ i++;
36
+ continue;
37
+ }
38
+ if (inString && char === stringChar) {
39
+ inString = false;
40
+ stringChar = '';
41
+ i++;
42
+ continue;
43
+ }
44
+ // Handle template literals
45
+ if (!inString && !inTemplate && char === '`') {
46
+ inTemplate = true;
47
+ i++;
48
+ continue;
49
+ }
50
+ if (inTemplate && char === '`') {
51
+ inTemplate = false;
52
+ i++;
53
+ continue;
54
+ }
55
+ // Count braces only when not in strings
56
+ if (!inString && !inTemplate) {
57
+ if (char === '{')
58
+ braceCount++;
59
+ else if (char === '}')
60
+ braceCount--;
61
+ }
62
+ i++;
63
+ }
64
+ return braceCount === 0 ? i : -1;
65
+ }
66
+ /**
67
+ * Parse JSX attributes using balanced parsing for expression values
68
+ */
69
+ function parseJSXAttributes(code, startIndex) {
70
+ const attrPairs = [];
71
+ let i = startIndex;
72
+ // Skip whitespace
73
+ while (i < code.length && /\s/.test(code[i]))
74
+ i++;
75
+ while (i < code.length) {
76
+ const char = code[i];
77
+ // Check for end of opening tag
78
+ if (char === '>') {
79
+ return { attrs: formatAttrs(attrPairs), endIndex: i + 1, isSelfClosing: false };
80
+ }
81
+ if (char === '/' && code[i + 1] === '>') {
82
+ return { attrs: formatAttrs(attrPairs), endIndex: i + 2, isSelfClosing: true };
83
+ }
84
+ // Parse attribute name
85
+ const nameMatch = code.slice(i).match(/^([a-zA-Z_][a-zA-Z0-9_-]*)/);
86
+ if (!nameMatch) {
87
+ i++;
88
+ continue;
89
+ }
90
+ const attrName = nameMatch[1];
91
+ i += attrName.length;
92
+ // Skip whitespace
93
+ while (i < code.length && /\s/.test(code[i]))
94
+ i++;
95
+ // Check for value
96
+ if (code[i] !== '=') {
97
+ attrPairs.push(`"${attrName}": true`);
98
+ continue;
99
+ }
100
+ i++; // Skip '='
101
+ // Skip whitespace
102
+ while (i < code.length && /\s/.test(code[i]))
103
+ i++;
104
+ // Parse value
105
+ if (code[i] === '"' || code[i] === "'") {
106
+ const quote = code[i];
107
+ let endQuote = i + 1;
108
+ while (endQuote < code.length && code[endQuote] !== quote) {
109
+ if (code[endQuote] === '\\')
110
+ endQuote++; // Skip escaped chars
111
+ endQuote++;
112
+ }
113
+ const value = code.slice(i + 1, endQuote);
114
+ attrPairs.push(`"${attrName}": "${value}"`);
115
+ i = endQuote + 1;
116
+ }
117
+ else if (code[i] === '{') {
118
+ // Expression value - find balanced end
119
+ const endBrace = findBalancedBraceEnd(code, i);
120
+ if (endBrace === -1) {
121
+ i++;
122
+ continue;
123
+ }
124
+ const expr = code.slice(i + 1, endBrace - 1).trim();
125
+ attrPairs.push(`"${attrName}": ${expr}`);
126
+ i = endBrace;
127
+ }
128
+ else {
129
+ // Unquoted value (rare in JSX, but support it)
130
+ const unquotedMatch = code.slice(i).match(/^([^\s/>]+)/);
131
+ if (unquotedMatch) {
132
+ attrPairs.push(`"${attrName}": "${unquotedMatch[1]}"`);
133
+ i += unquotedMatch[1].length;
134
+ }
135
+ }
136
+ // Skip whitespace
137
+ while (i < code.length && /\s/.test(code[i]))
138
+ i++;
139
+ }
140
+ return { attrs: formatAttrs(attrPairs), endIndex: i, isSelfClosing: false };
141
+ }
142
+ function formatAttrs(pairs) {
143
+ return pairs.length > 0 ? `{ ${pairs.join(', ')} }` : 'null';
144
+ }
145
+ /**
146
+ * Find the matching closing tag for an element
147
+ */
148
+ function findClosingTag(code, startIndex, tagName) {
149
+ let depth = 1;
150
+ let i = startIndex;
151
+ const openPattern = new RegExp(`<${tagName}(?:\\s|>|/>)`, 'i');
152
+ const closeTag = `</${tagName}>`;
153
+ while (i < code.length && depth > 0) {
154
+ // Check for closing tag
155
+ if (code.slice(i, i + closeTag.length).toLowerCase() === closeTag.toLowerCase()) {
156
+ depth--;
157
+ if (depth === 0)
158
+ return i;
159
+ i += closeTag.length;
160
+ continue;
161
+ }
162
+ // Check for opening tag (same name, nested)
163
+ const openMatch = code.slice(i).match(openPattern);
164
+ if (openMatch && openMatch.index === 0) {
165
+ // Check if it's self-closing
166
+ const selfClosing = code.slice(i).match(new RegExp(`<${tagName}[^>]*/>`, 'i'));
167
+ if (!selfClosing || selfClosing.index !== 0) {
168
+ depth++;
169
+ }
170
+ i += openMatch[0].length;
171
+ continue;
172
+ }
173
+ i++;
174
+ }
175
+ return -1;
176
+ }
177
+ /**
178
+ * Parse JSX children content
179
+ */
180
+ function parseJSXChildren(code, startIndex, tagName) {
181
+ const closingIndex = findClosingTag(code, startIndex, tagName);
182
+ if (closingIndex === -1) {
183
+ return { children: 'null', endIndex: code.length };
184
+ }
185
+ const content = code.slice(startIndex, closingIndex);
186
+ if (!content.trim()) {
187
+ return { children: 'null', endIndex: closingIndex };
188
+ }
189
+ // Transform the children content
190
+ const transformedContent = transformChildContent(content);
191
+ return { children: transformedContent, endIndex: closingIndex };
192
+ }
193
+ /**
194
+ * Transform content that may contain text, expressions, and nested JSX
195
+ */
196
+ function transformChildContent(content) {
197
+ const parts = [];
198
+ let i = 0;
199
+ let currentText = '';
200
+ while (i < content.length) {
201
+ const char = content[i];
202
+ // Check for JSX element
203
+ if (char === '<' && /[a-zA-Z]/.test(content[i + 1] || '')) {
204
+ // Save any accumulated text
205
+ if (currentText.trim()) {
206
+ parts.push(`"${escapeString(currentText.trim())}"`);
207
+ currentText = '';
208
+ }
209
+ // Try to parse as JSX element
210
+ const parsed = parseJSXElement(content, i);
211
+ if (parsed) {
212
+ parts.push(parsed.hCall);
213
+ i = parsed.endIndex;
214
+ continue;
215
+ }
216
+ }
217
+ // Check for expression {expr}
218
+ if (char === '{') {
219
+ const endBrace = findBalancedBraceEnd(content, i);
220
+ if (endBrace !== -1) {
221
+ // Save any accumulated text
222
+ if (currentText.trim()) {
223
+ parts.push(`"${escapeString(currentText.trim())}"`);
224
+ currentText = '';
225
+ }
226
+ // Extract and add expression
227
+ const expr = content.slice(i + 1, endBrace - 1).trim();
228
+ if (expr) {
229
+ // Transform any JSX inside the expression
230
+ const transformedExpr = transformExpressionJSX(expr);
231
+ parts.push(transformedExpr);
232
+ }
233
+ i = endBrace;
234
+ continue;
235
+ }
236
+ }
237
+ // Accumulate text
238
+ currentText += char;
239
+ i++;
240
+ }
241
+ // Add remaining text
242
+ if (currentText.trim()) {
243
+ parts.push(`"${escapeString(currentText.trim())}"`);
244
+ }
245
+ if (parts.length === 0)
246
+ return 'null';
247
+ if (parts.length === 1)
248
+ return parts[0];
249
+ return `[${parts.join(', ')}]`;
250
+ }
251
+ /**
252
+ * Escape a string for use in JavaScript
253
+ */
254
+ function escapeString(str) {
255
+ return str
256
+ .replace(/\\/g, '\\\\')
257
+ .replace(/"/g, '\\"')
258
+ .replace(/\n/g, '\\n')
259
+ .replace(/\r/g, '\\r')
260
+ .replace(/\t/g, '\\t');
261
+ }
262
+ /**
263
+ * Parse a single JSX element starting at the given index
264
+ */
265
+ function parseJSXElement(code, startIndex) {
266
+ // Extract tag name
267
+ const tagMatch = code.slice(startIndex).match(/^<([a-zA-Z][a-zA-Z0-9]*)/);
268
+ if (!tagMatch)
269
+ return null;
270
+ const tagName = tagMatch[1];
271
+ let i = startIndex + tagMatch[0].length;
272
+ // Parse attributes
273
+ const { attrs, endIndex: attrEnd, isSelfClosing } = parseJSXAttributes(code, i);
274
+ i = attrEnd;
275
+ if (isSelfClosing) {
276
+ return {
277
+ hCall: `__zenith.h("${tagName}", ${attrs}, null)`,
278
+ endIndex: i
279
+ };
280
+ }
281
+ // Parse children until closing tag
282
+ const { children, endIndex: childEnd } = parseJSXChildren(code, i, tagName);
283
+ i = childEnd;
284
+ // Skip closing tag
285
+ const closeTag = `</${tagName}>`;
286
+ if (code.slice(i, i + closeTag.length).toLowerCase() === closeTag.toLowerCase()) {
287
+ i += closeTag.length;
288
+ }
289
+ return {
290
+ hCall: `__zenith.h("${tagName}", ${attrs}, ${children})`,
291
+ endIndex: i
292
+ };
293
+ }
294
+ /**
295
+ * Main transformer function
296
+ *
297
+ * Transforms JSX-like tags inside Zenith expressions into __zenith.h() calls.
298
+ */
299
+ export function transformExpressionJSX(code) {
300
+ // Skip if no JSX-like content (optimization)
301
+ if (!/<[a-zA-Z]/.test(code)) {
302
+ return code;
303
+ }
304
+ let result = '';
305
+ let i = 0;
306
+ while (i < code.length) {
307
+ // Look for potential JSX tag start
308
+ // Only treat as JSX if it follows common JSX contexts: (, return, =, :, ,, [, ?
309
+ if (code[i] === '<' && /[a-zA-Z]/.test(code[i + 1] || '')) {
310
+ // Check if this looks like a JSX context
311
+ const beforeChar = i > 0 ? code[i - 1] : '';
312
+ const beforeTrimmed = code.slice(0, i).trimEnd();
313
+ const lastChar = beforeTrimmed[beforeTrimmed.length - 1] || '';
314
+ // Common JSX-starting contexts
315
+ const jsxContexts = ['(', '=', ':', ',', '[', '?', '{', 'n']; // 'n' for 'return'
316
+ const isJSXContext = jsxContexts.includes(lastChar) ||
317
+ beforeTrimmed.endsWith('return') ||
318
+ beforeTrimmed === '' ||
319
+ (beforeChar && /\s/.test(beforeChar));
320
+ if (isJSXContext) {
321
+ const parsed = parseJSXElement(code, i);
322
+ if (parsed) {
323
+ result += parsed.hCall;
324
+ i = parsed.endIndex;
325
+ continue;
326
+ }
327
+ }
328
+ }
329
+ result += code[i];
330
+ i++;
331
+ }
332
+ return result;
333
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Fragment Lowering
3
+ *
4
+ * Transforms JSX-returning expressions into structural fragment nodes.
5
+ *
6
+ * This phase runs AFTER parsing, BEFORE component resolution.
7
+ * Transforms ExpressionNode → ConditionalFragmentNode | OptionalFragmentNode | LoopFragmentNode
8
+ *
9
+ * IMPORTANT: JSX in Zenith is compile-time sugar only.
10
+ * The compiler enumerates all possible DOM shapes and lowers them at compile time.
11
+ * Runtime never creates DOM — it only toggles visibility and binds values.
12
+ */
13
+ import type { TemplateNode, ExpressionIR } from '../ir/types';
14
+ /**
15
+ * Lower JSX-returning expressions into structural fragments
16
+ *
17
+ * Walks the node tree and transforms ExpressionNode instances
18
+ * that return JSX into the appropriate fragment node types.
19
+ *
20
+ * @param nodes - Template nodes to process
21
+ * @param filePath - Source file path for error reporting
22
+ * @param expressions - Expression registry (mutated to add new expressions)
23
+ * @returns Lowered nodes with fragment bindings
24
+ */
25
+ export declare function lowerFragments(nodes: TemplateNode[], filePath: string, expressions: ExpressionIR[]): TemplateNode[];