Compiler for Constela UI framework - AST to Program transformation
npm install @constela/compilerTransforms Constela JSON programs into optimized runtime code.
``bash`
npm install @constela/compiler
`bash`
constela compile app.constela.json --out dist/app.compiled.json
`json`
{
"version": "1.0",
"state": {
"count": { "type": "number", "initial": 0 }
},
"actions": [
{
"name": "increment",
"steps": [{ "do": "update", "target": "count", "operation": "increment" }]
}
],
"view": {
"kind": "element",
"tag": "button",
"props": { "onClick": { "event": "click", "action": "increment" } },
"children": [{ "kind": "text", "value": { "expr": "state", "name": "count" } }]
}
}
The compiler transforms JSON programs through three passes:
1. Validate - JSON Schema validation
2. Analyze - Semantic analysis (state, actions, components, routes)
3. Transform - AST to optimized runtime program
- setPath - Compiles to efficient path-based state updates
- Key-based each - Compiles key expressions for list diffing
- WebSocket connections - Compiles connection definitions and send/close actions
- concat expression - Compiles string concatenation expressions
- Object payloads - Supports object-shaped event handler payloads with expression fields
- call/lambda expressions - Compiles method calls and anonymous functions for array/string/Math/Date operations
- array expression - Compiles dynamic array construction from expressions
- localState/localActions - Component-scoped state with instance isolation
Components can define localState and localActions for instance-scoped state:
`json`
{
"components": {
"Accordion": {
"params": { "title": { "type": "string" } },
"localState": {
"isExpanded": { "type": "boolean", "initial": false }
},
"localActions": [
{
"name": "toggle",
"steps": [{ "do": "update", "target": "isExpanded", "operation": "toggle" }]
}
],
"view": { ... }
}
}
}
The compiler:
1. Validates local state types and initial values
2. Wraps component views with localState nodes
3. Transforms local actions with instance-scoped store references
4. Handles param substitution within component views
`json`
{
"version": "1.0",
"route": {
"path": "/users/:id",
"params": ["id"],
"title": { ... },
"layout": "MainLayout"
},
"lifecycle": {
"onMount": "loadData",
"onUnmount": "cleanup"
},
"state": {
"count": { "type": "number", "initial": 0 }
},
"connections": {
"chat": {
"type": "websocket",
"url": { ... },
"onMessage": { "action": "handleMessage" }
}
},
"actions": {
"increment": {
"name": "increment",
"steps": [{ "do": "update", "target": "count", "operation": "increment" }]
}
},
"view": { ... }
}
Layouts are compiled separately with slot validation:
`json`
{
"version": "1.0",
"type": "layout",
"view": {
"kind": "element",
"tag": "div",
"children": [
{ "kind": "component", "name": "Header" },
{ "kind": "slot" },
{ "kind": "component", "name": "Footer" }
]
}
}
Layout Validations:
- At least one slot exists
- No duplicate named slots
- No duplicate default slots
- Slots not inside loops
Structured errors with JSON Pointer paths:
`json`
{
"code": "UNDEFINED_STATE",
"message": "State \"count\" is not defined",
"path": "/view/children/0/props/onClick"
}
Error Codes:
- SCHEMA_INVALID - JSON Schema validation errorUNDEFINED_STATE
- - Reference to undefined stateUNDEFINED_ACTION
- - Reference to undefined actionDUPLICATE_ACTION
- - Duplicate action nameVAR_UNDEFINED
- - Undefined variable referenceCOMPONENT_NOT_FOUND
- - Undefined componentCOMPONENT_PROP_MISSING
- - Missing required propCOMPONENT_CYCLE
- - Circular component referenceOPERATION_INVALID_FOR_TYPE
- - Invalid operation for state typeLAYOUT_MISSING_SLOT
- - Layout missing slot nodeLAYOUT_NOT_FOUND
- - Referenced layout not found
> For framework developers only. End users should use the CLI.
`typescript
import { compile } from '@constela/compiler';
const result = compile(jsonInput);
if (result.ok) {
console.log(result.program);
} else {
console.error(result.errors);
}
`
`typescript
import { validatePass, analyzePass, transformPass } from '@constela/compiler';
// Step 1: Validate
const validated = validatePass(input);
// Step 2: Analyze
const analyzed = analyzePass(validated.program);
// Step 3: Transform
const compiled = transformPass(analyzed.program, analyzed.context);
`
`typescript
import { analyzeLayoutPass, transformLayoutPass, composeLayoutWithPage } from '@constela/compiler';
const layoutResult = analyzeLayoutPass(layoutProgram);
const compiledLayout = transformLayoutPass(layoutProgram, layoutResult.context);
const composedProgram = composeLayoutWithPage(compiledLayout, compiledPage);
``
MIT