@hypen-space/core 0.4.37 → 0.4.38
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/README.md +13 -14
- package/dist/app.js +289 -227
- package/dist/app.js.map +5 -5
- package/dist/components/builtin.js +289 -227
- package/dist/components/builtin.js.map +5 -5
- package/dist/context.js +60 -64
- package/dist/context.js.map +2 -2
- package/dist/datasource.js +80 -0
- package/dist/datasource.js.map +10 -0
- package/dist/disposable.js +60 -63
- package/dist/disposable.js.map +2 -2
- package/dist/events.js +60 -63
- package/dist/events.js.map +2 -2
- package/dist/hypen.js +78 -0
- package/dist/hypen.js.map +10 -0
- package/dist/index.browser.d.ts +2 -1
- package/dist/index.browser.js +303 -244
- package/dist/index.browser.js.map +6 -7
- package/dist/index.d.ts +0 -3
- package/dist/index.js +492 -180
- package/dist/index.js.map +6 -6
- package/dist/logger.js +60 -64
- package/dist/logger.js.map +2 -2
- package/dist/remote/client.js +243 -158
- package/dist/remote/client.js.map +6 -6
- package/dist/remote/index.d.ts +6 -5
- package/dist/remote/index.js +241 -1986
- package/dist/remote/index.js.map +6 -13
- package/dist/remote/session.js +151 -0
- package/dist/remote/session.js.map +10 -0
- package/dist/renderer.js +60 -63
- package/dist/renderer.js.map +2 -2
- package/dist/result.js +220 -0
- package/dist/result.js.map +10 -0
- package/dist/retry.js +329 -0
- package/dist/retry.js.map +11 -0
- package/dist/router.js +62 -70
- package/dist/router.js.map +2 -2
- package/dist/state.js +3 -8
- package/dist/state.js.map +2 -2
- package/package.json +11 -56
- package/src/index.browser.ts +5 -4
- package/src/index.ts +10 -23
- package/src/remote/index.ts +9 -5
- package/dist/discovery.d.ts +0 -90
- package/dist/discovery.js +0 -1334
- package/dist/discovery.js.map +0 -15
- package/dist/engine.browser.d.ts +0 -116
- package/dist/engine.browser.js +0 -479
- package/dist/engine.browser.js.map +0 -12
- package/dist/engine.d.ts +0 -107
- package/dist/engine.js +0 -543
- package/dist/engine.js.map +0 -12
- package/dist/loader.d.ts +0 -51
- package/dist/loader.js +0 -292
- package/dist/loader.js.map +0 -11
- package/dist/plugin.d.ts +0 -39
- package/dist/plugin.js +0 -685
- package/dist/plugin.js.map +0 -12
- package/dist/remote/server.d.ts +0 -188
- package/dist/remote/server.js +0 -2270
- package/dist/remote/server.js.map +0 -19
- package/src/discovery.ts +0 -527
- package/src/engine.browser.ts +0 -302
- package/src/engine.ts +0 -282
- package/src/loader.ts +0 -136
- package/src/plugin.ts +0 -220
- package/src/remote/server.ts +0 -879
- package/wasm-browser/README.md +0 -594
- package/wasm-browser/hypen_engine.d.ts +0 -389
- package/wasm-browser/hypen_engine.js +0 -1070
- package/wasm-browser/hypen_engine_bg.wasm +0 -0
- package/wasm-browser/hypen_engine_bg.wasm.d.ts +0 -37
- package/wasm-browser/package.json +0 -24
- package/wasm-node/README.md +0 -594
- package/wasm-node/hypen_engine.d.ts +0 -327
- package/wasm-node/hypen_engine.js +0 -979
- package/wasm-node/hypen_engine_bg.wasm +0 -0
- package/wasm-node/hypen_engine_bg.wasm.d.ts +0 -37
- package/wasm-node/package.json +0 -22
|
Binary file
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/* tslint:disable */
|
|
2
|
-
/* eslint-disable */
|
|
3
|
-
export const memory: WebAssembly.Memory;
|
|
4
|
-
export const __wbg_wasmengine_free: (a: number, b: number) => void;
|
|
5
|
-
export const main: () => void;
|
|
6
|
-
export const parseToJson: (a: number, b: number) => [number, number, number, number];
|
|
7
|
-
export const patchesToJson: (a: any) => [number, number, number, number];
|
|
8
|
-
export const wasmengine_clearTree: (a: number) => void;
|
|
9
|
-
export const wasmengine_currentState: (a: number) => any;
|
|
10
|
-
export const wasmengine_debugParseComponent: (a: number, b: number, c: number) => [number, number, number, number];
|
|
11
|
-
export const wasmengine_dispatchAction: (a: number, b: number, c: number, d: any) => [number, number];
|
|
12
|
-
export const wasmengine_getRevision: (a: number) => bigint;
|
|
13
|
-
export const wasmengine_new: () => number;
|
|
14
|
-
export const wasmengine_onAction: (a: number, b: number, c: number, d: any) => void;
|
|
15
|
-
export const wasmengine_onDataSourceAction: (a: number, b: any) => void;
|
|
16
|
-
export const wasmengine_registerPrimitive: (a: number, b: number, c: number) => void;
|
|
17
|
-
export const wasmengine_removeContext: (a: number, b: number, c: number) => void;
|
|
18
|
-
export const wasmengine_renderInto: (a: number, b: number, c: number, d: number, e: number, f: any) => [number, number];
|
|
19
|
-
export const wasmengine_renderLazyComponent: (a: number, b: number, c: number) => [number, number];
|
|
20
|
-
export const wasmengine_reset: (a: number) => void;
|
|
21
|
-
export const wasmengine_setComponentResolver: (a: number, b: any) => void;
|
|
22
|
-
export const wasmengine_setContext: (a: number, b: number, c: number, d: any) => [number, number];
|
|
23
|
-
export const wasmengine_setModule: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: any) => [number, number];
|
|
24
|
-
export const wasmengine_setRenderCallback: (a: number, b: any) => void;
|
|
25
|
-
export const wasmengine_treeSize: (a: number) => number;
|
|
26
|
-
export const wasmengine_updateState: (a: number, b: any) => [number, number];
|
|
27
|
-
export const wasmengine_updateStateSparse: (a: number, b: any, c: any) => [number, number];
|
|
28
|
-
export const wasmengine_validate: (a: number) => any;
|
|
29
|
-
export const wasmengine_renderSource: (a: number, b: number, c: number) => [number, number];
|
|
30
|
-
export const __wbindgen_malloc: (a: number, b: number) => number;
|
|
31
|
-
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
|
32
|
-
export const __wbindgen_exn_store: (a: number) => void;
|
|
33
|
-
export const __externref_table_alloc: () => number;
|
|
34
|
-
export const __wbindgen_externrefs: WebAssembly.Table;
|
|
35
|
-
export const __externref_table_dealloc: (a: number) => void;
|
|
36
|
-
export const __wbindgen_free: (a: number, b: number, c: number) => void;
|
|
37
|
-
export const __wbindgen_start: () => void;
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "hypen-engine",
|
|
3
|
-
"type": "module",
|
|
4
|
-
"collaborators": [
|
|
5
|
-
"Hypen Contributors"
|
|
6
|
-
],
|
|
7
|
-
"description": "A Rust implementation of the Hypen engine",
|
|
8
|
-
"version": "0.4.37",
|
|
9
|
-
"license": "MIT",
|
|
10
|
-
"repository": {
|
|
11
|
-
"type": "git",
|
|
12
|
-
"url": "https://github.com/hypen-lang/hypen-engine-rs"
|
|
13
|
-
},
|
|
14
|
-
"files": [
|
|
15
|
-
"hypen_engine_bg.wasm",
|
|
16
|
-
"hypen_engine.js",
|
|
17
|
-
"hypen_engine.d.ts"
|
|
18
|
-
],
|
|
19
|
-
"main": "hypen_engine.js",
|
|
20
|
-
"types": "hypen_engine.d.ts",
|
|
21
|
-
"sideEffects": [
|
|
22
|
-
"./snippets/*"
|
|
23
|
-
]
|
|
24
|
-
}
|
package/wasm-node/README.md
DELETED
|
@@ -1,594 +0,0 @@
|
|
|
1
|
-
# Hypen Engine
|
|
2
|
-
|
|
3
|
-
[](https://www.rust-lang.org/)
|
|
4
|
-
[](https://webassembly.org/)
|
|
5
|
-
[](../LICENSE)
|
|
6
|
-
|
|
7
|
-
The core reactive rendering engine for Hypen, written in Rust. Compiles to WASM for web/desktop or native binaries with UniFFI for mobile platforms.
|
|
8
|
-
|
|
9
|
-
## Quick Start
|
|
10
|
-
|
|
11
|
-
### Rust
|
|
12
|
-
|
|
13
|
-
```rust
|
|
14
|
-
use hypen_engine::{Engine, ast_to_ir_node};
|
|
15
|
-
use hypen_parser::parse_component;
|
|
16
|
-
use serde_json::json;
|
|
17
|
-
|
|
18
|
-
let mut engine = Engine::new();
|
|
19
|
-
engine.set_render_callback(|patches| {
|
|
20
|
-
// Apply patches to your renderer
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
let ast = parse_component(r#"Column { Text("Hello") }"#)?;
|
|
24
|
-
engine.render_ir_node(&ast_to_ir_node(&ast));
|
|
25
|
-
engine.update_state(json!({ "count": 42 }));
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
### JavaScript/TypeScript (WASM)
|
|
29
|
-
|
|
30
|
-
```typescript
|
|
31
|
-
import init, { WasmEngine } from './wasm/hypen_engine.js';
|
|
32
|
-
await init();
|
|
33
|
-
|
|
34
|
-
const engine = new WasmEngine();
|
|
35
|
-
engine.setRenderCallback((patches) => applyPatches(patches));
|
|
36
|
-
engine.setModule('App', ['increment'], ['count'], { count: 0 });
|
|
37
|
-
engine.renderSource(`Column { Text("\${state.count}") }`);
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
See [BUILD_WASM.md](./BUILD_WASM.md) for detailed WASM build instructions.
|
|
41
|
-
|
|
42
|
-
## Overview
|
|
43
|
-
|
|
44
|
-
Hypen Engine is a platform-agnostic UI engine that:
|
|
45
|
-
- **Expands** Hypen DSL components into an intermediate representation (IR)
|
|
46
|
-
- **Tracks** reactive dependencies between state and UI nodes
|
|
47
|
-
- **Reconciles** UI trees efficiently using keyed diffing
|
|
48
|
-
- **Generates** minimal platform-agnostic patches for renderers
|
|
49
|
-
- **Routes** actions and events between UI and application logic
|
|
50
|
-
- **Serializes** for Remote UI scenarios (client-server streaming)
|
|
51
|
-
|
|
52
|
-
## Architecture
|
|
53
|
-
|
|
54
|
-
```
|
|
55
|
-
┌─────────────────────────────────────────────────────────┐
|
|
56
|
-
│ Hypen Engine │
|
|
57
|
-
├─────────────────────────────────────────────────────────┤
|
|
58
|
-
│ Parser → IR → Reactive Graph → Reconciler → Patches │
|
|
59
|
-
│ ↓ ↓ │
|
|
60
|
-
│ Component Registry Platform Renderer│
|
|
61
|
-
│ Dependency Tracking (Web/iOS/Android)│
|
|
62
|
-
│ State Management │
|
|
63
|
-
└─────────────────────────────────────────────────────────┘
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
### Core Systems
|
|
67
|
-
|
|
68
|
-
1. **IR & Component Expansion** (`src/ir/`)
|
|
69
|
-
- Canonical intermediate representation
|
|
70
|
-
- Component registry and resolution
|
|
71
|
-
- Props/slots expansion with defaults
|
|
72
|
-
- Stable NodeId generation
|
|
73
|
-
|
|
74
|
-
2. **Reactive System** (`src/reactive/`)
|
|
75
|
-
- Dependency graph tracking `${state.*}` bindings
|
|
76
|
-
- Dirty marking on state changes
|
|
77
|
-
- Scheduling for efficient updates
|
|
78
|
-
|
|
79
|
-
3. **Reconciliation** (`src/reconcile/`)
|
|
80
|
-
- Virtual instance tree (no platform objects)
|
|
81
|
-
- Keyed children diffing algorithm
|
|
82
|
-
- Minimal patch generation
|
|
83
|
-
|
|
84
|
-
4. **Patch Types** (Platform-agnostic):
|
|
85
|
-
- `Create(id, type, props)` - Create new node
|
|
86
|
-
- `SetProp(id, name, value)` - Update property
|
|
87
|
-
- `SetText(id, text)` - Update text content
|
|
88
|
-
- `Insert(parent, id, before?)` - Insert into tree
|
|
89
|
-
- `Move(parent, id, before?)` - Reorder node
|
|
90
|
-
- `Remove(id)` - Remove from tree
|
|
91
|
-
- Event handling is managed at the renderer level
|
|
92
|
-
|
|
93
|
-
5. **Action/Event Routing** (`src/dispatch/`)
|
|
94
|
-
- Map `@actions.*` to module handlers
|
|
95
|
-
- Forward UI events (click, input, etc.)
|
|
96
|
-
- Stable dispatch contract for SDKs
|
|
97
|
-
|
|
98
|
-
6. **Lifecycle Management** (`src/lifecycle/`)
|
|
99
|
-
- Module lifecycle (created/destroyed)
|
|
100
|
-
- Component lifecycle (mount/unmount)
|
|
101
|
-
- Resource cache (images/fonts) with pluggable fetcher
|
|
102
|
-
|
|
103
|
-
7. **Remote UI Serialization** (`src/serialize/`)
|
|
104
|
-
- Initial tree serialization
|
|
105
|
-
- Incremental patch streaming
|
|
106
|
-
- Revision tracking and optional integrity hashes
|
|
107
|
-
- JSON format support
|
|
108
|
-
|
|
109
|
-
## Usage
|
|
110
|
-
|
|
111
|
-
### Basic Example
|
|
112
|
-
|
|
113
|
-
```rust
|
|
114
|
-
use hypen_engine::{Engine, ir::{Element, Value, Component}};
|
|
115
|
-
use hypen_engine::reactive::parse_binding;
|
|
116
|
-
use indexmap::IndexMap;
|
|
117
|
-
use serde_json::json;
|
|
118
|
-
|
|
119
|
-
// Create engine
|
|
120
|
-
let mut engine = Engine::new();
|
|
121
|
-
|
|
122
|
-
// Register a custom component
|
|
123
|
-
// Note: In practice, you'd typically parse Hypen DSL with ast_to_ir_node
|
|
124
|
-
engine.register_component(Component::new("Greeting", |props: IndexMap<String, serde_json::Value>| {
|
|
125
|
-
Element::new("Text")
|
|
126
|
-
.with_prop("text", Value::Binding(
|
|
127
|
-
parse_binding("${state.name}").expect("valid binding")
|
|
128
|
-
))
|
|
129
|
-
}));
|
|
130
|
-
|
|
131
|
-
// Set render callback
|
|
132
|
-
engine.set_render_callback(|patches| {
|
|
133
|
-
for patch in patches {
|
|
134
|
-
println!("Patch: {:?}", patch);
|
|
135
|
-
}
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
// Register action handler
|
|
139
|
-
engine.on_action("greet", |action| {
|
|
140
|
-
println!("Hello from action: {:?}", action);
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
// Render UI
|
|
144
|
-
let ui = Element::new("Column")
|
|
145
|
-
.with_child(Element::new("Greeting"));
|
|
146
|
-
|
|
147
|
-
engine.render(&ui);
|
|
148
|
-
|
|
149
|
-
// Update state
|
|
150
|
-
engine.update_state(json!({
|
|
151
|
-
"name": "Alice"
|
|
152
|
-
}));
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
### With Module Host
|
|
156
|
-
|
|
157
|
-
```rust
|
|
158
|
-
use hypen_engine::lifecycle::{Module, ModuleInstance};
|
|
159
|
-
|
|
160
|
-
// Create module definition
|
|
161
|
-
let module = Module::new("ProfilePage")
|
|
162
|
-
.with_actions(vec!["signIn".to_string(), "signOut".to_string()])
|
|
163
|
-
.with_state_keys(vec!["user".to_string()])
|
|
164
|
-
.with_persist(true);
|
|
165
|
-
|
|
166
|
-
// Create module instance
|
|
167
|
-
let instance = ModuleInstance::new(
|
|
168
|
-
module,
|
|
169
|
-
json!({ "user": null })
|
|
170
|
-
);
|
|
171
|
-
|
|
172
|
-
engine.set_module(instance);
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
## Compilation Targets
|
|
176
|
-
|
|
177
|
-
### Native (Development)
|
|
178
|
-
|
|
179
|
-
```bash
|
|
180
|
-
cargo build
|
|
181
|
-
cargo test
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
### WASM (Web/Desktop)
|
|
185
|
-
|
|
186
|
-
The WASM build is fully functional and tested. See [BUILD_WASM.md](./BUILD_WASM.md) for detailed build instructions.
|
|
187
|
-
|
|
188
|
-
**Quick Start:**
|
|
189
|
-
|
|
190
|
-
```bash
|
|
191
|
-
# Install wasm-pack (one time)
|
|
192
|
-
cargo install wasm-pack
|
|
193
|
-
|
|
194
|
-
# Build for all WASM targets
|
|
195
|
-
./build-wasm.sh
|
|
196
|
-
|
|
197
|
-
# Or build manually for specific targets:
|
|
198
|
-
wasm-pack build --target bundler # For webpack/vite/rollup
|
|
199
|
-
wasm-pack build --target nodejs # For Node.js
|
|
200
|
-
wasm-pack build --target web # For vanilla JS
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
**Output directories:**
|
|
204
|
-
- `pkg/bundler/` - For use with bundlers (webpack, vite, rollup)
|
|
205
|
-
- `pkg/nodejs/` - For Node.js
|
|
206
|
-
- `pkg/web/` - For vanilla HTML/JS (see `example.html`)
|
|
207
|
-
|
|
208
|
-
**Build to custom directory:**
|
|
209
|
-
```bash
|
|
210
|
-
# Build directly to your renderer project
|
|
211
|
-
wasm-pack build --target bundler --out-dir ../hypen-render-bun/wasm
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
The WASM binary is optimized for size (~300KB) with LTO and size optimizations enabled.
|
|
215
|
-
|
|
216
|
-
### JavaScript/TypeScript API
|
|
217
|
-
|
|
218
|
-
The WASM build provides a `WasmEngine` class with a complete API:
|
|
219
|
-
|
|
220
|
-
```typescript
|
|
221
|
-
import init, { WasmEngine } from './pkg/web/hypen_engine.js';
|
|
222
|
-
|
|
223
|
-
// Initialize WASM (required before creating engine)
|
|
224
|
-
await init();
|
|
225
|
-
|
|
226
|
-
// Create engine instance
|
|
227
|
-
const engine = new WasmEngine();
|
|
228
|
-
|
|
229
|
-
// Set render callback to receive patches
|
|
230
|
-
engine.setRenderCallback((patches) => {
|
|
231
|
-
console.log('Patches:', patches);
|
|
232
|
-
// Apply patches to your platform renderer
|
|
233
|
-
applyPatchesToDOM(patches);
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
// Register action handlers
|
|
237
|
-
engine.onAction('increment', (action) => {
|
|
238
|
-
console.log('Action received:', action.name, action.payload);
|
|
239
|
-
// Handle action (e.g., update state)
|
|
240
|
-
engine.updateState({ count: action.payload.count + 1 });
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
// Initialize module with state and actions
|
|
244
|
-
engine.setModule(
|
|
245
|
-
'CounterModule', // Module name
|
|
246
|
-
['increment', 'decrement'], // Available actions
|
|
247
|
-
['count'], // State keys
|
|
248
|
-
{ count: 0 } // Initial state
|
|
249
|
-
);
|
|
250
|
-
|
|
251
|
-
// Render Hypen DSL source code
|
|
252
|
-
const source = `
|
|
253
|
-
Column {
|
|
254
|
-
Text("Count: \${state.count}")
|
|
255
|
-
Button("@actions.increment") { Text("+1") }
|
|
256
|
-
}
|
|
257
|
-
`;
|
|
258
|
-
engine.renderSource(source);
|
|
259
|
-
|
|
260
|
-
// Update state (triggers reactive re-render)
|
|
261
|
-
engine.updateState({ count: 42 });
|
|
262
|
-
|
|
263
|
-
// Dispatch action programmatically
|
|
264
|
-
engine.dispatchAction('increment', { amount: 1 });
|
|
265
|
-
|
|
266
|
-
// Get current revision number (for remote UI)
|
|
267
|
-
const revision = engine.getRevision();
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
**WasmEngine API Reference:**
|
|
271
|
-
|
|
272
|
-
- `constructor()` - Create a new engine instance
|
|
273
|
-
- `renderSource(source: string)` - Render Hypen DSL source code
|
|
274
|
-
- `setRenderCallback(callback: (patches: Patch[]) => void)` - Set patch callback
|
|
275
|
-
- `setModule(name, actions, stateKeys, initialState)` - Initialize module
|
|
276
|
-
- `updateState(patch: object)` - Update state and trigger re-render
|
|
277
|
-
- `dispatchAction(name: string, payload?: any)` - Dispatch an action
|
|
278
|
-
- `onAction(name: string, handler: (action: Action) => void)` - Register action handler
|
|
279
|
-
- `getRevision(): number` - Get current revision number
|
|
280
|
-
- `setComponentResolver(resolver: (name: string, context?: string) => ResolvedComponent | null)` - Set dynamic component resolver
|
|
281
|
-
|
|
282
|
-
See [BUILD_WASM.md](./BUILD_WASM.md) for more details and examples.
|
|
283
|
-
|
|
284
|
-
### Testing WASM Build
|
|
285
|
-
|
|
286
|
-
Open `example.html` in a web server:
|
|
287
|
-
|
|
288
|
-
```bash
|
|
289
|
-
# Using Python
|
|
290
|
-
python3 -m http.server 8000
|
|
291
|
-
|
|
292
|
-
# Using Node.js
|
|
293
|
-
npx serve .
|
|
294
|
-
|
|
295
|
-
# Then visit: http://localhost:8000/example.html
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
### Mobile (UniFFI)
|
|
299
|
-
|
|
300
|
-
UniFFI bindings for native mobile platforms are planned but not yet implemented.
|
|
301
|
-
|
|
302
|
-
```bash
|
|
303
|
-
# Future: Generate Swift/Kotlin bindings
|
|
304
|
-
cargo install uniffi_bindgen
|
|
305
|
-
uniffi-bindgen generate src/hypen_engine.udl --language swift
|
|
306
|
-
uniffi-bindgen generate src/hypen_engine.udl --language kotlin
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
For now, mobile platforms can use the WASM build via WebView or native WASM runtimes.
|
|
310
|
-
|
|
311
|
-
## Project Structure
|
|
312
|
-
|
|
313
|
-
```
|
|
314
|
-
hypen-engine-rs/
|
|
315
|
-
├── src/
|
|
316
|
-
│ ├── lib.rs # Public API exports
|
|
317
|
-
│ ├── engine.rs # Main Engine orchestrator
|
|
318
|
-
│ ├── wasm.rs # WASM bindings (wasm-bindgen)
|
|
319
|
-
│ ├── state.rs # State change tracking
|
|
320
|
-
│ ├── render.rs # Dirty node rendering
|
|
321
|
-
│ ├── logger.rs # Logging utilities
|
|
322
|
-
│ ├── ir/ # IR & component expansion
|
|
323
|
-
│ │ ├── mod.rs # Module exports
|
|
324
|
-
│ │ ├── node.rs # NodeId, Element, Props, Value
|
|
325
|
-
│ │ ├── component.rs # Component registry & resolution
|
|
326
|
-
│ │ ├── expand.rs # AST → IR lowering
|
|
327
|
-
│ │ └── children_slots_test.rs
|
|
328
|
-
│ ├── reactive/ # Reactive system
|
|
329
|
-
│ │ ├── mod.rs # Module exports
|
|
330
|
-
│ │ ├── binding.rs # ${state.*} parsing
|
|
331
|
-
│ │ ├── graph.rs # Dependency tracking
|
|
332
|
-
│ │ └── scheduler.rs # Dirty marking & scheduling
|
|
333
|
-
│ ├── reconcile/ # Reconciliation
|
|
334
|
-
│ │ ├── mod.rs # Module exports
|
|
335
|
-
│ │ ├── tree.rs # Instance tree (virtual DOM)
|
|
336
|
-
│ │ ├── diff.rs # Keyed diffing algorithm
|
|
337
|
-
│ │ └── patch.rs # Patch types
|
|
338
|
-
│ ├── dispatch/ # Events & actions
|
|
339
|
-
│ │ ├── mod.rs # Module exports
|
|
340
|
-
│ │ ├── action.rs # Action dispatcher
|
|
341
|
-
│ │ └── event.rs # Event router
|
|
342
|
-
│ ├── lifecycle/ # Lifecycle management
|
|
343
|
-
│ │ ├── mod.rs # Module exports
|
|
344
|
-
│ │ ├── module.rs # Module lifecycle
|
|
345
|
-
│ │ ├── component.rs # Component lifecycle
|
|
346
|
-
│ │ └── resource.rs # Resource cache
|
|
347
|
-
│ └── serialize/ # Serialization
|
|
348
|
-
│ ├── mod.rs # Module exports
|
|
349
|
-
│ └── remote.rs # Remote UI protocol
|
|
350
|
-
├── tests/ # Integration tests
|
|
351
|
-
├── Cargo.toml # Rust dependencies
|
|
352
|
-
├── build-wasm.sh # WASM build script
|
|
353
|
-
├── BUILD_WASM.md # Detailed WASM build docs
|
|
354
|
-
├── example.html # WASM demo page
|
|
355
|
-
└── README.md # This file
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
## Key Data Structures
|
|
359
|
-
|
|
360
|
-
### Element (IR Node)
|
|
361
|
-
```rust
|
|
362
|
-
pub struct Element {
|
|
363
|
-
pub element_type: String, // "Column", "Text", etc.
|
|
364
|
-
pub props: IndexMap<String, Value>, // Properties
|
|
365
|
-
pub children: Vec<Element>, // Child elements
|
|
366
|
-
pub key: Option<String>, // For reconciliation
|
|
367
|
-
// Note: Event handling is done at the renderer level, not in IR
|
|
368
|
-
}
|
|
369
|
-
```
|
|
370
|
-
|
|
371
|
-
### Value (Props)
|
|
372
|
-
```rust
|
|
373
|
-
pub enum Value {
|
|
374
|
-
Static(serde_json::Value), // Literal values
|
|
375
|
-
Binding(Binding), // Parsed ${state.user.name} binding
|
|
376
|
-
TemplateString { // Template with embedded bindings
|
|
377
|
-
template: String,
|
|
378
|
-
bindings: Vec<Binding>,
|
|
379
|
-
},
|
|
380
|
-
Action(String), // @actions.signIn
|
|
381
|
-
}
|
|
382
|
-
```
|
|
383
|
-
|
|
384
|
-
### Patch (Output)
|
|
385
|
-
```rust
|
|
386
|
-
pub enum Patch {
|
|
387
|
-
Create { id, element_type, props },
|
|
388
|
-
SetProp { id, name, value },
|
|
389
|
-
SetText { id, text },
|
|
390
|
-
Insert { parent_id, id, before_id? },
|
|
391
|
-
Move { parent_id, id, before_id? },
|
|
392
|
-
Remove { id },
|
|
393
|
-
// Note: Event handling is done at the renderer level
|
|
394
|
-
}
|
|
395
|
-
```
|
|
396
|
-
|
|
397
|
-
## Integration with Parser
|
|
398
|
-
|
|
399
|
-
The engine integrates with the Hypen parser from `../parser`:
|
|
400
|
-
|
|
401
|
-
```rust
|
|
402
|
-
use hypen_parser::parse_component;
|
|
403
|
-
use hypen_engine::ast_to_ir_node;
|
|
404
|
-
|
|
405
|
-
let source = r#"
|
|
406
|
-
Column {
|
|
407
|
-
Text("Hello, ${state.name}")
|
|
408
|
-
Button("@actions.greet") { Text("Greet") }
|
|
409
|
-
}
|
|
410
|
-
"#;
|
|
411
|
-
|
|
412
|
-
let ast = parse_component(source)?;
|
|
413
|
-
let ir_node = ast_to_ir_node(&ast); // Convert AST → IR
|
|
414
|
-
engine.render_ir_node(&ir_node);
|
|
415
|
-
```
|
|
416
|
-
|
|
417
|
-
### Full Example with Parser
|
|
418
|
-
|
|
419
|
-
```rust
|
|
420
|
-
use hypen_engine::{Engine, ast_to_ir_node};
|
|
421
|
-
use hypen_parser::parse_component;
|
|
422
|
-
use serde_json::json;
|
|
423
|
-
|
|
424
|
-
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
425
|
-
let mut engine = Engine::new();
|
|
426
|
-
|
|
427
|
-
// Set render callback
|
|
428
|
-
engine.set_render_callback(|patches| {
|
|
429
|
-
println!("Patches: {:#?}", patches);
|
|
430
|
-
});
|
|
431
|
-
|
|
432
|
-
// Parse Hypen DSL
|
|
433
|
-
let source = r#"
|
|
434
|
-
Column {
|
|
435
|
-
Text("Count: ${state.count}")
|
|
436
|
-
Button("@actions.increment") { Text("+1") }
|
|
437
|
-
}
|
|
438
|
-
"#;
|
|
439
|
-
|
|
440
|
-
let ast = parse_component(source)?;
|
|
441
|
-
let ir_node = ast_to_ir_node(&ast);
|
|
442
|
-
|
|
443
|
-
// Render
|
|
444
|
-
engine.render_ir_node(&ir_node);
|
|
445
|
-
|
|
446
|
-
// Update state
|
|
447
|
-
engine.update_state(json!({"count": 42}));
|
|
448
|
-
|
|
449
|
-
Ok(())
|
|
450
|
-
}
|
|
451
|
-
```
|
|
452
|
-
|
|
453
|
-
## Performance Considerations
|
|
454
|
-
|
|
455
|
-
- **Keyed reconciliation**: Use `key` props for list items to minimize DOM churn
|
|
456
|
-
- **Dependency tracking**: Only re-render nodes affected by state changes
|
|
457
|
-
- **Lazy evaluation**: Bindings are resolved on-demand during reconciliation
|
|
458
|
-
- **Resource caching**: Images/fonts are cached with configurable eviction
|
|
459
|
-
|
|
460
|
-
## Remote UI Protocol
|
|
461
|
-
|
|
462
|
-
For client-server streaming:
|
|
463
|
-
|
|
464
|
-
```json
|
|
465
|
-
// Initial tree (client connects)
|
|
466
|
-
{
|
|
467
|
-
"type": "initialTree",
|
|
468
|
-
"module": "ProfilePage",
|
|
469
|
-
"state": { "user": null },
|
|
470
|
-
"patches": [...],
|
|
471
|
-
"revision": 0
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
// State update (server → client)
|
|
475
|
-
{
|
|
476
|
-
"type": "stateUpdate",
|
|
477
|
-
"module": "ProfilePage",
|
|
478
|
-
"state": { "user": { "name": "Alice" } }
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
// Incremental patches (server → client)
|
|
482
|
-
{
|
|
483
|
-
"type": "patch",
|
|
484
|
-
"module": "ProfilePage",
|
|
485
|
-
"patches": [{ "type": "setProp", ... }],
|
|
486
|
-
"revision": 42
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
// Action dispatch (client → server)
|
|
490
|
-
{
|
|
491
|
-
"type": "dispatchAction",
|
|
492
|
-
"module": "ProfilePage",
|
|
493
|
-
"action": "signIn",
|
|
494
|
-
"payload": { "provider": "google" }
|
|
495
|
-
}
|
|
496
|
-
```
|
|
497
|
-
|
|
498
|
-
## Testing
|
|
499
|
-
|
|
500
|
-
```bash
|
|
501
|
-
# Run all tests
|
|
502
|
-
cargo test
|
|
503
|
-
|
|
504
|
-
# Run with output (useful for debugging)
|
|
505
|
-
cargo test -- --nocapture
|
|
506
|
-
|
|
507
|
-
# Test specific module
|
|
508
|
-
cargo test reactive::
|
|
509
|
-
|
|
510
|
-
# Test specific file
|
|
511
|
-
cargo test --test test_reactive_graph
|
|
512
|
-
|
|
513
|
-
# Run tests in parallel (default)
|
|
514
|
-
cargo test --jobs 4
|
|
515
|
-
```
|
|
516
|
-
|
|
517
|
-
The test suite includes:
|
|
518
|
-
- Unit tests for each module
|
|
519
|
-
- Integration tests for engine workflows
|
|
520
|
-
- WASM integration tests
|
|
521
|
-
- Reactive dependency tracking tests
|
|
522
|
-
- Reconciliation algorithm tests
|
|
523
|
-
|
|
524
|
-
## Contributing
|
|
525
|
-
|
|
526
|
-
This is part of the Hypen project. See the main repository for contribution guidelines.
|
|
527
|
-
|
|
528
|
-
## License
|
|
529
|
-
|
|
530
|
-
See main Hypen project for license information.
|
|
531
|
-
|
|
532
|
-
## API Reference
|
|
533
|
-
|
|
534
|
-
### Engine (Rust)
|
|
535
|
-
|
|
536
|
-
The main `Engine` struct provides the core functionality:
|
|
537
|
-
|
|
538
|
-
```rust
|
|
539
|
-
impl Engine {
|
|
540
|
-
pub fn new() -> Self;
|
|
541
|
-
pub fn register_component(&mut self, component: Component);
|
|
542
|
-
pub fn set_component_resolver<F>(&mut self, resolver: F);
|
|
543
|
-
pub fn set_module(&mut self, module: ModuleInstance);
|
|
544
|
-
pub fn set_render_callback<F>(&mut self, callback: F);
|
|
545
|
-
pub fn on_action<F>(&mut self, action_name: impl Into<String>, handler: F);
|
|
546
|
-
pub fn render(&mut self, element: &Element);
|
|
547
|
-
pub fn update_state(&mut self, state_patch: serde_json::Value);
|
|
548
|
-
pub fn notify_state_change(&mut self, change: &StateChange);
|
|
549
|
-
pub fn dispatch_action(&mut self, action: Action) -> Result<(), String>;
|
|
550
|
-
pub fn revision(&self) -> u64;
|
|
551
|
-
pub fn component_registry(&self) -> &ComponentRegistry;
|
|
552
|
-
pub fn resources(&self) -> &ResourceCache;
|
|
553
|
-
}
|
|
554
|
-
```
|
|
555
|
-
|
|
556
|
-
### Key Exports
|
|
557
|
-
|
|
558
|
-
```rust
|
|
559
|
-
pub use engine::Engine;
|
|
560
|
-
pub use ir::{ast_to_ir_node, Element, IRNode, Value};
|
|
561
|
-
pub use lifecycle::{Module, ModuleInstance};
|
|
562
|
-
pub use reconcile::Patch;
|
|
563
|
-
pub use state::StateChange;
|
|
564
|
-
```
|
|
565
|
-
|
|
566
|
-
---
|
|
567
|
-
|
|
568
|
-
## Status
|
|
569
|
-
|
|
570
|
-
**✅ Implemented:**
|
|
571
|
-
- Core reactive rendering engine
|
|
572
|
-
- Component expansion and registry
|
|
573
|
-
- Dependency tracking and dirty marking
|
|
574
|
-
- Keyed reconciliation algorithm
|
|
575
|
-
- Patch generation
|
|
576
|
-
- Action/event dispatch system
|
|
577
|
-
- Module lifecycle management
|
|
578
|
-
- Resource caching
|
|
579
|
-
- WASM bindings (fully functional)
|
|
580
|
-
- Remote UI serialization
|
|
581
|
-
|
|
582
|
-
---
|
|
583
|
-
|
|
584
|
-
## Related Documentation
|
|
585
|
-
|
|
586
|
-
- [Documentation Index](./docs/README.md) - Full documentation index
|
|
587
|
-
- [Control Flow Components](./docs/control-flow.md) - ForEach, When/If, Map usage guide
|
|
588
|
-
- [Router](./docs/router.md) - Declarative routing and navigation
|
|
589
|
-
- [Architecture Internals](./docs/architecture.md) - Reactive system, reconciliation, IR
|
|
590
|
-
- [Advanced SDK Usage](./docs/advanced-sdk-usage.md) - Custom renderers, component resolvers, Remote UI
|
|
591
|
-
- [Glossary](./docs/glossary.md) - Key terms and binding syntax reference
|
|
592
|
-
- [Browser Compatibility](./docs/browser-compatibility.md) - Browser, platform, and WASM target support
|
|
593
|
-
- [BUILD_WASM.md](./BUILD_WASM.md) - Detailed WASM build instructions
|
|
594
|
-
- [../parser/README.md](../parser/README.md) - Hypen parser documentation
|