@constela/compiler 0.9.0 → 0.10.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/README.md +15 -0
- package/dist/index.d.ts +27 -4
- package/dist/index.js +91 -8
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -45,6 +45,14 @@ The compiler transforms JSON programs through three passes:
|
|
|
45
45
|
2. **Analyze** - Semantic analysis (state, actions, components, routes)
|
|
46
46
|
3. **Transform** - AST to optimized runtime program
|
|
47
47
|
|
|
48
|
+
## Supported Features
|
|
49
|
+
|
|
50
|
+
- **setPath** - Compiles to efficient path-based state updates
|
|
51
|
+
- **Key-based each** - Compiles key expressions for list diffing
|
|
52
|
+
- **WebSocket connections** - Compiles connection definitions and send/close actions
|
|
53
|
+
- **concat expression** - Compiles string concatenation expressions
|
|
54
|
+
- **Object payloads** - Supports object-shaped event handler payloads with expression fields
|
|
55
|
+
|
|
48
56
|
## CompiledProgram Structure
|
|
49
57
|
|
|
50
58
|
```json
|
|
@@ -63,6 +71,13 @@ The compiler transforms JSON programs through three passes:
|
|
|
63
71
|
"state": {
|
|
64
72
|
"count": { "type": "number", "initial": 0 }
|
|
65
73
|
},
|
|
74
|
+
"connections": {
|
|
75
|
+
"chat": {
|
|
76
|
+
"type": "websocket",
|
|
77
|
+
"url": { ... },
|
|
78
|
+
"onMessage": { "action": "handleMessage" }
|
|
79
|
+
}
|
|
80
|
+
},
|
|
66
81
|
"actions": {
|
|
67
82
|
"increment": {
|
|
68
83
|
"name": "increment",
|
package/dist/index.d.ts
CHANGED
|
@@ -217,7 +217,26 @@ interface CompiledCloseStep {
|
|
|
217
217
|
do: 'close';
|
|
218
218
|
connection: string;
|
|
219
219
|
}
|
|
220
|
-
|
|
220
|
+
/**
|
|
221
|
+
* Compiled local action
|
|
222
|
+
*/
|
|
223
|
+
interface CompiledLocalAction {
|
|
224
|
+
name: string;
|
|
225
|
+
steps: CompiledActionStep[];
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Compiled local state node - wraps component with local state
|
|
229
|
+
*/
|
|
230
|
+
interface CompiledLocalStateNode {
|
|
231
|
+
kind: 'localState';
|
|
232
|
+
state: Record<string, {
|
|
233
|
+
type: string;
|
|
234
|
+
initial: unknown;
|
|
235
|
+
}>;
|
|
236
|
+
actions: Record<string, CompiledLocalAction>;
|
|
237
|
+
child: CompiledNode;
|
|
238
|
+
}
|
|
239
|
+
type CompiledNode = CompiledElementNode | CompiledTextNode | CompiledIfNode | CompiledEachNode | CompiledMarkdownNode | CompiledCodeNode | CompiledSlotNode | CompiledLocalStateNode;
|
|
221
240
|
interface CompiledElementNode {
|
|
222
241
|
kind: 'element';
|
|
223
242
|
tag: string;
|
|
@@ -256,7 +275,7 @@ interface CompiledSlotNode {
|
|
|
256
275
|
kind: 'slot';
|
|
257
276
|
name?: string;
|
|
258
277
|
}
|
|
259
|
-
type CompiledExpression = CompiledLitExpr | CompiledStateExpr | CompiledVarExpr | CompiledBinExpr | CompiledNotExpr | CompiledCondExpr | CompiledGetExpr | CompiledRouteExpr | CompiledImportExpr | CompiledDataExpr | CompiledRefExpr | CompiledIndexExpr | CompiledParamExpr | CompiledStyleExpr;
|
|
278
|
+
type CompiledExpression = CompiledLitExpr | CompiledStateExpr | CompiledVarExpr | CompiledBinExpr | CompiledNotExpr | CompiledCondExpr | CompiledGetExpr | CompiledRouteExpr | CompiledImportExpr | CompiledDataExpr | CompiledRefExpr | CompiledIndexExpr | CompiledParamExpr | CompiledStyleExpr | CompiledConcatExpr;
|
|
260
279
|
interface CompiledLitExpr {
|
|
261
280
|
expr: 'lit';
|
|
262
281
|
value: string | number | boolean | null | unknown[];
|
|
@@ -322,10 +341,14 @@ interface CompiledStyleExpr {
|
|
|
322
341
|
name: string;
|
|
323
342
|
variants?: Record<string, CompiledExpression>;
|
|
324
343
|
}
|
|
344
|
+
interface CompiledConcatExpr {
|
|
345
|
+
expr: 'concat';
|
|
346
|
+
items: CompiledExpression[];
|
|
347
|
+
}
|
|
325
348
|
interface CompiledEventHandler {
|
|
326
349
|
event: string;
|
|
327
350
|
action: string;
|
|
328
|
-
payload?: CompiledExpression
|
|
351
|
+
payload?: CompiledExpression | Record<string, CompiledExpression>;
|
|
329
352
|
}
|
|
330
353
|
/**
|
|
331
354
|
* Transforms the validated and analyzed AST into a CompiledProgram
|
|
@@ -455,4 +478,4 @@ declare function transformLayoutPass(layout: LayoutProgram, _context: LayoutAnal
|
|
|
455
478
|
*/
|
|
456
479
|
declare function composeLayoutWithPage(layout: CompiledProgram, page: CompiledProgram, layoutParams?: Record<string, Expression>, slots?: Record<string, ViewNode>): CompiledProgram;
|
|
457
480
|
|
|
458
|
-
export { type AnalysisContext, type AnalyzePassFailure, type AnalyzePassResult, type AnalyzePassSuccess, type CompileFailure, type CompileResult, type CompileSuccess, type CompiledAction, type CompiledActionStep, type CompiledBinExpr, type CompiledCallStep, type CompiledClipboardStep, type CompiledCloseStep, type CompiledCodeNode, type CompiledCondExpr, type CompiledDataExpr, type CompiledDisposeStep, type CompiledDomStep, type CompiledEachNode, type CompiledElementNode, type CompiledEventHandler, type CompiledExpression, type CompiledFetchStep, type CompiledGetExpr, type CompiledIfNode, type CompiledIfStep, type CompiledImportExpr, type CompiledImportStep, type CompiledIndexExpr, type CompiledLayoutProgram, type CompiledLifecycleHooks, type CompiledLitExpr, type CompiledMarkdownNode, type CompiledNavigateStep, type CompiledNode, type CompiledNotExpr, type CompiledProgram, type CompiledRefExpr, type CompiledRouteDefinition, type CompiledRouteExpr, type CompiledSendStep, type CompiledSetPathStep, type CompiledSetStep, type CompiledSlotNode, type CompiledStateExpr, type CompiledStorageStep, type CompiledSubscribeStep, type CompiledTextNode, type CompiledUpdateStep, type CompiledVarExpr, type LayoutAnalysisContext, type LayoutAnalysisFailure, type LayoutAnalysisResult, type LayoutAnalysisSuccess, type ValidatePassFailure, type ValidatePassResult, type ValidatePassSuccess, analyzeLayoutPass, analyzePass, compile, composeLayoutWithPage, transformLayoutPass, transformPass, validatePass };
|
|
481
|
+
export { type AnalysisContext, type AnalyzePassFailure, type AnalyzePassResult, type AnalyzePassSuccess, type CompileFailure, type CompileResult, type CompileSuccess, type CompiledAction, type CompiledActionStep, type CompiledBinExpr, type CompiledCallStep, type CompiledClipboardStep, type CompiledCloseStep, type CompiledCodeNode, type CompiledConcatExpr, type CompiledCondExpr, type CompiledDataExpr, type CompiledDisposeStep, type CompiledDomStep, type CompiledEachNode, type CompiledElementNode, type CompiledEventHandler, type CompiledExpression, type CompiledFetchStep, type CompiledGetExpr, type CompiledIfNode, type CompiledIfStep, type CompiledImportExpr, type CompiledImportStep, type CompiledIndexExpr, type CompiledLayoutProgram, type CompiledLifecycleHooks, type CompiledLitExpr, type CompiledLocalAction, type CompiledLocalStateNode, type CompiledMarkdownNode, type CompiledNavigateStep, type CompiledNode, type CompiledNotExpr, type CompiledParamExpr, type CompiledProgram, type CompiledRefExpr, type CompiledRouteDefinition, type CompiledRouteExpr, type CompiledSendStep, type CompiledSetPathStep, type CompiledSetStep, type CompiledSlotNode, type CompiledStateExpr, type CompiledStorageStep, type CompiledStyleExpr, type CompiledSubscribeStep, type CompiledTextNode, type CompiledUpdateStep, type CompiledVarExpr, type LayoutAnalysisContext, type LayoutAnalysisFailure, type LayoutAnalysisResult, type LayoutAnalysisSuccess, type ValidatePassFailure, type ValidatePassResult, type ValidatePassSuccess, analyzeLayoutPass, analyzePass, compile, composeLayoutWithPage, transformLayoutPass, transformPass, validatePass };
|
package/dist/index.js
CHANGED
|
@@ -44,6 +44,8 @@ import {
|
|
|
44
44
|
createUndefinedRefError,
|
|
45
45
|
createUndefinedStyleError,
|
|
46
46
|
createUndefinedVariantError,
|
|
47
|
+
createUndefinedLocalStateError,
|
|
48
|
+
createLocalActionInvalidStepError,
|
|
47
49
|
findSimilarNames,
|
|
48
50
|
isEventHandler,
|
|
49
51
|
DATA_SOURCE_TYPES,
|
|
@@ -157,12 +159,19 @@ function checkDuplicateActions(ast2) {
|
|
|
157
159
|
function validateExpression(expr, path, context, scope, paramScope) {
|
|
158
160
|
const errors = [];
|
|
159
161
|
switch (expr.expr) {
|
|
160
|
-
case "state":
|
|
161
|
-
|
|
162
|
-
|
|
162
|
+
case "state": {
|
|
163
|
+
const isGlobalState = context.stateNames.has(expr.name);
|
|
164
|
+
const isLocalState = paramScope?.localStateNames?.has(expr.name) ?? false;
|
|
165
|
+
if (!isGlobalState && !isLocalState) {
|
|
166
|
+
const availableNames = /* @__PURE__ */ new Set([
|
|
167
|
+
...context.stateNames,
|
|
168
|
+
...paramScope?.localStateNames ?? []
|
|
169
|
+
]);
|
|
170
|
+
const errorOptions = createErrorOptionsWithSuggestion(expr.name, availableNames);
|
|
163
171
|
errors.push(createUndefinedStateError(expr.name, path, errorOptions));
|
|
164
172
|
}
|
|
165
173
|
break;
|
|
174
|
+
}
|
|
166
175
|
case "var":
|
|
167
176
|
if (!scope.has(expr.name)) {
|
|
168
177
|
errors.push(createUndefinedVarError(expr.name, path));
|
|
@@ -706,8 +715,14 @@ function validateViewNode(node, path, context, scope, options = { insideComponen
|
|
|
706
715
|
for (const [propName, propValue] of Object.entries(node.props)) {
|
|
707
716
|
const propPath = buildPath(path, "props", propName);
|
|
708
717
|
if (isEventHandler(propValue)) {
|
|
709
|
-
|
|
710
|
-
|
|
718
|
+
const isGlobalAction = context.actionNames.has(propValue.action);
|
|
719
|
+
const isLocalAction = paramScope?.localActionNames?.has(propValue.action) ?? false;
|
|
720
|
+
if (!isGlobalAction && !isLocalAction) {
|
|
721
|
+
const availableNames = /* @__PURE__ */ new Set([
|
|
722
|
+
...context.actionNames,
|
|
723
|
+
...paramScope?.localActionNames ?? []
|
|
724
|
+
]);
|
|
725
|
+
const errorOptions = createErrorOptionsWithSuggestion(propValue.action, availableNames);
|
|
711
726
|
errors.push(createUndefinedActionError(propValue.action, propPath, errorOptions));
|
|
712
727
|
}
|
|
713
728
|
if (propValue.payload) {
|
|
@@ -910,21 +925,58 @@ function detectComponentCycles(programAst, context) {
|
|
|
910
925
|
}
|
|
911
926
|
return errors;
|
|
912
927
|
}
|
|
928
|
+
function validateLocalActions(localActions, localStateNames, componentPath) {
|
|
929
|
+
const errors = [];
|
|
930
|
+
for (let i = 0; i < localActions.length; i++) {
|
|
931
|
+
const action = localActions[i];
|
|
932
|
+
if (!action) continue;
|
|
933
|
+
const actionPath = buildPath(componentPath, "localActions", i);
|
|
934
|
+
for (let j = 0; j < action.steps.length; j++) {
|
|
935
|
+
const step = action.steps[j];
|
|
936
|
+
if (!step) continue;
|
|
937
|
+
const stepPath = buildPath(actionPath, "steps", j);
|
|
938
|
+
const stepDo = step.do;
|
|
939
|
+
if (stepDo !== "set" && stepDo !== "update" && stepDo !== "setPath") {
|
|
940
|
+
errors.push(createLocalActionInvalidStepError(stepDo, stepPath));
|
|
941
|
+
continue;
|
|
942
|
+
}
|
|
943
|
+
if (!localStateNames.has(step.target)) {
|
|
944
|
+
const errorOptions = createErrorOptionsWithSuggestion(step.target, localStateNames);
|
|
945
|
+
errors.push(createUndefinedLocalStateError(step.target, buildPath(stepPath, "target"), errorOptions));
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
return errors;
|
|
950
|
+
}
|
|
913
951
|
function validateComponents(programAst, context) {
|
|
914
952
|
const errors = [];
|
|
915
953
|
if (!programAst.components) return errors;
|
|
916
954
|
for (const [name, def] of Object.entries(programAst.components)) {
|
|
955
|
+
const componentPath = buildPath("", "components", name);
|
|
956
|
+
const localStateNames = new Set(
|
|
957
|
+
def.localState ? Object.keys(def.localState) : []
|
|
958
|
+
);
|
|
959
|
+
const localActionNames = new Set(
|
|
960
|
+
def.localActions ? def.localActions.map((a) => a.name) : []
|
|
961
|
+
);
|
|
917
962
|
const paramNames = new Set(
|
|
918
963
|
def.params ? Object.keys(def.params) : []
|
|
919
964
|
);
|
|
920
965
|
const paramScope = {
|
|
921
966
|
params: paramNames,
|
|
922
|
-
componentName: name
|
|
967
|
+
componentName: name,
|
|
968
|
+
localStateNames,
|
|
969
|
+
localActionNames
|
|
923
970
|
};
|
|
971
|
+
if (def.localActions && def.localActions.length > 0) {
|
|
972
|
+
errors.push(
|
|
973
|
+
...validateLocalActions(def.localActions, localStateNames, componentPath)
|
|
974
|
+
);
|
|
975
|
+
}
|
|
924
976
|
errors.push(
|
|
925
977
|
...validateViewNode(
|
|
926
978
|
def.view,
|
|
927
|
-
buildPath(
|
|
979
|
+
buildPath(componentPath, "view"),
|
|
928
980
|
context,
|
|
929
981
|
/* @__PURE__ */ new Set(),
|
|
930
982
|
{ insideComponent: true, paramScope }
|
|
@@ -1178,6 +1230,11 @@ function transformExpression(expr, ctx) {
|
|
|
1178
1230
|
}
|
|
1179
1231
|
return styleExpr;
|
|
1180
1232
|
}
|
|
1233
|
+
case "concat":
|
|
1234
|
+
return {
|
|
1235
|
+
expr: "concat",
|
|
1236
|
+
items: expr.items.map((item) => transformExpression(item, ctx))
|
|
1237
|
+
};
|
|
1181
1238
|
}
|
|
1182
1239
|
}
|
|
1183
1240
|
function transformEventHandler(handler, ctx) {
|
|
@@ -1475,7 +1532,16 @@ function transformViewNode(node, ctx) {
|
|
|
1475
1532
|
currentParams: params,
|
|
1476
1533
|
currentChildren: children
|
|
1477
1534
|
};
|
|
1478
|
-
|
|
1535
|
+
const expandedView = transformViewNode(def.view, newCtx);
|
|
1536
|
+
if (def.localState && Object.keys(def.localState).length > 0) {
|
|
1537
|
+
return {
|
|
1538
|
+
kind: "localState",
|
|
1539
|
+
state: transformLocalState(def.localState),
|
|
1540
|
+
actions: transformLocalActions(def.localActions ?? []),
|
|
1541
|
+
child: expandedView
|
|
1542
|
+
};
|
|
1543
|
+
}
|
|
1544
|
+
return expandedView;
|
|
1479
1545
|
}
|
|
1480
1546
|
case "markdown":
|
|
1481
1547
|
return {
|
|
@@ -1514,6 +1580,23 @@ function transformState(state) {
|
|
|
1514
1580
|
}
|
|
1515
1581
|
return compiledState;
|
|
1516
1582
|
}
|
|
1583
|
+
function transformLocalState(localState) {
|
|
1584
|
+
const result = {};
|
|
1585
|
+
for (const [name, field] of Object.entries(localState)) {
|
|
1586
|
+
result[name] = { type: field.type, initial: field.initial };
|
|
1587
|
+
}
|
|
1588
|
+
return result;
|
|
1589
|
+
}
|
|
1590
|
+
function transformLocalActions(localActions) {
|
|
1591
|
+
const result = {};
|
|
1592
|
+
for (const action of localActions) {
|
|
1593
|
+
result[action.name] = {
|
|
1594
|
+
name: action.name,
|
|
1595
|
+
steps: action.steps.map(transformActionStep)
|
|
1596
|
+
};
|
|
1597
|
+
}
|
|
1598
|
+
return result;
|
|
1599
|
+
}
|
|
1517
1600
|
function transformActions(actions) {
|
|
1518
1601
|
const compiledActions = {};
|
|
1519
1602
|
for (const action of actions) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@constela/compiler",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Compiler for Constela UI framework - AST to Program transformation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"dist"
|
|
16
16
|
],
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@constela/core": "0.
|
|
18
|
+
"@constela/core": "0.10.0"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@types/node": "^20.10.0",
|