@constela/core 0.1.0 → 0.3.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 +342 -7
- package/dist/index.js +337 -14
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -6,10 +6,16 @@
|
|
|
6
6
|
*/
|
|
7
7
|
declare const BINARY_OPERATORS: readonly ["+", "-", "*", "/", "==", "!=", "<", "<=", ">", ">=", "&&", "||"];
|
|
8
8
|
type BinaryOperator = (typeof BINARY_OPERATORS)[number];
|
|
9
|
-
declare const UPDATE_OPERATIONS: readonly ["increment", "decrement", "push", "pop", "remove"];
|
|
9
|
+
declare const UPDATE_OPERATIONS: readonly ["increment", "decrement", "push", "pop", "remove", "toggle", "merge", "replaceAt", "insertAt", "splice"];
|
|
10
10
|
type UpdateOperation = (typeof UPDATE_OPERATIONS)[number];
|
|
11
11
|
declare const HTTP_METHODS: readonly ["GET", "POST", "PUT", "DELETE"];
|
|
12
12
|
type HttpMethod = (typeof HTTP_METHODS)[number];
|
|
13
|
+
declare const PARAM_TYPES: readonly ["string", "number", "boolean", "json"];
|
|
14
|
+
type ParamType = (typeof PARAM_TYPES)[number];
|
|
15
|
+
interface ParamDef {
|
|
16
|
+
type: ParamType;
|
|
17
|
+
required?: boolean;
|
|
18
|
+
}
|
|
13
19
|
/**
|
|
14
20
|
* Literal expression - represents a constant value
|
|
15
21
|
*/
|
|
@@ -48,7 +54,32 @@ interface NotExpr {
|
|
|
48
54
|
expr: 'not';
|
|
49
55
|
operand: Expression;
|
|
50
56
|
}
|
|
51
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Param expression - references a component parameter
|
|
59
|
+
*/
|
|
60
|
+
interface ParamExpr {
|
|
61
|
+
expr: 'param';
|
|
62
|
+
name: string;
|
|
63
|
+
path?: string;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Cond expression - conditional if/then/else
|
|
67
|
+
*/
|
|
68
|
+
interface CondExpr {
|
|
69
|
+
expr: 'cond';
|
|
70
|
+
if: Expression;
|
|
71
|
+
then: Expression;
|
|
72
|
+
else: Expression;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Get expression - property access
|
|
76
|
+
*/
|
|
77
|
+
interface GetExpr {
|
|
78
|
+
expr: 'get';
|
|
79
|
+
base: Expression;
|
|
80
|
+
path: string;
|
|
81
|
+
}
|
|
82
|
+
type Expression = LitExpr | StateExpr | VarExpr | BinExpr | NotExpr | ParamExpr | CondExpr | GetExpr;
|
|
52
83
|
/**
|
|
53
84
|
* Number state field
|
|
54
85
|
*/
|
|
@@ -70,7 +101,21 @@ interface ListField {
|
|
|
70
101
|
type: 'list';
|
|
71
102
|
initial: unknown[];
|
|
72
103
|
}
|
|
73
|
-
|
|
104
|
+
/**
|
|
105
|
+
* Boolean state field
|
|
106
|
+
*/
|
|
107
|
+
interface BooleanField {
|
|
108
|
+
type: 'boolean';
|
|
109
|
+
initial: boolean;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Object state field
|
|
113
|
+
*/
|
|
114
|
+
interface ObjectField {
|
|
115
|
+
type: 'object';
|
|
116
|
+
initial: Record<string, unknown>;
|
|
117
|
+
}
|
|
118
|
+
type StateField = NumberField | StringField | ListField | BooleanField | ObjectField;
|
|
74
119
|
/**
|
|
75
120
|
* Set step - sets a state field to a new value
|
|
76
121
|
*/
|
|
@@ -81,12 +126,31 @@ interface SetStep {
|
|
|
81
126
|
}
|
|
82
127
|
/**
|
|
83
128
|
* Update step - performs an operation on a state field
|
|
129
|
+
*
|
|
130
|
+
* Operations and their required fields:
|
|
131
|
+
* - increment/decrement: Numeric operations. Optional `value` for amount (default: 1)
|
|
132
|
+
* - push: Add item to array. Requires `value`
|
|
133
|
+
* - pop: Remove last item from array. No additional fields
|
|
134
|
+
* - remove: Remove item from array by value or index. Requires `value`
|
|
135
|
+
* - toggle: Flip boolean value. No additional fields
|
|
136
|
+
* - merge: Shallow merge object. Requires `value` (object)
|
|
137
|
+
* - replaceAt: Replace array item at index. Requires `index` and `value`
|
|
138
|
+
* - insertAt: Insert item at array index. Requires `index` and `value`
|
|
139
|
+
* - splice: Delete and/or insert items. Requires `index` and `deleteCount`, optional `value` (array)
|
|
140
|
+
*
|
|
141
|
+
* @property target - The state field name to update
|
|
142
|
+
* @property operation - The update operation to perform
|
|
143
|
+
* @property value - Value for push/merge/replaceAt/insertAt/splice operations
|
|
144
|
+
* @property index - Array index for replaceAt/insertAt/splice operations
|
|
145
|
+
* @property deleteCount - Number of items to delete for splice operation
|
|
84
146
|
*/
|
|
85
147
|
interface UpdateStep {
|
|
86
148
|
do: 'update';
|
|
87
149
|
target: string;
|
|
88
150
|
operation: UpdateOperation;
|
|
89
151
|
value?: Expression;
|
|
152
|
+
index?: Expression;
|
|
153
|
+
deleteCount?: Expression;
|
|
90
154
|
}
|
|
91
155
|
/**
|
|
92
156
|
* Fetch step - makes an HTTP request
|
|
@@ -152,7 +216,26 @@ interface EachNode {
|
|
|
152
216
|
key?: Expression;
|
|
153
217
|
body: ViewNode;
|
|
154
218
|
}
|
|
155
|
-
|
|
219
|
+
/**
|
|
220
|
+
* Component node - invokes a defined component
|
|
221
|
+
*/
|
|
222
|
+
interface ComponentNode {
|
|
223
|
+
kind: 'component';
|
|
224
|
+
name: string;
|
|
225
|
+
props?: Record<string, Expression>;
|
|
226
|
+
children?: ViewNode[];
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Slot node - placeholder for children in component definition
|
|
230
|
+
*/
|
|
231
|
+
interface SlotNode {
|
|
232
|
+
kind: 'slot';
|
|
233
|
+
}
|
|
234
|
+
type ViewNode = ElementNode | TextNode | IfNode | EachNode | ComponentNode | SlotNode;
|
|
235
|
+
interface ComponentDef {
|
|
236
|
+
params?: Record<string, ParamDef>;
|
|
237
|
+
view: ViewNode;
|
|
238
|
+
}
|
|
156
239
|
/**
|
|
157
240
|
* Program - the root of a Constela AST
|
|
158
241
|
*/
|
|
@@ -161,6 +244,7 @@ interface Program {
|
|
|
161
244
|
state: Record<string, StateField>;
|
|
162
245
|
actions: ActionDefinition[];
|
|
163
246
|
view: ViewNode;
|
|
247
|
+
components?: Record<string, ComponentDef>;
|
|
164
248
|
}
|
|
165
249
|
type ConstelaAst = Program;
|
|
166
250
|
|
|
@@ -202,6 +286,30 @@ declare function isBinExpr(value: unknown): value is BinExpr;
|
|
|
202
286
|
* Use the AST validator for full recursive validation instead.
|
|
203
287
|
*/
|
|
204
288
|
declare function isNotExpr(value: unknown): value is NotExpr;
|
|
289
|
+
/**
|
|
290
|
+
* Checks if value is a param expression
|
|
291
|
+
*/
|
|
292
|
+
declare function isParamExpr(value: unknown): value is ParamExpr;
|
|
293
|
+
/**
|
|
294
|
+
* Checks if value is a cond expression
|
|
295
|
+
*
|
|
296
|
+
* Note: This performs shallow validation only - it checks that `if`, `then`, and `else`
|
|
297
|
+
* are objects but does not recursively validate they are valid Expressions.
|
|
298
|
+
* This is intentional for performance: deep validation would require traversing
|
|
299
|
+
* potentially deeply nested expression trees on every type guard call.
|
|
300
|
+
* Use the AST validator for full recursive validation instead.
|
|
301
|
+
*/
|
|
302
|
+
declare function isCondExpr(value: unknown): value is CondExpr;
|
|
303
|
+
/**
|
|
304
|
+
* Checks if value is a get expression
|
|
305
|
+
*
|
|
306
|
+
* Note: This performs shallow validation only - it checks that `base` is
|
|
307
|
+
* an object but does not recursively validate it is a valid Expression.
|
|
308
|
+
* This is intentional for performance: deep validation would require traversing
|
|
309
|
+
* potentially deeply nested expression trees on every type guard call.
|
|
310
|
+
* Use the AST validator for full recursive validation instead.
|
|
311
|
+
*/
|
|
312
|
+
declare function isGetExpr(value: unknown): value is GetExpr;
|
|
205
313
|
/**
|
|
206
314
|
* Checks if value is any valid expression
|
|
207
315
|
*/
|
|
@@ -222,6 +330,14 @@ declare function isIfNode(value: unknown): value is IfNode;
|
|
|
222
330
|
* Checks if value is an each node
|
|
223
331
|
*/
|
|
224
332
|
declare function isEachNode(value: unknown): value is EachNode;
|
|
333
|
+
/**
|
|
334
|
+
* Checks if value is a component node
|
|
335
|
+
*/
|
|
336
|
+
declare function isComponentNode(value: unknown): value is ComponentNode;
|
|
337
|
+
/**
|
|
338
|
+
* Checks if value is a slot node
|
|
339
|
+
*/
|
|
340
|
+
declare function isSlotNode(value: unknown): value is SlotNode;
|
|
225
341
|
/**
|
|
226
342
|
* Checks if value is any valid view node
|
|
227
343
|
*/
|
|
@@ -254,6 +370,14 @@ declare function isStringField(value: unknown): value is StringField;
|
|
|
254
370
|
* Checks if value is a list field
|
|
255
371
|
*/
|
|
256
372
|
declare function isListField(value: unknown): value is ListField;
|
|
373
|
+
/**
|
|
374
|
+
* Checks if value is a boolean field
|
|
375
|
+
*/
|
|
376
|
+
declare function isBooleanField(value: unknown): value is BooleanField;
|
|
377
|
+
/**
|
|
378
|
+
* Checks if value is an object field
|
|
379
|
+
*/
|
|
380
|
+
declare function isObjectField(value: unknown): value is ObjectField;
|
|
257
381
|
/**
|
|
258
382
|
* Checks if value is any valid state field
|
|
259
383
|
*/
|
|
@@ -269,7 +393,7 @@ declare function isEventHandler(value: unknown): value is EventHandler;
|
|
|
269
393
|
* This module defines error types, the ConstelaError class,
|
|
270
394
|
* and factory functions for creating specific errors.
|
|
271
395
|
*/
|
|
272
|
-
type ErrorCode = 'SCHEMA_INVALID' | 'UNDEFINED_STATE' | 'UNDEFINED_ACTION' | 'VAR_UNDEFINED' | 'DUPLICATE_ACTION' | 'UNSUPPORTED_VERSION';
|
|
396
|
+
type ErrorCode = 'SCHEMA_INVALID' | 'UNDEFINED_STATE' | 'UNDEFINED_ACTION' | 'VAR_UNDEFINED' | 'DUPLICATE_ACTION' | 'UNSUPPORTED_VERSION' | 'COMPONENT_NOT_FOUND' | 'COMPONENT_PROP_MISSING' | 'COMPONENT_CYCLE' | 'COMPONENT_PROP_TYPE' | 'PARAM_UNDEFINED' | 'OPERATION_INVALID_FOR_TYPE' | 'OPERATION_MISSING_FIELD' | 'OPERATION_UNKNOWN' | 'EXPR_INVALID_BASE' | 'EXPR_INVALID_CONDITION' | 'EXPR_COND_ELSE_REQUIRED';
|
|
273
397
|
/**
|
|
274
398
|
* Custom error class for Constela validation errors
|
|
275
399
|
*/
|
|
@@ -314,6 +438,42 @@ declare function createUndefinedVarError(varName: string, path?: string): Conste
|
|
|
314
438
|
* Creates an unsupported version error
|
|
315
439
|
*/
|
|
316
440
|
declare function createUnsupportedVersionError(version: string): ConstelaError;
|
|
441
|
+
/**
|
|
442
|
+
* Creates a component not found error
|
|
443
|
+
*/
|
|
444
|
+
declare function createComponentNotFoundError(name: string, path?: string): ConstelaError;
|
|
445
|
+
/**
|
|
446
|
+
* Creates a missing required prop error
|
|
447
|
+
*/
|
|
448
|
+
declare function createComponentPropMissingError(componentName: string, propName: string, path?: string): ConstelaError;
|
|
449
|
+
/**
|
|
450
|
+
* Creates a component cycle error
|
|
451
|
+
*/
|
|
452
|
+
declare function createComponentCycleError(cycle: string[], path?: string): ConstelaError;
|
|
453
|
+
/**
|
|
454
|
+
* Creates a prop type mismatch error
|
|
455
|
+
*/
|
|
456
|
+
declare function createComponentPropTypeError(componentName: string, propName: string, expected: string, actual: string, path?: string): ConstelaError;
|
|
457
|
+
/**
|
|
458
|
+
* Creates an undefined param reference error
|
|
459
|
+
*/
|
|
460
|
+
declare function createUndefinedParamError(paramName: string, path?: string): ConstelaError;
|
|
461
|
+
/**
|
|
462
|
+
* Creates an operation invalid for type error
|
|
463
|
+
*/
|
|
464
|
+
declare function createOperationInvalidForTypeError(operation: string, stateType: string, path?: string): ConstelaError;
|
|
465
|
+
/**
|
|
466
|
+
* Creates an operation missing field error
|
|
467
|
+
*/
|
|
468
|
+
declare function createOperationMissingFieldError(operation: string, field: string, path?: string): ConstelaError;
|
|
469
|
+
/**
|
|
470
|
+
* Creates an operation unknown error
|
|
471
|
+
*/
|
|
472
|
+
declare function createOperationUnknownError(operation: string, path?: string): ConstelaError;
|
|
473
|
+
/**
|
|
474
|
+
* Creates a cond else required error
|
|
475
|
+
*/
|
|
476
|
+
declare function createCondElseRequiredError(path?: string): ConstelaError;
|
|
317
477
|
|
|
318
478
|
/**
|
|
319
479
|
* AST Validator for Constela
|
|
@@ -372,6 +532,12 @@ declare const astSchema: {
|
|
|
372
532
|
readonly view: {
|
|
373
533
|
readonly $ref: "#/$defs/ViewNode";
|
|
374
534
|
};
|
|
535
|
+
readonly components: {
|
|
536
|
+
readonly type: "object";
|
|
537
|
+
readonly additionalProperties: {
|
|
538
|
+
readonly $ref: "#/$defs/ComponentDef";
|
|
539
|
+
};
|
|
540
|
+
};
|
|
375
541
|
};
|
|
376
542
|
readonly $defs: {
|
|
377
543
|
readonly Expression: {
|
|
@@ -385,6 +551,12 @@ declare const astSchema: {
|
|
|
385
551
|
readonly $ref: "#/$defs/BinExpr";
|
|
386
552
|
}, {
|
|
387
553
|
readonly $ref: "#/$defs/NotExpr";
|
|
554
|
+
}, {
|
|
555
|
+
readonly $ref: "#/$defs/ParamExpr";
|
|
556
|
+
}, {
|
|
557
|
+
readonly $ref: "#/$defs/CondExpr";
|
|
558
|
+
}, {
|
|
559
|
+
readonly $ref: "#/$defs/GetExpr";
|
|
388
560
|
}];
|
|
389
561
|
};
|
|
390
562
|
readonly LitExpr: {
|
|
@@ -477,6 +649,60 @@ declare const astSchema: {
|
|
|
477
649
|
};
|
|
478
650
|
};
|
|
479
651
|
};
|
|
652
|
+
readonly ParamExpr: {
|
|
653
|
+
readonly type: "object";
|
|
654
|
+
readonly required: readonly ["expr", "name"];
|
|
655
|
+
readonly additionalProperties: false;
|
|
656
|
+
readonly properties: {
|
|
657
|
+
readonly expr: {
|
|
658
|
+
readonly type: "string";
|
|
659
|
+
readonly const: "param";
|
|
660
|
+
};
|
|
661
|
+
readonly name: {
|
|
662
|
+
readonly type: "string";
|
|
663
|
+
};
|
|
664
|
+
readonly path: {
|
|
665
|
+
readonly type: "string";
|
|
666
|
+
};
|
|
667
|
+
};
|
|
668
|
+
};
|
|
669
|
+
readonly CondExpr: {
|
|
670
|
+
readonly type: "object";
|
|
671
|
+
readonly required: readonly ["expr", "if", "then", "else"];
|
|
672
|
+
readonly additionalProperties: false;
|
|
673
|
+
readonly properties: {
|
|
674
|
+
readonly expr: {
|
|
675
|
+
readonly type: "string";
|
|
676
|
+
readonly const: "cond";
|
|
677
|
+
};
|
|
678
|
+
readonly if: {
|
|
679
|
+
readonly $ref: "#/$defs/Expression";
|
|
680
|
+
};
|
|
681
|
+
readonly then: {
|
|
682
|
+
readonly $ref: "#/$defs/Expression";
|
|
683
|
+
};
|
|
684
|
+
readonly else: {
|
|
685
|
+
readonly $ref: "#/$defs/Expression";
|
|
686
|
+
};
|
|
687
|
+
};
|
|
688
|
+
};
|
|
689
|
+
readonly GetExpr: {
|
|
690
|
+
readonly type: "object";
|
|
691
|
+
readonly required: readonly ["expr", "base", "path"];
|
|
692
|
+
readonly additionalProperties: false;
|
|
693
|
+
readonly properties: {
|
|
694
|
+
readonly expr: {
|
|
695
|
+
readonly type: "string";
|
|
696
|
+
readonly const: "get";
|
|
697
|
+
};
|
|
698
|
+
readonly base: {
|
|
699
|
+
readonly $ref: "#/$defs/Expression";
|
|
700
|
+
};
|
|
701
|
+
readonly path: {
|
|
702
|
+
readonly type: "string";
|
|
703
|
+
};
|
|
704
|
+
};
|
|
705
|
+
};
|
|
480
706
|
readonly StateField: {
|
|
481
707
|
readonly oneOf: readonly [{
|
|
482
708
|
readonly $ref: "#/$defs/NumberField";
|
|
@@ -484,6 +710,10 @@ declare const astSchema: {
|
|
|
484
710
|
readonly $ref: "#/$defs/StringField";
|
|
485
711
|
}, {
|
|
486
712
|
readonly $ref: "#/$defs/ListField";
|
|
713
|
+
}, {
|
|
714
|
+
readonly $ref: "#/$defs/BooleanField";
|
|
715
|
+
}, {
|
|
716
|
+
readonly $ref: "#/$defs/ObjectField";
|
|
487
717
|
}];
|
|
488
718
|
};
|
|
489
719
|
readonly NumberField: {
|
|
@@ -528,6 +758,34 @@ declare const astSchema: {
|
|
|
528
758
|
};
|
|
529
759
|
};
|
|
530
760
|
};
|
|
761
|
+
readonly BooleanField: {
|
|
762
|
+
readonly type: "object";
|
|
763
|
+
readonly required: readonly ["type", "initial"];
|
|
764
|
+
readonly additionalProperties: false;
|
|
765
|
+
readonly properties: {
|
|
766
|
+
readonly type: {
|
|
767
|
+
readonly type: "string";
|
|
768
|
+
readonly const: "boolean";
|
|
769
|
+
};
|
|
770
|
+
readonly initial: {
|
|
771
|
+
readonly type: "boolean";
|
|
772
|
+
};
|
|
773
|
+
};
|
|
774
|
+
};
|
|
775
|
+
readonly ObjectField: {
|
|
776
|
+
readonly type: "object";
|
|
777
|
+
readonly required: readonly ["type", "initial"];
|
|
778
|
+
readonly additionalProperties: false;
|
|
779
|
+
readonly properties: {
|
|
780
|
+
readonly type: {
|
|
781
|
+
readonly type: "string";
|
|
782
|
+
readonly const: "object";
|
|
783
|
+
};
|
|
784
|
+
readonly initial: {
|
|
785
|
+
readonly type: "object";
|
|
786
|
+
};
|
|
787
|
+
};
|
|
788
|
+
};
|
|
531
789
|
readonly ActionStep: {
|
|
532
790
|
readonly oneOf: readonly [{
|
|
533
791
|
readonly $ref: "#/$defs/SetStep";
|
|
@@ -568,11 +826,17 @@ declare const astSchema: {
|
|
|
568
826
|
};
|
|
569
827
|
readonly operation: {
|
|
570
828
|
readonly type: "string";
|
|
571
|
-
readonly enum: readonly ["increment", "decrement", "push", "pop", "remove"];
|
|
829
|
+
readonly enum: readonly ["increment", "decrement", "push", "pop", "remove", "toggle", "merge", "replaceAt", "insertAt", "splice"];
|
|
572
830
|
};
|
|
573
831
|
readonly value: {
|
|
574
832
|
readonly $ref: "#/$defs/Expression";
|
|
575
833
|
};
|
|
834
|
+
readonly index: {
|
|
835
|
+
readonly $ref: "#/$defs/Expression";
|
|
836
|
+
};
|
|
837
|
+
readonly deleteCount: {
|
|
838
|
+
readonly $ref: "#/$defs/Expression";
|
|
839
|
+
};
|
|
576
840
|
};
|
|
577
841
|
};
|
|
578
842
|
readonly FetchStep: {
|
|
@@ -652,6 +916,10 @@ declare const astSchema: {
|
|
|
652
916
|
readonly $ref: "#/$defs/IfNode";
|
|
653
917
|
}, {
|
|
654
918
|
readonly $ref: "#/$defs/EachNode";
|
|
919
|
+
}, {
|
|
920
|
+
readonly $ref: "#/$defs/ComponentNode";
|
|
921
|
+
}, {
|
|
922
|
+
readonly $ref: "#/$defs/SlotNode";
|
|
655
923
|
}];
|
|
656
924
|
};
|
|
657
925
|
readonly ElementNode: {
|
|
@@ -744,7 +1012,74 @@ declare const astSchema: {
|
|
|
744
1012
|
};
|
|
745
1013
|
};
|
|
746
1014
|
};
|
|
1015
|
+
readonly ComponentNode: {
|
|
1016
|
+
readonly type: "object";
|
|
1017
|
+
readonly required: readonly ["kind", "name"];
|
|
1018
|
+
readonly additionalProperties: false;
|
|
1019
|
+
readonly properties: {
|
|
1020
|
+
readonly kind: {
|
|
1021
|
+
readonly type: "string";
|
|
1022
|
+
readonly const: "component";
|
|
1023
|
+
};
|
|
1024
|
+
readonly name: {
|
|
1025
|
+
readonly type: "string";
|
|
1026
|
+
};
|
|
1027
|
+
readonly props: {
|
|
1028
|
+
readonly type: "object";
|
|
1029
|
+
readonly additionalProperties: {
|
|
1030
|
+
readonly $ref: "#/$defs/Expression";
|
|
1031
|
+
};
|
|
1032
|
+
};
|
|
1033
|
+
readonly children: {
|
|
1034
|
+
readonly type: "array";
|
|
1035
|
+
readonly items: {
|
|
1036
|
+
readonly $ref: "#/$defs/ViewNode";
|
|
1037
|
+
};
|
|
1038
|
+
};
|
|
1039
|
+
};
|
|
1040
|
+
};
|
|
1041
|
+
readonly SlotNode: {
|
|
1042
|
+
readonly type: "object";
|
|
1043
|
+
readonly required: readonly ["kind"];
|
|
1044
|
+
readonly additionalProperties: false;
|
|
1045
|
+
readonly properties: {
|
|
1046
|
+
readonly kind: {
|
|
1047
|
+
readonly type: "string";
|
|
1048
|
+
readonly const: "slot";
|
|
1049
|
+
};
|
|
1050
|
+
};
|
|
1051
|
+
};
|
|
1052
|
+
readonly ParamDef: {
|
|
1053
|
+
readonly type: "object";
|
|
1054
|
+
readonly required: readonly ["type"];
|
|
1055
|
+
readonly additionalProperties: false;
|
|
1056
|
+
readonly properties: {
|
|
1057
|
+
readonly type: {
|
|
1058
|
+
readonly type: "string";
|
|
1059
|
+
readonly enum: readonly ["string", "number", "boolean", "json"];
|
|
1060
|
+
};
|
|
1061
|
+
readonly required: {
|
|
1062
|
+
readonly type: "boolean";
|
|
1063
|
+
};
|
|
1064
|
+
};
|
|
1065
|
+
};
|
|
1066
|
+
readonly ComponentDef: {
|
|
1067
|
+
readonly type: "object";
|
|
1068
|
+
readonly required: readonly ["view"];
|
|
1069
|
+
readonly additionalProperties: false;
|
|
1070
|
+
readonly properties: {
|
|
1071
|
+
readonly params: {
|
|
1072
|
+
readonly type: "object";
|
|
1073
|
+
readonly additionalProperties: {
|
|
1074
|
+
readonly $ref: "#/$defs/ParamDef";
|
|
1075
|
+
};
|
|
1076
|
+
};
|
|
1077
|
+
readonly view: {
|
|
1078
|
+
readonly $ref: "#/$defs/ViewNode";
|
|
1079
|
+
};
|
|
1080
|
+
};
|
|
1081
|
+
};
|
|
747
1082
|
};
|
|
748
1083
|
};
|
|
749
1084
|
|
|
750
|
-
export { type ActionDefinition, type ActionStep, BINARY_OPERATORS, type BinExpr, type BinaryOperator, type ConstelaAst, ConstelaError, type EachNode, type ElementNode, type ErrorCode, type EventHandler, type Expression, type FetchStep, HTTP_METHODS, type HttpMethod, type IfNode, type ListField, type LitExpr, type NotExpr, type NumberField, type Program, type SetStep, type StateExpr, type StateField, type StringField, type TextNode, UPDATE_OPERATIONS, type UpdateOperation, type UpdateStep, type ValidationFailure, type ValidationResult, type ValidationSuccess, type VarExpr, type ViewNode, astSchema, createDuplicateActionError, createSchemaError, createUndefinedActionError, createUndefinedStateError, createUndefinedVarError, createUnsupportedVersionError, isActionStep, isBinExpr, isConstelaError, isEachNode, isElementNode, isEventHandler, isExpression, isFetchStep, isIfNode, isListField, isLitExpr, isNotExpr, isNumberField, isSetStep, isStateExpr, isStateField, isStringField, isTextNode, isUpdateStep, isVarExpr, isViewNode, validateAst };
|
|
1085
|
+
export { type ActionDefinition, type ActionStep, BINARY_OPERATORS, type BinExpr, type BinaryOperator, type BooleanField, type ComponentDef, type ComponentNode, type CondExpr, type ConstelaAst, ConstelaError, type EachNode, type ElementNode, type ErrorCode, type EventHandler, type Expression, type FetchStep, type GetExpr, HTTP_METHODS, type HttpMethod, type IfNode, type ListField, type LitExpr, type NotExpr, type NumberField, type ObjectField, PARAM_TYPES, type ParamDef, type ParamExpr, type ParamType, type Program, type SetStep, type SlotNode, type StateExpr, type StateField, type StringField, type TextNode, UPDATE_OPERATIONS, type UpdateOperation, type UpdateStep, type ValidationFailure, type ValidationResult, type ValidationSuccess, type VarExpr, type ViewNode, astSchema, createComponentCycleError, createComponentNotFoundError, createComponentPropMissingError, createComponentPropTypeError, createCondElseRequiredError, createDuplicateActionError, createOperationInvalidForTypeError, createOperationMissingFieldError, createOperationUnknownError, createSchemaError, createUndefinedActionError, createUndefinedParamError, createUndefinedStateError, createUndefinedVarError, createUnsupportedVersionError, isActionStep, isBinExpr, isBooleanField, isComponentNode, isCondExpr, isConstelaError, isEachNode, isElementNode, isEventHandler, isExpression, isFetchStep, isGetExpr, isIfNode, isListField, isLitExpr, isNotExpr, isNumberField, isObjectField, isParamExpr, isSetStep, isSlotNode, isStateExpr, isStateField, isStringField, isTextNode, isUpdateStep, isVarExpr, isViewNode, validateAst };
|
package/dist/index.js
CHANGED
|
@@ -18,9 +18,15 @@ var UPDATE_OPERATIONS = [
|
|
|
18
18
|
"decrement",
|
|
19
19
|
"push",
|
|
20
20
|
"pop",
|
|
21
|
-
"remove"
|
|
21
|
+
"remove",
|
|
22
|
+
"toggle",
|
|
23
|
+
"merge",
|
|
24
|
+
"replaceAt",
|
|
25
|
+
"insertAt",
|
|
26
|
+
"splice"
|
|
22
27
|
];
|
|
23
28
|
var HTTP_METHODS = ["GET", "POST", "PUT", "DELETE"];
|
|
29
|
+
var PARAM_TYPES = ["string", "number", "boolean", "json"];
|
|
24
30
|
|
|
25
31
|
// src/types/guards.ts
|
|
26
32
|
function isObject(value) {
|
|
@@ -56,8 +62,30 @@ function isNotExpr(value) {
|
|
|
56
62
|
if (!isObject(value["operand"])) return false;
|
|
57
63
|
return true;
|
|
58
64
|
}
|
|
65
|
+
function isParamExpr(value) {
|
|
66
|
+
if (!isObject(value)) return false;
|
|
67
|
+
if (value["expr"] !== "param") return false;
|
|
68
|
+
if (typeof value["name"] !== "string") return false;
|
|
69
|
+
if ("path" in value && value["path"] !== void 0) {
|
|
70
|
+
if (typeof value["path"] !== "string") return false;
|
|
71
|
+
}
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
function isCondExpr(value) {
|
|
75
|
+
if (!isObject(value)) return false;
|
|
76
|
+
if (value["expr"] !== "cond") return false;
|
|
77
|
+
if (!isObject(value["if"]) || !isObject(value["then"]) || !isObject(value["else"])) return false;
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
function isGetExpr(value) {
|
|
81
|
+
if (!isObject(value)) return false;
|
|
82
|
+
if (value["expr"] !== "get") return false;
|
|
83
|
+
if (!isObject(value["base"])) return false;
|
|
84
|
+
if (typeof value["path"] !== "string") return false;
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
59
87
|
function isExpression(value) {
|
|
60
|
-
return isLitExpr(value) || isStateExpr(value) || isVarExpr(value) || isBinExpr(value) || isNotExpr(value);
|
|
88
|
+
return isLitExpr(value) || isStateExpr(value) || isVarExpr(value) || isBinExpr(value) || isNotExpr(value) || isParamExpr(value) || isCondExpr(value) || isGetExpr(value);
|
|
61
89
|
}
|
|
62
90
|
function isElementNode(value) {
|
|
63
91
|
if (!isObject(value)) return false;
|
|
@@ -84,8 +112,24 @@ function isEachNode(value) {
|
|
|
84
112
|
if (!isObject(value["body"])) return false;
|
|
85
113
|
return true;
|
|
86
114
|
}
|
|
115
|
+
function isComponentNode(value) {
|
|
116
|
+
if (!isObject(value)) return false;
|
|
117
|
+
if (value["kind"] !== "component") return false;
|
|
118
|
+
if (typeof value["name"] !== "string") return false;
|
|
119
|
+
if ("props" in value && value["props"] !== void 0) {
|
|
120
|
+
if (!isObject(value["props"])) return false;
|
|
121
|
+
}
|
|
122
|
+
if ("children" in value && value["children"] !== void 0) {
|
|
123
|
+
if (!Array.isArray(value["children"])) return false;
|
|
124
|
+
}
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
function isSlotNode(value) {
|
|
128
|
+
if (!isObject(value)) return false;
|
|
129
|
+
return value["kind"] === "slot";
|
|
130
|
+
}
|
|
87
131
|
function isViewNode(value) {
|
|
88
|
-
return isElementNode(value) || isTextNode(value) || isIfNode(value) || isEachNode(value);
|
|
132
|
+
return isElementNode(value) || isTextNode(value) || isIfNode(value) || isEachNode(value) || isComponentNode(value) || isSlotNode(value);
|
|
89
133
|
}
|
|
90
134
|
function isSetStep(value) {
|
|
91
135
|
if (!isObject(value)) return false;
|
|
@@ -132,8 +176,18 @@ function isListField(value) {
|
|
|
132
176
|
if (value["type"] !== "list") return false;
|
|
133
177
|
return Array.isArray(value["initial"]);
|
|
134
178
|
}
|
|
179
|
+
function isBooleanField(value) {
|
|
180
|
+
if (!isObject(value)) return false;
|
|
181
|
+
if (value["type"] !== "boolean") return false;
|
|
182
|
+
return typeof value["initial"] === "boolean";
|
|
183
|
+
}
|
|
184
|
+
function isObjectField(value) {
|
|
185
|
+
if (!isObject(value)) return false;
|
|
186
|
+
if (value["type"] !== "object") return false;
|
|
187
|
+
return typeof value["initial"] === "object" && value["initial"] !== null;
|
|
188
|
+
}
|
|
135
189
|
function isStateField(value) {
|
|
136
|
-
return isNumberField(value) || isStringField(value) || isListField(value);
|
|
190
|
+
return isNumberField(value) || isStringField(value) || isListField(value) || isBooleanField(value) || isObjectField(value);
|
|
137
191
|
}
|
|
138
192
|
function isEventHandler(value) {
|
|
139
193
|
if (!isObject(value)) return false;
|
|
@@ -205,6 +259,69 @@ function createUnsupportedVersionError(version) {
|
|
|
205
259
|
"/version"
|
|
206
260
|
);
|
|
207
261
|
}
|
|
262
|
+
function createComponentNotFoundError(name, path) {
|
|
263
|
+
return new ConstelaError(
|
|
264
|
+
"COMPONENT_NOT_FOUND",
|
|
265
|
+
`Component '${name}' is not defined in components`,
|
|
266
|
+
path
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
function createComponentPropMissingError(componentName, propName, path) {
|
|
270
|
+
return new ConstelaError(
|
|
271
|
+
"COMPONENT_PROP_MISSING",
|
|
272
|
+
`Component '${componentName}' requires prop '${propName}'`,
|
|
273
|
+
path
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
function createComponentCycleError(cycle, path) {
|
|
277
|
+
return new ConstelaError(
|
|
278
|
+
"COMPONENT_CYCLE",
|
|
279
|
+
`Circular component reference detected: ${cycle.join(" -> ")}`,
|
|
280
|
+
path
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
function createComponentPropTypeError(componentName, propName, expected, actual, path) {
|
|
284
|
+
return new ConstelaError(
|
|
285
|
+
"COMPONENT_PROP_TYPE",
|
|
286
|
+
`Component '${componentName}' prop '${propName}' expects ${expected}, got ${actual}`,
|
|
287
|
+
path
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
function createUndefinedParamError(paramName, path) {
|
|
291
|
+
return new ConstelaError(
|
|
292
|
+
"PARAM_UNDEFINED",
|
|
293
|
+
`Undefined param reference: '${paramName}' is not defined in component params`,
|
|
294
|
+
path
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
function createOperationInvalidForTypeError(operation, stateType, path) {
|
|
298
|
+
return new ConstelaError(
|
|
299
|
+
"OPERATION_INVALID_FOR_TYPE",
|
|
300
|
+
`Operation '${operation}' is not valid for state type '${stateType}'`,
|
|
301
|
+
path
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
function createOperationMissingFieldError(operation, field, path) {
|
|
305
|
+
return new ConstelaError(
|
|
306
|
+
"OPERATION_MISSING_FIELD",
|
|
307
|
+
`Operation '${operation}' requires field '${field}'`,
|
|
308
|
+
path
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
function createOperationUnknownError(operation, path) {
|
|
312
|
+
return new ConstelaError(
|
|
313
|
+
"OPERATION_UNKNOWN",
|
|
314
|
+
`Unknown operation: '${operation}'`,
|
|
315
|
+
path
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
function createCondElseRequiredError(path) {
|
|
319
|
+
return new ConstelaError(
|
|
320
|
+
"EXPR_COND_ELSE_REQUIRED",
|
|
321
|
+
`Cond expression requires 'else' field`,
|
|
322
|
+
path
|
|
323
|
+
);
|
|
324
|
+
}
|
|
208
325
|
|
|
209
326
|
// src/schema/validator.ts
|
|
210
327
|
import Ajv from "ajv";
|
|
@@ -237,6 +354,10 @@ var astSchema = {
|
|
|
237
354
|
},
|
|
238
355
|
view: {
|
|
239
356
|
$ref: "#/$defs/ViewNode"
|
|
357
|
+
},
|
|
358
|
+
components: {
|
|
359
|
+
type: "object",
|
|
360
|
+
additionalProperties: { $ref: "#/$defs/ComponentDef" }
|
|
240
361
|
}
|
|
241
362
|
},
|
|
242
363
|
$defs: {
|
|
@@ -247,7 +368,10 @@ var astSchema = {
|
|
|
247
368
|
{ $ref: "#/$defs/StateExpr" },
|
|
248
369
|
{ $ref: "#/$defs/VarExpr" },
|
|
249
370
|
{ $ref: "#/$defs/BinExpr" },
|
|
250
|
-
{ $ref: "#/$defs/NotExpr" }
|
|
371
|
+
{ $ref: "#/$defs/NotExpr" },
|
|
372
|
+
{ $ref: "#/$defs/ParamExpr" },
|
|
373
|
+
{ $ref: "#/$defs/CondExpr" },
|
|
374
|
+
{ $ref: "#/$defs/GetExpr" }
|
|
251
375
|
]
|
|
252
376
|
},
|
|
253
377
|
LitExpr: {
|
|
@@ -309,12 +433,45 @@ var astSchema = {
|
|
|
309
433
|
operand: { $ref: "#/$defs/Expression" }
|
|
310
434
|
}
|
|
311
435
|
},
|
|
436
|
+
ParamExpr: {
|
|
437
|
+
type: "object",
|
|
438
|
+
required: ["expr", "name"],
|
|
439
|
+
additionalProperties: false,
|
|
440
|
+
properties: {
|
|
441
|
+
expr: { type: "string", const: "param" },
|
|
442
|
+
name: { type: "string" },
|
|
443
|
+
path: { type: "string" }
|
|
444
|
+
}
|
|
445
|
+
},
|
|
446
|
+
CondExpr: {
|
|
447
|
+
type: "object",
|
|
448
|
+
required: ["expr", "if", "then", "else"],
|
|
449
|
+
additionalProperties: false,
|
|
450
|
+
properties: {
|
|
451
|
+
expr: { type: "string", const: "cond" },
|
|
452
|
+
if: { $ref: "#/$defs/Expression" },
|
|
453
|
+
then: { $ref: "#/$defs/Expression" },
|
|
454
|
+
else: { $ref: "#/$defs/Expression" }
|
|
455
|
+
}
|
|
456
|
+
},
|
|
457
|
+
GetExpr: {
|
|
458
|
+
type: "object",
|
|
459
|
+
required: ["expr", "base", "path"],
|
|
460
|
+
additionalProperties: false,
|
|
461
|
+
properties: {
|
|
462
|
+
expr: { type: "string", const: "get" },
|
|
463
|
+
base: { $ref: "#/$defs/Expression" },
|
|
464
|
+
path: { type: "string" }
|
|
465
|
+
}
|
|
466
|
+
},
|
|
312
467
|
// ==================== State Fields ====================
|
|
313
468
|
StateField: {
|
|
314
469
|
oneOf: [
|
|
315
470
|
{ $ref: "#/$defs/NumberField" },
|
|
316
471
|
{ $ref: "#/$defs/StringField" },
|
|
317
|
-
{ $ref: "#/$defs/ListField" }
|
|
472
|
+
{ $ref: "#/$defs/ListField" },
|
|
473
|
+
{ $ref: "#/$defs/BooleanField" },
|
|
474
|
+
{ $ref: "#/$defs/ObjectField" }
|
|
318
475
|
]
|
|
319
476
|
},
|
|
320
477
|
NumberField: {
|
|
@@ -344,6 +501,24 @@ var astSchema = {
|
|
|
344
501
|
initial: { type: "array" }
|
|
345
502
|
}
|
|
346
503
|
},
|
|
504
|
+
BooleanField: {
|
|
505
|
+
type: "object",
|
|
506
|
+
required: ["type", "initial"],
|
|
507
|
+
additionalProperties: false,
|
|
508
|
+
properties: {
|
|
509
|
+
type: { type: "string", const: "boolean" },
|
|
510
|
+
initial: { type: "boolean" }
|
|
511
|
+
}
|
|
512
|
+
},
|
|
513
|
+
ObjectField: {
|
|
514
|
+
type: "object",
|
|
515
|
+
required: ["type", "initial"],
|
|
516
|
+
additionalProperties: false,
|
|
517
|
+
properties: {
|
|
518
|
+
type: { type: "string", const: "object" },
|
|
519
|
+
initial: { type: "object" }
|
|
520
|
+
}
|
|
521
|
+
},
|
|
347
522
|
// ==================== Action Steps ====================
|
|
348
523
|
ActionStep: {
|
|
349
524
|
oneOf: [
|
|
@@ -371,9 +546,11 @@ var astSchema = {
|
|
|
371
546
|
target: { type: "string" },
|
|
372
547
|
operation: {
|
|
373
548
|
type: "string",
|
|
374
|
-
enum: ["increment", "decrement", "push", "pop", "remove"]
|
|
549
|
+
enum: ["increment", "decrement", "push", "pop", "remove", "toggle", "merge", "replaceAt", "insertAt", "splice"]
|
|
375
550
|
},
|
|
376
|
-
value: { $ref: "#/$defs/Expression" }
|
|
551
|
+
value: { $ref: "#/$defs/Expression" },
|
|
552
|
+
index: { $ref: "#/$defs/Expression" },
|
|
553
|
+
deleteCount: { $ref: "#/$defs/Expression" }
|
|
377
554
|
}
|
|
378
555
|
},
|
|
379
556
|
FetchStep: {
|
|
@@ -429,7 +606,9 @@ var astSchema = {
|
|
|
429
606
|
{ $ref: "#/$defs/ElementNode" },
|
|
430
607
|
{ $ref: "#/$defs/TextNode" },
|
|
431
608
|
{ $ref: "#/$defs/IfNode" },
|
|
432
|
-
{ $ref: "#/$defs/EachNode" }
|
|
609
|
+
{ $ref: "#/$defs/EachNode" },
|
|
610
|
+
{ $ref: "#/$defs/ComponentNode" },
|
|
611
|
+
{ $ref: "#/$defs/SlotNode" }
|
|
433
612
|
]
|
|
434
613
|
},
|
|
435
614
|
ElementNode: {
|
|
@@ -486,6 +665,56 @@ var astSchema = {
|
|
|
486
665
|
key: { $ref: "#/$defs/Expression" },
|
|
487
666
|
body: { $ref: "#/$defs/ViewNode" }
|
|
488
667
|
}
|
|
668
|
+
},
|
|
669
|
+
ComponentNode: {
|
|
670
|
+
type: "object",
|
|
671
|
+
required: ["kind", "name"],
|
|
672
|
+
additionalProperties: false,
|
|
673
|
+
properties: {
|
|
674
|
+
kind: { type: "string", const: "component" },
|
|
675
|
+
name: { type: "string" },
|
|
676
|
+
props: {
|
|
677
|
+
type: "object",
|
|
678
|
+
additionalProperties: { $ref: "#/$defs/Expression" }
|
|
679
|
+
},
|
|
680
|
+
children: {
|
|
681
|
+
type: "array",
|
|
682
|
+
items: { $ref: "#/$defs/ViewNode" }
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
},
|
|
686
|
+
SlotNode: {
|
|
687
|
+
type: "object",
|
|
688
|
+
required: ["kind"],
|
|
689
|
+
additionalProperties: false,
|
|
690
|
+
properties: {
|
|
691
|
+
kind: { type: "string", const: "slot" }
|
|
692
|
+
}
|
|
693
|
+
},
|
|
694
|
+
// ==================== Component Definition ====================
|
|
695
|
+
ParamDef: {
|
|
696
|
+
type: "object",
|
|
697
|
+
required: ["type"],
|
|
698
|
+
additionalProperties: false,
|
|
699
|
+
properties: {
|
|
700
|
+
type: {
|
|
701
|
+
type: "string",
|
|
702
|
+
enum: ["string", "number", "boolean", "json"]
|
|
703
|
+
},
|
|
704
|
+
required: { type: "boolean" }
|
|
705
|
+
}
|
|
706
|
+
},
|
|
707
|
+
ComponentDef: {
|
|
708
|
+
type: "object",
|
|
709
|
+
required: ["view"],
|
|
710
|
+
additionalProperties: false,
|
|
711
|
+
properties: {
|
|
712
|
+
params: {
|
|
713
|
+
type: "object",
|
|
714
|
+
additionalProperties: { $ref: "#/$defs/ParamDef" }
|
|
715
|
+
},
|
|
716
|
+
view: { $ref: "#/$defs/ViewNode" }
|
|
717
|
+
}
|
|
489
718
|
}
|
|
490
719
|
}
|
|
491
720
|
};
|
|
@@ -500,10 +729,11 @@ var validate = ajv.compile(astSchema);
|
|
|
500
729
|
function isObject2(value) {
|
|
501
730
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
502
731
|
}
|
|
503
|
-
var VALID_VIEW_KINDS = ["element", "text", "if", "each"];
|
|
504
|
-
var VALID_EXPR_TYPES = ["lit", "state", "var", "bin", "not"];
|
|
732
|
+
var VALID_VIEW_KINDS = ["element", "text", "if", "each", "component", "slot"];
|
|
733
|
+
var VALID_EXPR_TYPES = ["lit", "state", "var", "bin", "not", "param"];
|
|
734
|
+
var VALID_PARAM_TYPES = ["string", "number", "boolean", "json"];
|
|
505
735
|
var VALID_ACTION_TYPES = ["set", "update", "fetch"];
|
|
506
|
-
var VALID_STATE_TYPES = ["number", "string", "list"];
|
|
736
|
+
var VALID_STATE_TYPES = ["number", "string", "list", "boolean", "object"];
|
|
507
737
|
var VALID_BIN_OPS = BINARY_OPERATORS;
|
|
508
738
|
var VALID_UPDATE_OPS = UPDATE_OPERATIONS;
|
|
509
739
|
var VALID_HTTP_METHODS = HTTP_METHODS;
|
|
@@ -516,7 +746,7 @@ function validateViewNode(node, path) {
|
|
|
516
746
|
return { path: path + "/kind", message: "kind is required" };
|
|
517
747
|
}
|
|
518
748
|
if (!VALID_VIEW_KINDS.includes(kind)) {
|
|
519
|
-
return { path: path + "/kind", message: "must be one of: element, text, if, each" };
|
|
749
|
+
return { path: path + "/kind", message: "must be one of: element, text, if, each, component, slot" };
|
|
520
750
|
}
|
|
521
751
|
switch (kind) {
|
|
522
752
|
case "element":
|
|
@@ -579,6 +809,25 @@ function validateViewNode(node, path) {
|
|
|
579
809
|
if (bodyError) return bodyError;
|
|
580
810
|
}
|
|
581
811
|
break;
|
|
812
|
+
case "component":
|
|
813
|
+
if (typeof node["name"] !== "string") {
|
|
814
|
+
return { path: path + "/name", message: "name is required" };
|
|
815
|
+
}
|
|
816
|
+
if (node["props"] !== void 0 && isObject2(node["props"])) {
|
|
817
|
+
for (const [propName, propValue] of Object.entries(node["props"])) {
|
|
818
|
+
const error = validateExpression(propValue, path + "/props/" + propName);
|
|
819
|
+
if (error) return error;
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
if (Array.isArray(node["children"])) {
|
|
823
|
+
for (let i = 0; i < node["children"].length; i++) {
|
|
824
|
+
const error = validateViewNode(node["children"][i], path + "/children/" + i);
|
|
825
|
+
if (error) return error;
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
break;
|
|
829
|
+
case "slot":
|
|
830
|
+
break;
|
|
582
831
|
}
|
|
583
832
|
return null;
|
|
584
833
|
}
|
|
@@ -591,7 +840,7 @@ function validateExpression(expr, path) {
|
|
|
591
840
|
return { path: path + "/expr", message: "expr is required" };
|
|
592
841
|
}
|
|
593
842
|
if (!VALID_EXPR_TYPES.includes(exprType)) {
|
|
594
|
-
return { path: path + "/expr", message: "must be one of: lit, state, var, bin, not" };
|
|
843
|
+
return { path: path + "/expr", message: "must be one of: lit, state, var, bin, not, param" };
|
|
595
844
|
}
|
|
596
845
|
switch (exprType) {
|
|
597
846
|
case "lit":
|
|
@@ -630,6 +879,14 @@ function validateExpression(expr, path) {
|
|
|
630
879
|
return { path: path + "/operand", message: "operand is required" };
|
|
631
880
|
}
|
|
632
881
|
return validateExpression(expr["operand"], path + "/operand");
|
|
882
|
+
case "param":
|
|
883
|
+
if (typeof expr["name"] !== "string") {
|
|
884
|
+
return { path: path + "/name", message: "name is required" };
|
|
885
|
+
}
|
|
886
|
+
if ("path" in expr && typeof expr["path"] !== "string") {
|
|
887
|
+
return { path: path + "/path", message: "path must be a string" };
|
|
888
|
+
}
|
|
889
|
+
break;
|
|
633
890
|
}
|
|
634
891
|
return null;
|
|
635
892
|
}
|
|
@@ -718,7 +975,50 @@ function validateStateField(field, path) {
|
|
|
718
975
|
return { path: path + "/initial", message: "must be an array" };
|
|
719
976
|
}
|
|
720
977
|
break;
|
|
978
|
+
case "boolean":
|
|
979
|
+
if (typeof field["initial"] !== "boolean") {
|
|
980
|
+
return { path: path + "/initial", message: "must be a boolean" };
|
|
981
|
+
}
|
|
982
|
+
break;
|
|
983
|
+
case "object":
|
|
984
|
+
if (!isObject2(field["initial"])) {
|
|
985
|
+
return { path: path + "/initial", message: "must be an object" };
|
|
986
|
+
}
|
|
987
|
+
break;
|
|
988
|
+
}
|
|
989
|
+
return null;
|
|
990
|
+
}
|
|
991
|
+
function validateParamDef(param, path) {
|
|
992
|
+
if (!isObject2(param)) {
|
|
993
|
+
return { path, message: "must be an object" };
|
|
994
|
+
}
|
|
995
|
+
const paramType = param["type"];
|
|
996
|
+
if (typeof paramType !== "string") {
|
|
997
|
+
return { path: path + "/type", message: "type is required" };
|
|
998
|
+
}
|
|
999
|
+
if (!VALID_PARAM_TYPES.includes(paramType)) {
|
|
1000
|
+
return { path: path + "/type", message: "must be one of: string, number, boolean, json" };
|
|
1001
|
+
}
|
|
1002
|
+
if ("required" in param && typeof param["required"] !== "boolean") {
|
|
1003
|
+
return { path: path + "/required", message: "required must be a boolean" };
|
|
1004
|
+
}
|
|
1005
|
+
return null;
|
|
1006
|
+
}
|
|
1007
|
+
function validateComponentDef(def, path) {
|
|
1008
|
+
if (!isObject2(def)) {
|
|
1009
|
+
return { path, message: "must be an object" };
|
|
1010
|
+
}
|
|
1011
|
+
if (!("view" in def)) {
|
|
1012
|
+
return { path: path + "/view", message: "view is required" };
|
|
1013
|
+
}
|
|
1014
|
+
if ("params" in def && isObject2(def["params"])) {
|
|
1015
|
+
for (const [paramName, paramDef] of Object.entries(def["params"])) {
|
|
1016
|
+
const error = validateParamDef(paramDef, path + "/params/" + paramName);
|
|
1017
|
+
if (error) return error;
|
|
1018
|
+
}
|
|
721
1019
|
}
|
|
1020
|
+
const viewError = validateViewNode(def["view"], path + "/view");
|
|
1021
|
+
if (viewError) return viewError;
|
|
722
1022
|
return null;
|
|
723
1023
|
}
|
|
724
1024
|
function customValidateAst(input) {
|
|
@@ -743,6 +1043,12 @@ function customValidateAst(input) {
|
|
|
743
1043
|
const error = validateViewNode(input["view"], "/view");
|
|
744
1044
|
if (error) return error;
|
|
745
1045
|
}
|
|
1046
|
+
if ("components" in input && isObject2(input["components"])) {
|
|
1047
|
+
for (const [name, def] of Object.entries(input["components"])) {
|
|
1048
|
+
const error = validateComponentDef(def, "/components/" + name);
|
|
1049
|
+
if (error) return error;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
746
1052
|
return null;
|
|
747
1053
|
}
|
|
748
1054
|
function findTopLevelRequiredError(errors) {
|
|
@@ -943,28 +1249,45 @@ export {
|
|
|
943
1249
|
BINARY_OPERATORS,
|
|
944
1250
|
ConstelaError,
|
|
945
1251
|
HTTP_METHODS,
|
|
1252
|
+
PARAM_TYPES,
|
|
946
1253
|
UPDATE_OPERATIONS,
|
|
947
1254
|
astSchema,
|
|
1255
|
+
createComponentCycleError,
|
|
1256
|
+
createComponentNotFoundError,
|
|
1257
|
+
createComponentPropMissingError,
|
|
1258
|
+
createComponentPropTypeError,
|
|
1259
|
+
createCondElseRequiredError,
|
|
948
1260
|
createDuplicateActionError,
|
|
1261
|
+
createOperationInvalidForTypeError,
|
|
1262
|
+
createOperationMissingFieldError,
|
|
1263
|
+
createOperationUnknownError,
|
|
949
1264
|
createSchemaError,
|
|
950
1265
|
createUndefinedActionError,
|
|
1266
|
+
createUndefinedParamError,
|
|
951
1267
|
createUndefinedStateError,
|
|
952
1268
|
createUndefinedVarError,
|
|
953
1269
|
createUnsupportedVersionError,
|
|
954
1270
|
isActionStep,
|
|
955
1271
|
isBinExpr,
|
|
1272
|
+
isBooleanField,
|
|
1273
|
+
isComponentNode,
|
|
1274
|
+
isCondExpr,
|
|
956
1275
|
isConstelaError,
|
|
957
1276
|
isEachNode,
|
|
958
1277
|
isElementNode,
|
|
959
1278
|
isEventHandler,
|
|
960
1279
|
isExpression,
|
|
961
1280
|
isFetchStep,
|
|
1281
|
+
isGetExpr,
|
|
962
1282
|
isIfNode,
|
|
963
1283
|
isListField,
|
|
964
1284
|
isLitExpr,
|
|
965
1285
|
isNotExpr,
|
|
966
1286
|
isNumberField,
|
|
1287
|
+
isObjectField,
|
|
1288
|
+
isParamExpr,
|
|
967
1289
|
isSetStep,
|
|
1290
|
+
isSlotNode,
|
|
968
1291
|
isStateExpr,
|
|
969
1292
|
isStateField,
|
|
970
1293
|
isStringField,
|