@constela/compiler 0.5.0 → 0.6.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/dist/index.d.ts CHANGED
@@ -19,6 +19,7 @@ interface AnalysisContext {
19
19
  routeParams: Set<string>;
20
20
  importNames: Set<string>;
21
21
  dataNames: Set<string>;
22
+ refNames: Set<string>;
22
23
  }
23
24
  interface AnalyzePassSuccess {
24
25
  ok: true;
@@ -86,7 +87,7 @@ interface CompiledAction {
86
87
  name: string;
87
88
  steps: CompiledActionStep[];
88
89
  }
89
- type CompiledActionStep = CompiledSetStep | CompiledUpdateStep | CompiledFetchStep | CompiledStorageStep | CompiledClipboardStep | CompiledNavigateStep;
90
+ type CompiledActionStep = CompiledSetStep | CompiledUpdateStep | CompiledFetchStep | CompiledStorageStep | CompiledClipboardStep | CompiledNavigateStep | CompiledImportStep | CompiledCallStep | CompiledSubscribeStep | CompiledDisposeStep;
90
91
  interface CompiledSetStep {
91
92
  do: 'set';
92
93
  target: string;
@@ -133,10 +134,55 @@ interface CompiledNavigateStep {
133
134
  target?: '_self' | '_blank';
134
135
  replace?: boolean;
135
136
  }
137
+ /**
138
+ * Compiled ref expression
139
+ */
140
+ interface CompiledRefExpr {
141
+ expr: 'ref';
142
+ name: string;
143
+ }
144
+ /**
145
+ * Compiled import step
146
+ */
147
+ interface CompiledImportStep {
148
+ do: 'import';
149
+ module: string;
150
+ result: string;
151
+ onSuccess?: CompiledActionStep[];
152
+ onError?: CompiledActionStep[];
153
+ }
154
+ /**
155
+ * Compiled call step
156
+ */
157
+ interface CompiledCallStep {
158
+ do: 'call';
159
+ target: CompiledExpression;
160
+ args?: CompiledExpression[];
161
+ result?: string;
162
+ onSuccess?: CompiledActionStep[];
163
+ onError?: CompiledActionStep[];
164
+ }
165
+ /**
166
+ * Compiled subscribe step
167
+ */
168
+ interface CompiledSubscribeStep {
169
+ do: 'subscribe';
170
+ target: CompiledExpression;
171
+ event: string;
172
+ action: string;
173
+ }
174
+ /**
175
+ * Compiled dispose step
176
+ */
177
+ interface CompiledDisposeStep {
178
+ do: 'dispose';
179
+ target: CompiledExpression;
180
+ }
136
181
  type CompiledNode = CompiledElementNode | CompiledTextNode | CompiledIfNode | CompiledEachNode | CompiledMarkdownNode | CompiledCodeNode;
137
182
  interface CompiledElementNode {
138
183
  kind: 'element';
139
184
  tag: string;
185
+ ref?: string;
140
186
  props?: Record<string, CompiledExpression | CompiledEventHandler>;
141
187
  children?: CompiledNode[];
142
188
  }
@@ -167,7 +213,7 @@ interface CompiledCodeNode {
167
213
  language: CompiledExpression;
168
214
  content: CompiledExpression;
169
215
  }
170
- type CompiledExpression = CompiledLitExpr | CompiledStateExpr | CompiledVarExpr | CompiledBinExpr | CompiledNotExpr | CompiledCondExpr | CompiledGetExpr | CompiledRouteExpr | CompiledImportExpr;
216
+ type CompiledExpression = CompiledLitExpr | CompiledStateExpr | CompiledVarExpr | CompiledBinExpr | CompiledNotExpr | CompiledCondExpr | CompiledGetExpr | CompiledRouteExpr | CompiledImportExpr | CompiledRefExpr;
171
217
  interface CompiledLitExpr {
172
218
  expr: 'lit';
173
219
  value: string | number | boolean | null | unknown[];
@@ -344,4 +390,4 @@ declare function transformLayoutPass(layout: LayoutProgram, _context: LayoutAnal
344
390
  */
345
391
  declare function composeLayoutWithPage(layout: CompiledProgram, page: CompiledProgram, slots?: Record<string, ViewNode>): CompiledProgram;
346
392
 
347
- export { type AnalysisContext, type AnalyzePassFailure, type AnalyzePassResult, type AnalyzePassSuccess, type CompileFailure, type CompileResult, type CompileSuccess, type CompiledAction, type CompiledActionStep, type CompiledClipboardStep, type CompiledCodeNode, type CompiledEachNode, type CompiledElementNode, type CompiledEventHandler, type CompiledExpression, type CompiledFetchStep, type CompiledIfNode, type CompiledImportExpr, type CompiledLayoutProgram, type CompiledLifecycleHooks, type CompiledMarkdownNode, type CompiledNavigateStep, type CompiledNode, type CompiledProgram, type CompiledRouteDefinition, type CompiledRouteExpr, type CompiledSetStep, type CompiledStorageStep, type CompiledTextNode, type CompiledUpdateStep, type LayoutAnalysisContext, type LayoutAnalysisFailure, type LayoutAnalysisResult, type LayoutAnalysisSuccess, type ValidatePassFailure, type ValidatePassResult, type ValidatePassSuccess, analyzeLayoutPass, analyzePass, compile, composeLayoutWithPage, transformLayoutPass, transformPass, validatePass };
393
+ export { type AnalysisContext, type AnalyzePassFailure, type AnalyzePassResult, type AnalyzePassSuccess, type CompileFailure, type CompileResult, type CompileSuccess, type CompiledAction, type CompiledActionStep, type CompiledCallStep, type CompiledClipboardStep, type CompiledCodeNode, type CompiledDisposeStep, type CompiledEachNode, type CompiledElementNode, type CompiledEventHandler, type CompiledExpression, type CompiledFetchStep, type CompiledIfNode, type CompiledImportExpr, type CompiledImportStep, type CompiledLayoutProgram, type CompiledLifecycleHooks, type CompiledMarkdownNode, type CompiledNavigateStep, type CompiledNode, type CompiledProgram, type CompiledRefExpr, type CompiledRouteDefinition, type CompiledRouteExpr, type CompiledSetStep, type CompiledStorageStep, type CompiledSubscribeStep, type CompiledTextNode, type CompiledUpdateStep, 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
@@ -41,6 +41,7 @@ import {
41
41
  createInvalidClipboardOperationError,
42
42
  createClipboardWriteMissingValueError,
43
43
  createInvalidNavigateTargetError,
44
+ createUndefinedRefError,
44
45
  isEventHandler,
45
46
  DATA_SOURCE_TYPES,
46
47
  DATA_TRANSFORMS,
@@ -62,22 +63,68 @@ function extractRouteParams(path) {
62
63
  }
63
64
  return params;
64
65
  }
65
- function collectContext(ast2) {
66
- const stateNames = new Set(Object.keys(ast2.state));
67
- const actionNames = new Set(ast2.actions.map((a) => a.name));
66
+ function collectRefs(node) {
67
+ const refs = /* @__PURE__ */ new Set();
68
+ switch (node.kind) {
69
+ case "element":
70
+ if (node.ref) {
71
+ refs.add(node.ref);
72
+ }
73
+ if (node.children) {
74
+ for (const child of node.children) {
75
+ for (const ref of collectRefs(child)) {
76
+ refs.add(ref);
77
+ }
78
+ }
79
+ }
80
+ break;
81
+ case "if":
82
+ for (const ref of collectRefs(node.then)) {
83
+ refs.add(ref);
84
+ }
85
+ if (node.else) {
86
+ for (const ref of collectRefs(node.else)) {
87
+ refs.add(ref);
88
+ }
89
+ }
90
+ break;
91
+ case "each":
92
+ for (const ref of collectRefs(node.body)) {
93
+ refs.add(ref);
94
+ }
95
+ break;
96
+ case "component":
97
+ if (node.children) {
98
+ for (const child of node.children) {
99
+ for (const ref of collectRefs(child)) {
100
+ refs.add(ref);
101
+ }
102
+ }
103
+ }
104
+ break;
105
+ case "text":
106
+ case "slot":
107
+ break;
108
+ }
109
+ return refs;
110
+ }
111
+ function collectContext(programAst) {
112
+ const stateNames = new Set(Object.keys(programAst.state));
113
+ const actionNames = new Set(programAst.actions.map((a) => a.name));
68
114
  const componentNames = new Set(
69
- ast2.components ? Object.keys(ast2.components) : []
115
+ programAst.components ? Object.keys(programAst.components) : []
70
116
  );
71
117
  const routeParams = new Set(
72
- ast2.route ? extractRouteParams(ast2.route.path) : []
118
+ programAst.route ? extractRouteParams(programAst.route.path) : []
73
119
  );
74
120
  const importNames = new Set(
75
- ast2.imports ? Object.keys(ast2.imports) : []
121
+ programAst.imports ? Object.keys(programAst.imports) : []
76
122
  );
77
123
  const dataNames = new Set(
78
- ast2.data ? Object.keys(ast2.data) : []
124
+ programAst.data ? Object.keys(programAst.data) : []
79
125
  );
80
- return { stateNames, actionNames, componentNames, routeParams, importNames, dataNames };
126
+ const refNames = collectRefs(programAst.view);
127
+ return { stateNames, actionNames, componentNames, routeParams, importNames, dataNames, refNames };
81
128
  }
82
129
  function checkDuplicateActions(ast2) {
83
130
  const errors = [];
@@ -137,6 +184,12 @@ function validateExpression(expr, path, context, scope, paramScope) {
137
184
  }
138
185
  break;
139
186
  }
187
+ case "ref": {
188
+ if (!context.refNames.has(expr.name)) {
189
+ errors.push(createUndefinedRefError(expr.name, path));
190
+ }
191
+ break;
192
+ }
140
193
  case "bin":
141
194
  errors.push(...validateExpression(expr.left, buildPath(path, "left"), context, scope, paramScope));
142
195
  errors.push(...validateExpression(expr.right, buildPath(path, "right"), context, scope, paramScope));
@@ -322,6 +375,79 @@ function validateActionStep(step, path, context) {
322
375
  }
323
376
  break;
324
377
  }
378
+ case "import": {
379
+ const importStep = step;
380
+ if (importStep.onSuccess) {
381
+ for (let i = 0; i < importStep.onSuccess.length; i++) {
382
+ const successStep = importStep.onSuccess[i];
383
+ if (successStep === void 0) continue;
384
+ errors.push(
385
+ ...validateActionStep(successStep, buildPath(path, "onSuccess", i), context)
386
+ );
387
+ }
388
+ }
389
+ if (importStep.onError) {
390
+ for (let i = 0; i < importStep.onError.length; i++) {
391
+ const errorStep = importStep.onError[i];
392
+ if (errorStep === void 0) continue;
393
+ errors.push(
394
+ ...validateActionStep(errorStep, buildPath(path, "onError", i), context)
395
+ );
396
+ }
397
+ }
398
+ break;
399
+ }
400
+ case "call": {
401
+ const callStep = step;
402
+ errors.push(
403
+ ...validateExpressionStateOnly(callStep.target, buildPath(path, "target"), context)
404
+ );
405
+ if (callStep.args) {
406
+ for (let i = 0; i < callStep.args.length; i++) {
407
+ const arg = callStep.args[i];
408
+ if (arg === void 0) continue;
409
+ errors.push(
410
+ ...validateExpressionStateOnly(arg, buildPath(path, "args", i), context)
411
+ );
412
+ }
413
+ }
414
+ if (callStep.onSuccess) {
415
+ for (let i = 0; i < callStep.onSuccess.length; i++) {
416
+ const successStep = callStep.onSuccess[i];
417
+ if (successStep === void 0) continue;
418
+ errors.push(
419
+ ...validateActionStep(successStep, buildPath(path, "onSuccess", i), context)
420
+ );
421
+ }
422
+ }
423
+ if (callStep.onError) {
424
+ for (let i = 0; i < callStep.onError.length; i++) {
425
+ const errorStep = callStep.onError[i];
426
+ if (errorStep === void 0) continue;
427
+ errors.push(
428
+ ...validateActionStep(errorStep, buildPath(path, "onError", i), context)
429
+ );
430
+ }
431
+ }
432
+ break;
433
+ }
434
+ case "subscribe": {
435
+ const subscribeStep = step;
436
+ errors.push(
437
+ ...validateExpressionStateOnly(subscribeStep.target, buildPath(path, "target"), context)
438
+ );
439
+ if (!context.actionNames.has(subscribeStep.action)) {
440
+ errors.push(createUndefinedActionError(subscribeStep.action, buildPath(path, "action")));
441
+ }
442
+ break;
443
+ }
444
+ case "dispose": {
445
+ const disposeStep = step;
446
+ errors.push(
447
+ ...validateExpressionStateOnly(disposeStep.target, buildPath(path, "target"), context)
448
+ );
449
+ break;
450
+ }
325
451
  }
326
452
  return errors;
327
453
  }
@@ -362,6 +488,12 @@ function validateExpressionStateOnly(expr, path, context) {
362
488
  }
363
489
  break;
364
490
  }
491
+ case "ref": {
492
+ if (!context.refNames.has(expr.name)) {
493
+ errors.push(createUndefinedRefError(expr.name, path));
494
+ }
495
+ break;
496
+ }
365
497
  case "bin":
366
498
  errors.push(...validateExpressionStateOnly(expr.left, buildPath(path, "left"), context));
367
499
  errors.push(...validateExpressionStateOnly(expr.right, buildPath(path, "right"), context));
@@ -421,6 +553,12 @@ function validateExpressionInEventPayload(expr, path, context, scope) {
421
553
  }
422
554
  break;
423
555
  }
556
+ case "ref": {
557
+ if (!context.refNames.has(expr.name)) {
558
+ errors.push(createUndefinedRefError(expr.name, path));
559
+ }
560
+ break;
561
+ }
424
562
  case "bin":
425
563
  errors.push(
426
564
  ...validateExpressionInEventPayload(expr.left, buildPath(path, "left"), context, scope)
@@ -912,6 +1050,8 @@ function transformExpression(expr, ctx) {
912
1050
  }
913
1051
  return dataExpr;
914
1052
  }
1053
+ case "ref":
1054
+ return { expr: "ref", name: expr.name };
915
1055
  }
916
1056
  }
917
1057
  function transformEventHandler(handler, ctx) {
@@ -1028,6 +1168,57 @@ function transformActionStep(step) {
1028
1168
  }
1029
1169
  return compiledNavigateStep;
1030
1170
  }
1171
+ case "import": {
1172
+ const importStep = step;
1173
+ const compiledImportStep = {
1174
+ do: "import",
1175
+ module: importStep.module,
1176
+ result: importStep.result
1177
+ };
1178
+ if (importStep.onSuccess) {
1179
+ compiledImportStep.onSuccess = importStep.onSuccess.map(transformActionStep);
1180
+ }
1181
+ if (importStep.onError) {
1182
+ compiledImportStep.onError = importStep.onError.map(transformActionStep);
1183
+ }
1184
+ return compiledImportStep;
1185
+ }
1186
+ case "call": {
1187
+ const callStep = step;
1188
+ const compiledCallStep = {
1189
+ do: "call",
1190
+ target: transformExpression(callStep.target, emptyContext)
1191
+ };
1192
+ if (callStep.args) {
1193
+ compiledCallStep.args = callStep.args.map((arg) => transformExpression(arg, emptyContext));
1194
+ }
1195
+ if (callStep.result) {
1196
+ compiledCallStep.result = callStep.result;
1197
+ }
1198
+ if (callStep.onSuccess) {
1199
+ compiledCallStep.onSuccess = callStep.onSuccess.map(transformActionStep);
1200
+ }
1201
+ if (callStep.onError) {
1202
+ compiledCallStep.onError = callStep.onError.map(transformActionStep);
1203
+ }
1204
+ return compiledCallStep;
1205
+ }
1206
+ case "subscribe": {
1207
+ const subscribeStep = step;
1208
+ return {
1209
+ do: "subscribe",
1210
+ target: transformExpression(subscribeStep.target, emptyContext),
1211
+ event: subscribeStep.event,
1212
+ action: subscribeStep.action
1213
+ };
1214
+ }
1215
+ case "dispose": {
1216
+ const disposeStep = step;
1217
+ return {
1218
+ do: "dispose",
1219
+ target: transformExpression(disposeStep.target, emptyContext)
1220
+ };
1221
+ }
1031
1222
  }
1032
1223
  }
1033
1224
  function flattenSlotChildren(children, ctx) {
@@ -1050,6 +1241,9 @@ function transformViewNode(node, ctx) {
1050
1241
  kind: "element",
1051
1242
  tag: node.tag
1052
1243
  };
1244
+ if (node.ref) {
1245
+ compiledElement.ref = node.ref;
1246
+ }
1053
1247
  if (node.props) {
1054
1248
  compiledElement.props = {};
1055
1249
  for (const [propName, propValue] of Object.entries(node.props)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@constela/compiler",
3
- "version": "0.5.0",
3
+ "version": "0.6.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.5.0"
18
+ "@constela/core": "0.6.0"
19
19
  },
20
20
  "devDependencies": {
21
21
  "@types/node": "^20.10.0",