@zenithbuild/core 0.1.0
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.
- package/.eslintignore +15 -0
- package/.gitattributes +2 -0
- package/.github/ISSUE_TEMPLATE/compiler-errors-for-invalid-state-declarations.md +25 -0
- package/.github/ISSUE_TEMPLATE/new_ticket.yaml +34 -0
- package/.github/pull_request_template.md +15 -0
- package/.github/workflows/discord-changelog.yml +141 -0
- package/.github/workflows/discord-notify.yml +242 -0
- package/.github/workflows/discord-version.yml +195 -0
- package/.prettierignore +13 -0
- package/.prettierrc +21 -0
- package/.zen.d.ts +15 -0
- package/LICENSE +21 -0
- package/README.md +55 -0
- package/app/components/Button.zen +46 -0
- package/app/components/Link.zen +11 -0
- package/app/favicon.ico +0 -0
- package/app/layouts/Main.zen +59 -0
- package/app/pages/about.zen +23 -0
- package/app/pages/blog/[id].zen +53 -0
- package/app/pages/blog/index.zen +32 -0
- package/app/pages/dynamic-dx.zen +712 -0
- package/app/pages/dynamic-primitives.zen +453 -0
- package/app/pages/index.zen +154 -0
- package/app/pages/navigation-demo.zen +229 -0
- package/app/pages/posts/[...slug].zen +61 -0
- package/app/pages/primitives-demo.zen +273 -0
- package/assets/logos/0E3B5DDD-605C-4839-BB2E-DFCA8ADC9604.PNG +0 -0
- package/assets/logos/760971E5-79A1-44F9-90B9-925DF30F4278.PNG +0 -0
- package/assets/logos/8A06ED80-9ED2-4689-BCBD-13B2E95EE8E4.JPG +0 -0
- package/assets/logos/C691FF58-ED13-4E8D-B6A3-02E835849340.PNG +0 -0
- package/assets/logos/C691FF58-ED13-4E8D-B6A3-02E835849340.svg +601 -0
- package/assets/logos/README.md +54 -0
- package/assets/logos/zen.icns +0 -0
- package/bun.lock +39 -0
- package/compiler/README.md +380 -0
- package/compiler/errors/compilerError.ts +24 -0
- package/compiler/finalize/finalizeOutput.ts +163 -0
- package/compiler/finalize/generateFinalBundle.ts +82 -0
- package/compiler/index.ts +44 -0
- package/compiler/ir/types.ts +83 -0
- package/compiler/legacy/binding.ts +254 -0
- package/compiler/legacy/bindings.ts +338 -0
- package/compiler/legacy/component-process.ts +1208 -0
- package/compiler/legacy/component.ts +301 -0
- package/compiler/legacy/event.ts +50 -0
- package/compiler/legacy/expression.ts +1149 -0
- package/compiler/legacy/mutation.ts +280 -0
- package/compiler/legacy/parse.ts +299 -0
- package/compiler/legacy/split.ts +608 -0
- package/compiler/legacy/types.ts +32 -0
- package/compiler/output/types.ts +34 -0
- package/compiler/parse/detectMapExpressions.ts +102 -0
- package/compiler/parse/parseScript.ts +22 -0
- package/compiler/parse/parseTemplate.ts +425 -0
- package/compiler/parse/parseZenFile.ts +66 -0
- package/compiler/parse/trackLoopContext.ts +82 -0
- package/compiler/runtime/dataExposure.ts +291 -0
- package/compiler/runtime/generateDOM.ts +144 -0
- package/compiler/runtime/generateHydrationBundle.ts +383 -0
- package/compiler/runtime/hydration.ts +309 -0
- package/compiler/runtime/navigation.ts +432 -0
- package/compiler/runtime/thinRuntime.ts +160 -0
- package/compiler/runtime/transformIR.ts +256 -0
- package/compiler/runtime/wrapExpression.ts +84 -0
- package/compiler/runtime/wrapExpressionWithLoop.ts +77 -0
- package/compiler/spa-build.ts +1000 -0
- package/compiler/test/validate-test.ts +104 -0
- package/compiler/transform/generateBindings.ts +47 -0
- package/compiler/transform/generateHTML.ts +28 -0
- package/compiler/transform/transformNode.ts +126 -0
- package/compiler/transform/transformTemplate.ts +38 -0
- package/compiler/validate/validateExpressions.ts +168 -0
- package/core/index.ts +135 -0
- package/core/lifecycle/index.ts +49 -0
- package/core/lifecycle/zen-mount.ts +182 -0
- package/core/lifecycle/zen-unmount.ts +88 -0
- package/core/reactivity/index.ts +54 -0
- package/core/reactivity/tracking.ts +167 -0
- package/core/reactivity/zen-batch.ts +57 -0
- package/core/reactivity/zen-effect.ts +139 -0
- package/core/reactivity/zen-memo.ts +146 -0
- package/core/reactivity/zen-ref.ts +52 -0
- package/core/reactivity/zen-signal.ts +121 -0
- package/core/reactivity/zen-state.ts +180 -0
- package/core/reactivity/zen-untrack.ts +44 -0
- package/docs/COMMENTS.md +111 -0
- package/docs/COMMITS.md +36 -0
- package/docs/CONTRIBUTING.md +116 -0
- package/docs/STYLEGUIDE.md +62 -0
- package/package.json +44 -0
- package/router/index.ts +76 -0
- package/router/manifest.ts +314 -0
- package/router/navigation/ZenLink.zen +231 -0
- package/router/navigation/index.ts +78 -0
- package/router/navigation/zen-link.ts +584 -0
- package/router/runtime.ts +458 -0
- package/router/types.ts +168 -0
- package/runtime/build.ts +17 -0
- package/runtime/serve.ts +93 -0
- package/scripts/webhook-proxy.ts +213 -0
- package/tsconfig.json +28 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Zenith Logos
|
|
2
|
+
|
|
3
|
+
This directory contains the Zenith framework logo assets.
|
|
4
|
+
|
|
5
|
+
## Logo Files
|
|
6
|
+
|
|
7
|
+
Based on the logo designs, you should place the following files here:
|
|
8
|
+
|
|
9
|
+
1. **zenith-logo-icon.png** (or .svg) - The file icon version with the folded corner and ".ZENITH" button
|
|
10
|
+
2. **zenith-logo-z.png** (or .svg) - The stylized "Z" logo with gradient and light trails
|
|
11
|
+
3. **zenith-logo-full.png** (or .svg) - The full logo with "ZENITH" text below
|
|
12
|
+
4. **zenith-logo-soon.png** (or .svg) - The logo variant with "Soon" text
|
|
13
|
+
|
|
14
|
+
## File Icon for .zen Files
|
|
15
|
+
|
|
16
|
+
The SVG logo has been converted to a macOS `.icns` file to use as the file icon for `.zen` files.
|
|
17
|
+
|
|
18
|
+
### Setting the Icon
|
|
19
|
+
|
|
20
|
+
**Option 1: Use the automated script (recommended)**
|
|
21
|
+
```bash
|
|
22
|
+
cd assets/logos
|
|
23
|
+
./set-zen-icon.sh path/to/your/file.zen
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Option 2: Set icon for all .zen files in a directory**
|
|
27
|
+
```bash
|
|
28
|
+
cd assets/logos
|
|
29
|
+
find ../app -name "*.zen" -exec ./set-zen-icon.sh {} \;
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Option 3: Manual method**
|
|
33
|
+
1. Open Finder and navigate to a `.zen` file
|
|
34
|
+
2. Right-click the file and select "Get Info"
|
|
35
|
+
3. Drag `zen.icns` onto the small icon in the top-left of the Get Info window
|
|
36
|
+
4. Close the Get Info window
|
|
37
|
+
|
|
38
|
+
### Recreating the .icns File
|
|
39
|
+
|
|
40
|
+
If you update the SVG and need to regenerate the `.icns` file:
|
|
41
|
+
```bash
|
|
42
|
+
cd assets/logos
|
|
43
|
+
./create-zen-icon.sh
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Usage
|
|
47
|
+
|
|
48
|
+
These logos can be used in:
|
|
49
|
+
- Documentation (`docs/`)
|
|
50
|
+
- README files
|
|
51
|
+
- Website/marketing materials
|
|
52
|
+
- Framework branding
|
|
53
|
+
- File type icons (`.zen` files)
|
|
54
|
+
|
|
Binary file
|
package/bun.lock
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"lockfileVersion": 1,
|
|
3
|
+
"configVersion": 1,
|
|
4
|
+
"workspaces": {
|
|
5
|
+
"": {
|
|
6
|
+
"name": "zenith",
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"@types/parse5": "^7.0.0",
|
|
9
|
+
"parse5": "^8.0.0",
|
|
10
|
+
},
|
|
11
|
+
"devDependencies": {
|
|
12
|
+
"@types/bun": "latest",
|
|
13
|
+
"prettier": "^3.7.4",
|
|
14
|
+
},
|
|
15
|
+
"peerDependencies": {
|
|
16
|
+
"typescript": "^5",
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
"packages": {
|
|
21
|
+
"@types/bun": ["@types/bun@1.3.5", "", { "dependencies": { "bun-types": "1.3.5" } }, "sha512-RnygCqNrd3srIPEWBd5LFeUYG7plCoH2Yw9WaZGyNmdTEei+gWaHqydbaIRkIkcbXwhBT94q78QljxN0Sk838w=="],
|
|
22
|
+
|
|
23
|
+
"@types/node": ["@types/node@25.0.3", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA=="],
|
|
24
|
+
|
|
25
|
+
"@types/parse5": ["@types/parse5@7.0.0", "", { "dependencies": { "parse5": "*" } }, "sha512-f2SeAxumolBmhuR62vNGTsSAvdz/Oj0k682xNrcKJ4dmRnTPODB74j6CPoNPzBPTHsu7Y7W7u93Mgp8Ovo8vWw=="],
|
|
26
|
+
|
|
27
|
+
"bun-types": ["bun-types@1.3.5", "", { "dependencies": { "@types/node": "*" } }, "sha512-inmAYe2PFLs0SUbFOWSVD24sg1jFlMPxOjOSSCYqUgn4Hsc3rDc7dFvfVYjFPNHtov6kgUeulV4SxbuIV/stPw=="],
|
|
28
|
+
|
|
29
|
+
"entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="],
|
|
30
|
+
|
|
31
|
+
"parse5": ["parse5@8.0.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA=="],
|
|
32
|
+
|
|
33
|
+
"prettier": ["prettier@3.7.4", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA=="],
|
|
34
|
+
|
|
35
|
+
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
|
36
|
+
|
|
37
|
+
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
# Zenith Compiler - Phase 1: Parse & Extract
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This is Phase 1 of the Zenith compiler implementation. This phase focuses on **parsing and extracting** structure from `.zen` files without any runtime execution or transformation.
|
|
6
|
+
|
|
7
|
+
## Directory Structure
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
/compiler
|
|
11
|
+
/parse
|
|
12
|
+
parseZenFile.ts # Main file parser
|
|
13
|
+
parseTemplate.ts # Template/HTML parser
|
|
14
|
+
parseScript.ts # Script block extractor
|
|
15
|
+
/ir
|
|
16
|
+
types.ts # Intermediate Representation types
|
|
17
|
+
/errors
|
|
18
|
+
compilerError.ts # Compiler error handling
|
|
19
|
+
index.ts # Public API entry point
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { compileZen } from './compiler/index'
|
|
26
|
+
|
|
27
|
+
const ir = compileZen('app/pages/example.zen')
|
|
28
|
+
// Returns ZenIR structure with parsed template, script, styles, and extracted expressions
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## What This Phase Does
|
|
32
|
+
|
|
33
|
+
✅ Parses `.zen` files into structured IR
|
|
34
|
+
✅ Extracts `<script>` and `<style>` blocks
|
|
35
|
+
✅ Parses HTML template structure
|
|
36
|
+
✅ Extracts `{expression}` patterns from text and attributes
|
|
37
|
+
✅ Records source locations for all nodes and expressions
|
|
38
|
+
✅ Throws compiler errors with location information
|
|
39
|
+
|
|
40
|
+
## What This Phase Does NOT Do
|
|
41
|
+
|
|
42
|
+
❌ Execute expressions
|
|
43
|
+
❌ Transform code
|
|
44
|
+
❌ Generate runtime code
|
|
45
|
+
❌ Handle reactivity
|
|
46
|
+
❌ Render to DOM
|
|
47
|
+
❌ Perform any runtime operations
|
|
48
|
+
|
|
49
|
+
## IR Structure
|
|
50
|
+
|
|
51
|
+
The compiler produces a `ZenIR` object containing:
|
|
52
|
+
|
|
53
|
+
- `filePath`: Path to the source file
|
|
54
|
+
- `template`: TemplateIR with nodes and extracted expressions
|
|
55
|
+
- `script`: ScriptIR with raw script content (or null)
|
|
56
|
+
- `styles`: Array of StyleIR with raw style content
|
|
57
|
+
|
|
58
|
+
## Expression Extraction
|
|
59
|
+
|
|
60
|
+
Expressions are extracted from:
|
|
61
|
+
- Text content: `Hello {name}!`
|
|
62
|
+
- Attribute values: `class={isActive ? "on" : "off"}`
|
|
63
|
+
|
|
64
|
+
Each expression gets:
|
|
65
|
+
- Unique ID (e.g., `expr_0`, `expr_1`)
|
|
66
|
+
- Source code (the expression content)
|
|
67
|
+
- Source location (line + column)
|
|
68
|
+
|
|
69
|
+
## Phase 2: Transform IR → Static HTML + Runtime Bindings
|
|
70
|
+
|
|
71
|
+
Phase 2 transforms the IR into static HTML with explicit bindings:
|
|
72
|
+
|
|
73
|
+
- ✅ All `{}` expressions removed from HTML
|
|
74
|
+
- ✅ Expressions replaced with data attributes (`data-zen-text`, `data-zen-attr-*`)
|
|
75
|
+
- ✅ Bindings array generated with expression source code
|
|
76
|
+
- ✅ Scripts and styles pass through unchanged
|
|
77
|
+
- ✅ No runtime execution - pure transformation
|
|
78
|
+
|
|
79
|
+
### Output Structure
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
{
|
|
83
|
+
html: string, // Static HTML with no {}
|
|
84
|
+
bindings: Binding[], // Array of expression bindings
|
|
85
|
+
scripts: string, // Raw script content
|
|
86
|
+
styles: string[] // Raw style content
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Binding Format
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
{
|
|
94
|
+
id: "exp_1",
|
|
95
|
+
type: "text" | "attribute",
|
|
96
|
+
target: "data-zen-text" | "class" | "style" | etc,
|
|
97
|
+
expression: "user.name" // Original expression code
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Phase 4: Runtime DOM & Reactivity
|
|
102
|
+
|
|
103
|
+
Phase 4 transforms the IR into fully functional runtime JavaScript code:
|
|
104
|
+
|
|
105
|
+
- ✅ Expression wrapping with state access
|
|
106
|
+
- ✅ DOM creation code generation
|
|
107
|
+
- ✅ Event handler binding
|
|
108
|
+
- ✅ State initialization
|
|
109
|
+
- ✅ Hydrate function for SPA hydration
|
|
110
|
+
- ✅ Style injection
|
|
111
|
+
|
|
112
|
+
### Runtime Code Structure
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
{
|
|
116
|
+
expressions: string, // Wrapped expression functions
|
|
117
|
+
render: string, // renderDynamicPage(state) function
|
|
118
|
+
hydrate: string, // hydrate(root, state) function
|
|
119
|
+
styles: string, // Style injection code
|
|
120
|
+
script: string, // Transformed script code
|
|
121
|
+
stateInit: string // State initialization code
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Usage
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { compileZen } from './compiler/index'
|
|
129
|
+
import { transformIR } from './compiler/runtime/transformIR'
|
|
130
|
+
|
|
131
|
+
const { ir } = compileZen('app/pages/example.zen')
|
|
132
|
+
const runtime = transformIR(ir)
|
|
133
|
+
|
|
134
|
+
// Runtime code is now ready to execute
|
|
135
|
+
// - runtime.expressions: Expression wrapper functions
|
|
136
|
+
// - runtime.render: DOM creation function
|
|
137
|
+
// - runtime.hydrate: Hydration function
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Phase 5: Runtime Hydration
|
|
141
|
+
|
|
142
|
+
Phase 5 provides the browser-side runtime that hydrates static HTML with dynamic expressions:
|
|
143
|
+
|
|
144
|
+
- ✅ Expression evaluation via registry (`window.__ZENITH_EXPRESSIONS__`)
|
|
145
|
+
- ✅ Text binding updates (`data-zen-text` attributes)
|
|
146
|
+
- ✅ Attribute binding updates (`data-zen-attr-*` attributes)
|
|
147
|
+
- ✅ Event handler binding (`data-zen-{eventType}` attributes)
|
|
148
|
+
- ✅ Reactive state updates (`update(state)` function)
|
|
149
|
+
- ✅ Cleanup and memory management
|
|
150
|
+
- ✅ Error handling with expression IDs
|
|
151
|
+
|
|
152
|
+
### Runtime Functions
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
// Hydrate static HTML with dynamic expressions
|
|
156
|
+
window.zenithHydrate(state, container?)
|
|
157
|
+
|
|
158
|
+
// Update all bindings when state changes
|
|
159
|
+
window.zenithUpdate(state)
|
|
160
|
+
|
|
161
|
+
// Bind event handlers
|
|
162
|
+
window.zenithBindEvents(container?)
|
|
163
|
+
|
|
164
|
+
// Cleanup bindings and event listeners
|
|
165
|
+
window.zenithCleanup(container?)
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Runtime Bundle
|
|
169
|
+
|
|
170
|
+
The `transformIR` function now generates a complete runtime bundle:
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
const runtime = transformIR(ir)
|
|
174
|
+
// runtime.bundle contains the complete JavaScript code ready for browser execution
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
The bundle includes:
|
|
178
|
+
- Expression wrapper functions
|
|
179
|
+
- Expression registry initialization
|
|
180
|
+
- Hydration runtime code
|
|
181
|
+
- State initialization
|
|
182
|
+
- Style injection
|
|
183
|
+
- User script code
|
|
184
|
+
|
|
185
|
+
### Usage Example
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
// In browser
|
|
189
|
+
const state = { user: { name: 'Alice' }, count: 5 }
|
|
190
|
+
window.zenithHydrate(state, document.body)
|
|
191
|
+
|
|
192
|
+
// On state change
|
|
193
|
+
state.count = 10
|
|
194
|
+
window.zenithUpdate(state)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Phase 6: Explicit Data Exposure
|
|
198
|
+
|
|
199
|
+
Phase 6 ensures all data references are explicit rather than relying on implicit globals:
|
|
200
|
+
|
|
201
|
+
- ✅ Expression dependency analysis (loaderData, props, stores, state)
|
|
202
|
+
- ✅ Explicit function signatures with data arguments
|
|
203
|
+
- ✅ Updated hydration runtime to pass explicit data
|
|
204
|
+
- ✅ Compile-time validation of data references
|
|
205
|
+
- ✅ Backwards compatibility with legacy state-only expressions
|
|
206
|
+
|
|
207
|
+
### Data Sources
|
|
208
|
+
|
|
209
|
+
Expressions can reference data from:
|
|
210
|
+
1. **Loader Data** - Route-level `loader()` function data (`loaderData.user.name`)
|
|
211
|
+
2. **Props** - Component/page props (`props.title`)
|
|
212
|
+
3. **Stores** - Global stores (`stores.cart.items`)
|
|
213
|
+
4. **State** - Reactive state (`state.count`)
|
|
214
|
+
|
|
215
|
+
### Expression Wrapper Signatures
|
|
216
|
+
|
|
217
|
+
Phase 6 expressions now accept explicit arguments:
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
// Before (Phase 5)
|
|
221
|
+
const expr_0 = (state) => { with (state) { return user.name } }
|
|
222
|
+
|
|
223
|
+
// After (Phase 6)
|
|
224
|
+
const expr_0 = (state, loaderData, props, stores) => {
|
|
225
|
+
const __ctx = Object.assign({}, loaderData, props, stores, state);
|
|
226
|
+
with (__ctx) { return user.name }
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Runtime Hydration
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
// Phase 6 signature
|
|
234
|
+
window.zenithHydrate(state, loaderData, props, stores, container?)
|
|
235
|
+
window.zenithUpdate(state, loaderData, props, stores)
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
The runtime maintains backwards compatibility - if called with only `state`, it uses legacy behavior.
|
|
239
|
+
|
|
240
|
+
### Data Dependency Analysis
|
|
241
|
+
|
|
242
|
+
The compiler analyzes each expression to detect:
|
|
243
|
+
- `loaderData.property` → loader data dependency
|
|
244
|
+
- `props.name` → props dependency
|
|
245
|
+
- `stores.name` → stores dependency
|
|
246
|
+
- Simple identifiers → state dependency
|
|
247
|
+
|
|
248
|
+
All dependencies are validated at compile time with clear error messages.
|
|
249
|
+
|
|
250
|
+
## Phase 7: Navigation, Prefetch & Bun Accelerator
|
|
251
|
+
|
|
252
|
+
Phase 7 implements safe SPA navigation with prefetching and explicit data exposure:
|
|
253
|
+
|
|
254
|
+
- ✅ Prefetch compiled output (HTML + JS) for routes
|
|
255
|
+
- ✅ Route caching system
|
|
256
|
+
- ✅ Safe SPA navigation with explicit data (loaderData, props, stores)
|
|
257
|
+
- ✅ Browser history handling (back/forward)
|
|
258
|
+
- ✅ ZenLink component with prefetch support
|
|
259
|
+
- ✅ Navigation runtime integration
|
|
260
|
+
- ✅ No raw .zen files in browser
|
|
261
|
+
|
|
262
|
+
### Navigation API
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
// Prefetch a route
|
|
266
|
+
window.__zenith_prefetch('/dashboard')
|
|
267
|
+
|
|
268
|
+
// Navigate with explicit data
|
|
269
|
+
window.navigate('/dashboard', {
|
|
270
|
+
loaderData: { user: { name: 'Alice' } },
|
|
271
|
+
props: { title: 'Dashboard' },
|
|
272
|
+
stores: { cart: { items: 3 } },
|
|
273
|
+
replace: false // Use pushState instead of replaceState
|
|
274
|
+
})
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### ZenLink Component
|
|
278
|
+
|
|
279
|
+
```html
|
|
280
|
+
<!-- With prefetch (on hover) -->
|
|
281
|
+
<ZenLink href="/about" prefetch={true}>About</ZenLink>
|
|
282
|
+
|
|
283
|
+
<!-- Without prefetch -->
|
|
284
|
+
<ZenLink href="/blog">Blog</ZenLink>
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Key Principles
|
|
288
|
+
|
|
289
|
+
1. **Compiler owns all expressions** - Runtime never parses .zen files
|
|
290
|
+
2. **Prefetch compiled output** - HTML + JS bundles, not source
|
|
291
|
+
3. **Explicit data exposure** - All data passed explicitly (no implicit globals)
|
|
292
|
+
4. **Bun as accelerator** - Used for bundling/transpilation, not template parsing
|
|
293
|
+
5. **Safe navigation** - No stacked mutations, proper cleanup, history handling
|
|
294
|
+
|
|
295
|
+
### Route Cache
|
|
296
|
+
|
|
297
|
+
Prefetched routes are cached with:
|
|
298
|
+
- Compiled HTML
|
|
299
|
+
- Compiled JS runtime
|
|
300
|
+
- Styles
|
|
301
|
+
- Route metadata
|
|
302
|
+
|
|
303
|
+
### Browser History
|
|
304
|
+
|
|
305
|
+
The navigation system:
|
|
306
|
+
- Handles `popstate` events for back/forward
|
|
307
|
+
- Updates DOM safely without re-parsing
|
|
308
|
+
- Maintains route state correctly
|
|
309
|
+
- Avoids stacked history mutations
|
|
310
|
+
|
|
311
|
+
## Phase 8/9/10: Finalization & Build Guarantees
|
|
312
|
+
|
|
313
|
+
Phase 8/9/10 ensures deterministic compilation and compile-time validation:
|
|
314
|
+
|
|
315
|
+
- ✅ Compile-time expression validation
|
|
316
|
+
- ✅ Build fails on invalid expressions with line/column info
|
|
317
|
+
- ✅ No raw `{expression}` in HTML output
|
|
318
|
+
- ✅ Thin declarative runtime (no eval, no template parsing)
|
|
319
|
+
- ✅ Bun integration for bundling/transpilation (not template parsing)
|
|
320
|
+
- ✅ Final HTML + JS output ready for browser
|
|
321
|
+
|
|
322
|
+
### Validation
|
|
323
|
+
|
|
324
|
+
All expressions are validated at compile time:
|
|
325
|
+
- Syntax validation
|
|
326
|
+
- Brace/parentheses/bracket matching
|
|
327
|
+
- Unsafe code detection (eval, Function, with)
|
|
328
|
+
- Build fails immediately on errors
|
|
329
|
+
|
|
330
|
+
### Output Guarantees
|
|
331
|
+
|
|
332
|
+
- **HTML**: Contains only hydration markers (`data-zen-text`, `data-zen-attr-*`)
|
|
333
|
+
- **JS**: Pre-compiled expression functions, no template parsing
|
|
334
|
+
- **Runtime**: Thin, declarative - only DOM updates and event binding
|
|
335
|
+
- **No eval**: Runtime never uses `eval`, `new Function`, or `with(window)`
|
|
336
|
+
|
|
337
|
+
### Bun Integration
|
|
338
|
+
|
|
339
|
+
Bun is used as an accelerator for:
|
|
340
|
+
- ✅ JS/TS transpilation
|
|
341
|
+
- ✅ Asset bundling
|
|
342
|
+
- ✅ SSR runtime support
|
|
343
|
+
|
|
344
|
+
Bun is **NOT** used for:
|
|
345
|
+
- ❌ Template parsing
|
|
346
|
+
- ❌ Expression analysis
|
|
347
|
+
- ❌ AST transformations
|
|
348
|
+
|
|
349
|
+
### Build Guarantees
|
|
350
|
+
|
|
351
|
+
- Build success = UI guaranteed to work
|
|
352
|
+
- All failures are compile-time (never runtime)
|
|
353
|
+
- Error messages include file, line, column
|
|
354
|
+
- Invalid expressions fail the build immediately
|
|
355
|
+
|
|
356
|
+
## Next Phases
|
|
357
|
+
|
|
358
|
+
Future enhancements:
|
|
359
|
+
- Enhanced conditional/ternary handling in IR
|
|
360
|
+
- Map iteration support in IR
|
|
361
|
+
- Advanced reactivity with dependency tracking
|
|
362
|
+
- SSR/SSG/ISR output generation
|
|
363
|
+
- Type checking for loader/props/stores data
|
|
364
|
+
- Route cache generation in build system
|
|
365
|
+
|
|
366
|
+
## Testing
|
|
367
|
+
|
|
368
|
+
The compiler can be tested by importing and calling `compileZen()`:
|
|
369
|
+
|
|
370
|
+
```typescript
|
|
371
|
+
import { compileZen } from './compiler/index'
|
|
372
|
+
|
|
373
|
+
try {
|
|
374
|
+
const ir = compileZen('app/pages/example.zen')
|
|
375
|
+
console.log(JSON.stringify(ir, null, 2))
|
|
376
|
+
} catch (error) {
|
|
377
|
+
console.error('Compiler error:', error)
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compiler Error Handling
|
|
3
|
+
*
|
|
4
|
+
* Compiler errors with source location information
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export class CompilerError extends Error {
|
|
8
|
+
file: string
|
|
9
|
+
line: number
|
|
10
|
+
column: number
|
|
11
|
+
|
|
12
|
+
constructor(message: string, file: string, line: number, column: number) {
|
|
13
|
+
super(`${file}:${line}:${column} ${message}`)
|
|
14
|
+
this.name = 'CompilerError'
|
|
15
|
+
this.file = file
|
|
16
|
+
this.line = line
|
|
17
|
+
this.column = column
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
override toString(): string {
|
|
21
|
+
return `${this.file}:${this.line}:${this.column} ${this.message}`
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finalize Output
|
|
3
|
+
*
|
|
4
|
+
* Phase 8/9/10: Generate final compiled HTML + JS output with hydration markers
|
|
5
|
+
*
|
|
6
|
+
* Ensures:
|
|
7
|
+
* - All expressions are replaced with hydration markers
|
|
8
|
+
* - HTML contains no raw {expression} syntax
|
|
9
|
+
* - JS runtime is ready for browser execution
|
|
10
|
+
* - Hydration markers are correctly placed
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { CompiledTemplate } from '../output/types'
|
|
14
|
+
import type { ZenIR } from '../ir/types'
|
|
15
|
+
import { transformIR, type RuntimeCode } from '../runtime/transformIR'
|
|
16
|
+
import { validateExpressionsOrThrow } from '../validate/validateExpressions'
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Finalized output ready for browser
|
|
20
|
+
*/
|
|
21
|
+
export interface FinalizedOutput {
|
|
22
|
+
html: string
|
|
23
|
+
js: string
|
|
24
|
+
styles: string[]
|
|
25
|
+
hasErrors: boolean
|
|
26
|
+
errors: string[]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Finalize compiler output
|
|
31
|
+
*
|
|
32
|
+
* This is the final step that ensures:
|
|
33
|
+
* 1. All expressions are validated
|
|
34
|
+
* 2. HTML contains no raw expressions
|
|
35
|
+
* 3. JS runtime is generated
|
|
36
|
+
* 4. Output is ready for browser
|
|
37
|
+
*
|
|
38
|
+
* @param ir - Intermediate representation
|
|
39
|
+
* @param compiled - Compiled template from Phase 2
|
|
40
|
+
* @returns Finalized output
|
|
41
|
+
*/
|
|
42
|
+
export function finalizeOutput(
|
|
43
|
+
ir: ZenIR,
|
|
44
|
+
compiled: CompiledTemplate
|
|
45
|
+
): FinalizedOutput {
|
|
46
|
+
const errors: string[] = []
|
|
47
|
+
|
|
48
|
+
// 1. Validate all expressions (Phase 8/9/10 requirement)
|
|
49
|
+
try {
|
|
50
|
+
validateExpressionsOrThrow(ir.template.expressions, ir.filePath)
|
|
51
|
+
} catch (error: any) {
|
|
52
|
+
if (error instanceof Error) {
|
|
53
|
+
errors.push(error.message)
|
|
54
|
+
return {
|
|
55
|
+
html: '',
|
|
56
|
+
js: '',
|
|
57
|
+
styles: [],
|
|
58
|
+
hasErrors: true,
|
|
59
|
+
errors
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// 2. Verify HTML contains no raw expressions
|
|
65
|
+
const htmlErrors = verifyNoRawExpressions(compiled.html, ir.filePath)
|
|
66
|
+
if (htmlErrors.length > 0) {
|
|
67
|
+
errors.push(...htmlErrors)
|
|
68
|
+
return {
|
|
69
|
+
html: '',
|
|
70
|
+
js: '',
|
|
71
|
+
styles: [],
|
|
72
|
+
hasErrors: true,
|
|
73
|
+
errors
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// 3. Generate runtime code
|
|
78
|
+
let runtimeCode: RuntimeCode
|
|
79
|
+
try {
|
|
80
|
+
runtimeCode = transformIR(ir)
|
|
81
|
+
} catch (error: any) {
|
|
82
|
+
errors.push(`Runtime generation failed: ${error.message}`)
|
|
83
|
+
return {
|
|
84
|
+
html: '',
|
|
85
|
+
js: '',
|
|
86
|
+
styles: [],
|
|
87
|
+
hasErrors: true,
|
|
88
|
+
errors
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// 4. Combine HTML and JS
|
|
93
|
+
const finalHTML = compiled.html
|
|
94
|
+
const finalJS = runtimeCode.bundle
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
html: finalHTML,
|
|
98
|
+
js: finalJS,
|
|
99
|
+
styles: compiled.styles,
|
|
100
|
+
hasErrors: false,
|
|
101
|
+
errors: []
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Verify HTML contains no raw {expression} syntax
|
|
107
|
+
*
|
|
108
|
+
* This is a critical check - browser must never see raw expressions
|
|
109
|
+
*/
|
|
110
|
+
function verifyNoRawExpressions(html: string, filePath: string): string[] {
|
|
111
|
+
const errors: string[] = []
|
|
112
|
+
|
|
113
|
+
// Check for raw {expression} patterns (not data-zen-* attributes)
|
|
114
|
+
// Allow data-zen-text, data-zen-attr-* but not raw { }
|
|
115
|
+
const rawExpressionPattern = /\{[^}]*\}/g
|
|
116
|
+
const matches = html.match(rawExpressionPattern)
|
|
117
|
+
|
|
118
|
+
if (matches && matches.length > 0) {
|
|
119
|
+
// Filter out false positives (comments, data attributes, etc.)
|
|
120
|
+
const actualExpressions = matches.filter(match => {
|
|
121
|
+
// Exclude if it's in a comment
|
|
122
|
+
if (html.includes(`<!--${match}`) || html.includes(`${match}-->`)) {
|
|
123
|
+
return false
|
|
124
|
+
}
|
|
125
|
+
// Exclude if it's in a data attribute value (already processed)
|
|
126
|
+
if (match.includes('data-zen-')) {
|
|
127
|
+
return false
|
|
128
|
+
}
|
|
129
|
+
// This looks like a raw expression
|
|
130
|
+
return true
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
if (actualExpressions.length > 0) {
|
|
134
|
+
errors.push(
|
|
135
|
+
`HTML contains raw expressions that were not compiled: ${actualExpressions.join(', ')}\n` +
|
|
136
|
+
`File: ${filePath}\n` +
|
|
137
|
+
`All expressions must be replaced with hydration markers (data-zen-text, data-zen-attr-*)`
|
|
138
|
+
)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return errors
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Generate final output with error handling
|
|
147
|
+
*
|
|
148
|
+
* Throws if validation fails (build must fail on errors)
|
|
149
|
+
*/
|
|
150
|
+
export function finalizeOutputOrThrow(
|
|
151
|
+
ir: ZenIR,
|
|
152
|
+
compiled: CompiledTemplate
|
|
153
|
+
): FinalizedOutput {
|
|
154
|
+
const output = finalizeOutput(ir, compiled)
|
|
155
|
+
|
|
156
|
+
if (output.hasErrors) {
|
|
157
|
+
const errorMessage = output.errors.join('\n\n')
|
|
158
|
+
throw new Error(`Compilation failed:\n\n${errorMessage}`)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return output
|
|
162
|
+
}
|
|
163
|
+
|