@constela/compiler
v0.16.0
Published
Compiler for Constela UI framework - AST to Program transformation
Readme
@constela/compiler
Transforms Constela JSON programs into optimized runtime code.
Installation
npm install @constela/compilerUsage
constela compile app.constela.json --out dist/app.compiled.jsonJSON Input
{
"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" } }]
}
}Compiler Pipeline
The compiler transforms JSON programs through three passes:
- Validate - JSON Schema validation
- Analyze - Semantic analysis (state, actions, components, routes)
- Transform - AST to optimized runtime program
Supported Features
- 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
Component Local State
Components can define localState and localActions for instance-scoped state:
{
"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:
- Validates local state types and initial values
- Wraps component views with
localStatenodes - Transforms local actions with instance-scoped store references
- Handles param substitution within component views
CompiledProgram Structure
{
"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": { ... }
}Layout Compilation
Layouts are compiled separately with slot validation:
{
"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
Error Handling
Structured errors with JSON Pointer paths:
{
"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
Internal API
For framework developers only. End users should use the CLI.
compile
import { compile } from '@constela/compiler';
const result = compile(jsonInput);
if (result.ok) {
console.log(result.program);
} else {
console.error(result.errors);
}Individual Passes
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);Layout Compilation
import { analyzeLayoutPass, transformLayoutPass, composeLayoutWithPage } from '@constela/compiler';
const layoutResult = analyzeLayoutPass(layoutProgram);
const compiledLayout = transformLayoutPass(layoutProgram, layoutResult.context);
const composedProgram = composeLayoutWithPage(compiledLayout, compiledPage);License
MIT
