@constela/core 0.1.0 → 0.2.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 +166 -4
- package/dist/index.js +212 -8
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,12 @@ declare const UPDATE_OPERATIONS: readonly ["increment", "decrement", "push", "po
|
|
|
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,15 @@ 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
|
+
type Expression = LitExpr | StateExpr | VarExpr | BinExpr | NotExpr | ParamExpr;
|
|
52
66
|
/**
|
|
53
67
|
* Number state field
|
|
54
68
|
*/
|
|
@@ -152,7 +166,26 @@ interface EachNode {
|
|
|
152
166
|
key?: Expression;
|
|
153
167
|
body: ViewNode;
|
|
154
168
|
}
|
|
155
|
-
|
|
169
|
+
/**
|
|
170
|
+
* Component node - invokes a defined component
|
|
171
|
+
*/
|
|
172
|
+
interface ComponentNode {
|
|
173
|
+
kind: 'component';
|
|
174
|
+
name: string;
|
|
175
|
+
props?: Record<string, Expression>;
|
|
176
|
+
children?: ViewNode[];
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Slot node - placeholder for children in component definition
|
|
180
|
+
*/
|
|
181
|
+
interface SlotNode {
|
|
182
|
+
kind: 'slot';
|
|
183
|
+
}
|
|
184
|
+
type ViewNode = ElementNode | TextNode | IfNode | EachNode | ComponentNode | SlotNode;
|
|
185
|
+
interface ComponentDef {
|
|
186
|
+
params?: Record<string, ParamDef>;
|
|
187
|
+
view: ViewNode;
|
|
188
|
+
}
|
|
156
189
|
/**
|
|
157
190
|
* Program - the root of a Constela AST
|
|
158
191
|
*/
|
|
@@ -161,6 +194,7 @@ interface Program {
|
|
|
161
194
|
state: Record<string, StateField>;
|
|
162
195
|
actions: ActionDefinition[];
|
|
163
196
|
view: ViewNode;
|
|
197
|
+
components?: Record<string, ComponentDef>;
|
|
164
198
|
}
|
|
165
199
|
type ConstelaAst = Program;
|
|
166
200
|
|
|
@@ -202,6 +236,10 @@ declare function isBinExpr(value: unknown): value is BinExpr;
|
|
|
202
236
|
* Use the AST validator for full recursive validation instead.
|
|
203
237
|
*/
|
|
204
238
|
declare function isNotExpr(value: unknown): value is NotExpr;
|
|
239
|
+
/**
|
|
240
|
+
* Checks if value is a param expression
|
|
241
|
+
*/
|
|
242
|
+
declare function isParamExpr(value: unknown): value is ParamExpr;
|
|
205
243
|
/**
|
|
206
244
|
* Checks if value is any valid expression
|
|
207
245
|
*/
|
|
@@ -222,6 +260,14 @@ declare function isIfNode(value: unknown): value is IfNode;
|
|
|
222
260
|
* Checks if value is an each node
|
|
223
261
|
*/
|
|
224
262
|
declare function isEachNode(value: unknown): value is EachNode;
|
|
263
|
+
/**
|
|
264
|
+
* Checks if value is a component node
|
|
265
|
+
*/
|
|
266
|
+
declare function isComponentNode(value: unknown): value is ComponentNode;
|
|
267
|
+
/**
|
|
268
|
+
* Checks if value is a slot node
|
|
269
|
+
*/
|
|
270
|
+
declare function isSlotNode(value: unknown): value is SlotNode;
|
|
225
271
|
/**
|
|
226
272
|
* Checks if value is any valid view node
|
|
227
273
|
*/
|
|
@@ -269,7 +315,7 @@ declare function isEventHandler(value: unknown): value is EventHandler;
|
|
|
269
315
|
* This module defines error types, the ConstelaError class,
|
|
270
316
|
* and factory functions for creating specific errors.
|
|
271
317
|
*/
|
|
272
|
-
type ErrorCode = 'SCHEMA_INVALID' | 'UNDEFINED_STATE' | 'UNDEFINED_ACTION' | 'VAR_UNDEFINED' | 'DUPLICATE_ACTION' | 'UNSUPPORTED_VERSION';
|
|
318
|
+
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';
|
|
273
319
|
/**
|
|
274
320
|
* Custom error class for Constela validation errors
|
|
275
321
|
*/
|
|
@@ -314,6 +360,26 @@ declare function createUndefinedVarError(varName: string, path?: string): Conste
|
|
|
314
360
|
* Creates an unsupported version error
|
|
315
361
|
*/
|
|
316
362
|
declare function createUnsupportedVersionError(version: string): ConstelaError;
|
|
363
|
+
/**
|
|
364
|
+
* Creates a component not found error
|
|
365
|
+
*/
|
|
366
|
+
declare function createComponentNotFoundError(name: string, path?: string): ConstelaError;
|
|
367
|
+
/**
|
|
368
|
+
* Creates a missing required prop error
|
|
369
|
+
*/
|
|
370
|
+
declare function createComponentPropMissingError(componentName: string, propName: string, path?: string): ConstelaError;
|
|
371
|
+
/**
|
|
372
|
+
* Creates a component cycle error
|
|
373
|
+
*/
|
|
374
|
+
declare function createComponentCycleError(cycle: string[], path?: string): ConstelaError;
|
|
375
|
+
/**
|
|
376
|
+
* Creates a prop type mismatch error
|
|
377
|
+
*/
|
|
378
|
+
declare function createComponentPropTypeError(componentName: string, propName: string, expected: string, actual: string, path?: string): ConstelaError;
|
|
379
|
+
/**
|
|
380
|
+
* Creates an undefined param reference error
|
|
381
|
+
*/
|
|
382
|
+
declare function createUndefinedParamError(paramName: string, path?: string): ConstelaError;
|
|
317
383
|
|
|
318
384
|
/**
|
|
319
385
|
* AST Validator for Constela
|
|
@@ -372,6 +438,12 @@ declare const astSchema: {
|
|
|
372
438
|
readonly view: {
|
|
373
439
|
readonly $ref: "#/$defs/ViewNode";
|
|
374
440
|
};
|
|
441
|
+
readonly components: {
|
|
442
|
+
readonly type: "object";
|
|
443
|
+
readonly additionalProperties: {
|
|
444
|
+
readonly $ref: "#/$defs/ComponentDef";
|
|
445
|
+
};
|
|
446
|
+
};
|
|
375
447
|
};
|
|
376
448
|
readonly $defs: {
|
|
377
449
|
readonly Expression: {
|
|
@@ -385,6 +457,8 @@ declare const astSchema: {
|
|
|
385
457
|
readonly $ref: "#/$defs/BinExpr";
|
|
386
458
|
}, {
|
|
387
459
|
readonly $ref: "#/$defs/NotExpr";
|
|
460
|
+
}, {
|
|
461
|
+
readonly $ref: "#/$defs/ParamExpr";
|
|
388
462
|
}];
|
|
389
463
|
};
|
|
390
464
|
readonly LitExpr: {
|
|
@@ -477,6 +551,23 @@ declare const astSchema: {
|
|
|
477
551
|
};
|
|
478
552
|
};
|
|
479
553
|
};
|
|
554
|
+
readonly ParamExpr: {
|
|
555
|
+
readonly type: "object";
|
|
556
|
+
readonly required: readonly ["expr", "name"];
|
|
557
|
+
readonly additionalProperties: false;
|
|
558
|
+
readonly properties: {
|
|
559
|
+
readonly expr: {
|
|
560
|
+
readonly type: "string";
|
|
561
|
+
readonly const: "param";
|
|
562
|
+
};
|
|
563
|
+
readonly name: {
|
|
564
|
+
readonly type: "string";
|
|
565
|
+
};
|
|
566
|
+
readonly path: {
|
|
567
|
+
readonly type: "string";
|
|
568
|
+
};
|
|
569
|
+
};
|
|
570
|
+
};
|
|
480
571
|
readonly StateField: {
|
|
481
572
|
readonly oneOf: readonly [{
|
|
482
573
|
readonly $ref: "#/$defs/NumberField";
|
|
@@ -652,6 +743,10 @@ declare const astSchema: {
|
|
|
652
743
|
readonly $ref: "#/$defs/IfNode";
|
|
653
744
|
}, {
|
|
654
745
|
readonly $ref: "#/$defs/EachNode";
|
|
746
|
+
}, {
|
|
747
|
+
readonly $ref: "#/$defs/ComponentNode";
|
|
748
|
+
}, {
|
|
749
|
+
readonly $ref: "#/$defs/SlotNode";
|
|
655
750
|
}];
|
|
656
751
|
};
|
|
657
752
|
readonly ElementNode: {
|
|
@@ -744,7 +839,74 @@ declare const astSchema: {
|
|
|
744
839
|
};
|
|
745
840
|
};
|
|
746
841
|
};
|
|
842
|
+
readonly ComponentNode: {
|
|
843
|
+
readonly type: "object";
|
|
844
|
+
readonly required: readonly ["kind", "name"];
|
|
845
|
+
readonly additionalProperties: false;
|
|
846
|
+
readonly properties: {
|
|
847
|
+
readonly kind: {
|
|
848
|
+
readonly type: "string";
|
|
849
|
+
readonly const: "component";
|
|
850
|
+
};
|
|
851
|
+
readonly name: {
|
|
852
|
+
readonly type: "string";
|
|
853
|
+
};
|
|
854
|
+
readonly props: {
|
|
855
|
+
readonly type: "object";
|
|
856
|
+
readonly additionalProperties: {
|
|
857
|
+
readonly $ref: "#/$defs/Expression";
|
|
858
|
+
};
|
|
859
|
+
};
|
|
860
|
+
readonly children: {
|
|
861
|
+
readonly type: "array";
|
|
862
|
+
readonly items: {
|
|
863
|
+
readonly $ref: "#/$defs/ViewNode";
|
|
864
|
+
};
|
|
865
|
+
};
|
|
866
|
+
};
|
|
867
|
+
};
|
|
868
|
+
readonly SlotNode: {
|
|
869
|
+
readonly type: "object";
|
|
870
|
+
readonly required: readonly ["kind"];
|
|
871
|
+
readonly additionalProperties: false;
|
|
872
|
+
readonly properties: {
|
|
873
|
+
readonly kind: {
|
|
874
|
+
readonly type: "string";
|
|
875
|
+
readonly const: "slot";
|
|
876
|
+
};
|
|
877
|
+
};
|
|
878
|
+
};
|
|
879
|
+
readonly ParamDef: {
|
|
880
|
+
readonly type: "object";
|
|
881
|
+
readonly required: readonly ["type"];
|
|
882
|
+
readonly additionalProperties: false;
|
|
883
|
+
readonly properties: {
|
|
884
|
+
readonly type: {
|
|
885
|
+
readonly type: "string";
|
|
886
|
+
readonly enum: readonly ["string", "number", "boolean", "json"];
|
|
887
|
+
};
|
|
888
|
+
readonly required: {
|
|
889
|
+
readonly type: "boolean";
|
|
890
|
+
};
|
|
891
|
+
};
|
|
892
|
+
};
|
|
893
|
+
readonly ComponentDef: {
|
|
894
|
+
readonly type: "object";
|
|
895
|
+
readonly required: readonly ["view"];
|
|
896
|
+
readonly additionalProperties: false;
|
|
897
|
+
readonly properties: {
|
|
898
|
+
readonly params: {
|
|
899
|
+
readonly type: "object";
|
|
900
|
+
readonly additionalProperties: {
|
|
901
|
+
readonly $ref: "#/$defs/ParamDef";
|
|
902
|
+
};
|
|
903
|
+
};
|
|
904
|
+
readonly view: {
|
|
905
|
+
readonly $ref: "#/$defs/ViewNode";
|
|
906
|
+
};
|
|
907
|
+
};
|
|
908
|
+
};
|
|
747
909
|
};
|
|
748
910
|
};
|
|
749
911
|
|
|
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 };
|
|
912
|
+
export { type ActionDefinition, type ActionStep, BINARY_OPERATORS, type BinExpr, type BinaryOperator, type ComponentDef, type ComponentNode, 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, 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, createDuplicateActionError, createSchemaError, createUndefinedActionError, createUndefinedParamError, createUndefinedStateError, createUndefinedVarError, createUnsupportedVersionError, isActionStep, isBinExpr, isComponentNode, isConstelaError, isEachNode, isElementNode, isEventHandler, isExpression, isFetchStep, isIfNode, isListField, isLitExpr, isNotExpr, isNumberField, isParamExpr, isSetStep, isSlotNode, isStateExpr, isStateField, isStringField, isTextNode, isUpdateStep, isVarExpr, isViewNode, validateAst };
|
package/dist/index.js
CHANGED
|
@@ -21,6 +21,7 @@ var UPDATE_OPERATIONS = [
|
|
|
21
21
|
"remove"
|
|
22
22
|
];
|
|
23
23
|
var HTTP_METHODS = ["GET", "POST", "PUT", "DELETE"];
|
|
24
|
+
var PARAM_TYPES = ["string", "number", "boolean", "json"];
|
|
24
25
|
|
|
25
26
|
// src/types/guards.ts
|
|
26
27
|
function isObject(value) {
|
|
@@ -56,8 +57,17 @@ function isNotExpr(value) {
|
|
|
56
57
|
if (!isObject(value["operand"])) return false;
|
|
57
58
|
return true;
|
|
58
59
|
}
|
|
60
|
+
function isParamExpr(value) {
|
|
61
|
+
if (!isObject(value)) return false;
|
|
62
|
+
if (value["expr"] !== "param") return false;
|
|
63
|
+
if (typeof value["name"] !== "string") return false;
|
|
64
|
+
if ("path" in value && value["path"] !== void 0) {
|
|
65
|
+
if (typeof value["path"] !== "string") return false;
|
|
66
|
+
}
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
59
69
|
function isExpression(value) {
|
|
60
|
-
return isLitExpr(value) || isStateExpr(value) || isVarExpr(value) || isBinExpr(value) || isNotExpr(value);
|
|
70
|
+
return isLitExpr(value) || isStateExpr(value) || isVarExpr(value) || isBinExpr(value) || isNotExpr(value) || isParamExpr(value);
|
|
61
71
|
}
|
|
62
72
|
function isElementNode(value) {
|
|
63
73
|
if (!isObject(value)) return false;
|
|
@@ -84,8 +94,24 @@ function isEachNode(value) {
|
|
|
84
94
|
if (!isObject(value["body"])) return false;
|
|
85
95
|
return true;
|
|
86
96
|
}
|
|
97
|
+
function isComponentNode(value) {
|
|
98
|
+
if (!isObject(value)) return false;
|
|
99
|
+
if (value["kind"] !== "component") return false;
|
|
100
|
+
if (typeof value["name"] !== "string") return false;
|
|
101
|
+
if ("props" in value && value["props"] !== void 0) {
|
|
102
|
+
if (!isObject(value["props"])) return false;
|
|
103
|
+
}
|
|
104
|
+
if ("children" in value && value["children"] !== void 0) {
|
|
105
|
+
if (!Array.isArray(value["children"])) return false;
|
|
106
|
+
}
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
function isSlotNode(value) {
|
|
110
|
+
if (!isObject(value)) return false;
|
|
111
|
+
return value["kind"] === "slot";
|
|
112
|
+
}
|
|
87
113
|
function isViewNode(value) {
|
|
88
|
-
return isElementNode(value) || isTextNode(value) || isIfNode(value) || isEachNode(value);
|
|
114
|
+
return isElementNode(value) || isTextNode(value) || isIfNode(value) || isEachNode(value) || isComponentNode(value) || isSlotNode(value);
|
|
89
115
|
}
|
|
90
116
|
function isSetStep(value) {
|
|
91
117
|
if (!isObject(value)) return false;
|
|
@@ -205,6 +231,41 @@ function createUnsupportedVersionError(version) {
|
|
|
205
231
|
"/version"
|
|
206
232
|
);
|
|
207
233
|
}
|
|
234
|
+
function createComponentNotFoundError(name, path) {
|
|
235
|
+
return new ConstelaError(
|
|
236
|
+
"COMPONENT_NOT_FOUND",
|
|
237
|
+
`Component '${name}' is not defined in components`,
|
|
238
|
+
path
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
function createComponentPropMissingError(componentName, propName, path) {
|
|
242
|
+
return new ConstelaError(
|
|
243
|
+
"COMPONENT_PROP_MISSING",
|
|
244
|
+
`Component '${componentName}' requires prop '${propName}'`,
|
|
245
|
+
path
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
function createComponentCycleError(cycle, path) {
|
|
249
|
+
return new ConstelaError(
|
|
250
|
+
"COMPONENT_CYCLE",
|
|
251
|
+
`Circular component reference detected: ${cycle.join(" -> ")}`,
|
|
252
|
+
path
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
function createComponentPropTypeError(componentName, propName, expected, actual, path) {
|
|
256
|
+
return new ConstelaError(
|
|
257
|
+
"COMPONENT_PROP_TYPE",
|
|
258
|
+
`Component '${componentName}' prop '${propName}' expects ${expected}, got ${actual}`,
|
|
259
|
+
path
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
function createUndefinedParamError(paramName, path) {
|
|
263
|
+
return new ConstelaError(
|
|
264
|
+
"PARAM_UNDEFINED",
|
|
265
|
+
`Undefined param reference: '${paramName}' is not defined in component params`,
|
|
266
|
+
path
|
|
267
|
+
);
|
|
268
|
+
}
|
|
208
269
|
|
|
209
270
|
// src/schema/validator.ts
|
|
210
271
|
import Ajv from "ajv";
|
|
@@ -237,6 +298,10 @@ var astSchema = {
|
|
|
237
298
|
},
|
|
238
299
|
view: {
|
|
239
300
|
$ref: "#/$defs/ViewNode"
|
|
301
|
+
},
|
|
302
|
+
components: {
|
|
303
|
+
type: "object",
|
|
304
|
+
additionalProperties: { $ref: "#/$defs/ComponentDef" }
|
|
240
305
|
}
|
|
241
306
|
},
|
|
242
307
|
$defs: {
|
|
@@ -247,7 +312,8 @@ var astSchema = {
|
|
|
247
312
|
{ $ref: "#/$defs/StateExpr" },
|
|
248
313
|
{ $ref: "#/$defs/VarExpr" },
|
|
249
314
|
{ $ref: "#/$defs/BinExpr" },
|
|
250
|
-
{ $ref: "#/$defs/NotExpr" }
|
|
315
|
+
{ $ref: "#/$defs/NotExpr" },
|
|
316
|
+
{ $ref: "#/$defs/ParamExpr" }
|
|
251
317
|
]
|
|
252
318
|
},
|
|
253
319
|
LitExpr: {
|
|
@@ -309,6 +375,16 @@ var astSchema = {
|
|
|
309
375
|
operand: { $ref: "#/$defs/Expression" }
|
|
310
376
|
}
|
|
311
377
|
},
|
|
378
|
+
ParamExpr: {
|
|
379
|
+
type: "object",
|
|
380
|
+
required: ["expr", "name"],
|
|
381
|
+
additionalProperties: false,
|
|
382
|
+
properties: {
|
|
383
|
+
expr: { type: "string", const: "param" },
|
|
384
|
+
name: { type: "string" },
|
|
385
|
+
path: { type: "string" }
|
|
386
|
+
}
|
|
387
|
+
},
|
|
312
388
|
// ==================== State Fields ====================
|
|
313
389
|
StateField: {
|
|
314
390
|
oneOf: [
|
|
@@ -429,7 +505,9 @@ var astSchema = {
|
|
|
429
505
|
{ $ref: "#/$defs/ElementNode" },
|
|
430
506
|
{ $ref: "#/$defs/TextNode" },
|
|
431
507
|
{ $ref: "#/$defs/IfNode" },
|
|
432
|
-
{ $ref: "#/$defs/EachNode" }
|
|
508
|
+
{ $ref: "#/$defs/EachNode" },
|
|
509
|
+
{ $ref: "#/$defs/ComponentNode" },
|
|
510
|
+
{ $ref: "#/$defs/SlotNode" }
|
|
433
511
|
]
|
|
434
512
|
},
|
|
435
513
|
ElementNode: {
|
|
@@ -486,6 +564,56 @@ var astSchema = {
|
|
|
486
564
|
key: { $ref: "#/$defs/Expression" },
|
|
487
565
|
body: { $ref: "#/$defs/ViewNode" }
|
|
488
566
|
}
|
|
567
|
+
},
|
|
568
|
+
ComponentNode: {
|
|
569
|
+
type: "object",
|
|
570
|
+
required: ["kind", "name"],
|
|
571
|
+
additionalProperties: false,
|
|
572
|
+
properties: {
|
|
573
|
+
kind: { type: "string", const: "component" },
|
|
574
|
+
name: { type: "string" },
|
|
575
|
+
props: {
|
|
576
|
+
type: "object",
|
|
577
|
+
additionalProperties: { $ref: "#/$defs/Expression" }
|
|
578
|
+
},
|
|
579
|
+
children: {
|
|
580
|
+
type: "array",
|
|
581
|
+
items: { $ref: "#/$defs/ViewNode" }
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
},
|
|
585
|
+
SlotNode: {
|
|
586
|
+
type: "object",
|
|
587
|
+
required: ["kind"],
|
|
588
|
+
additionalProperties: false,
|
|
589
|
+
properties: {
|
|
590
|
+
kind: { type: "string", const: "slot" }
|
|
591
|
+
}
|
|
592
|
+
},
|
|
593
|
+
// ==================== Component Definition ====================
|
|
594
|
+
ParamDef: {
|
|
595
|
+
type: "object",
|
|
596
|
+
required: ["type"],
|
|
597
|
+
additionalProperties: false,
|
|
598
|
+
properties: {
|
|
599
|
+
type: {
|
|
600
|
+
type: "string",
|
|
601
|
+
enum: ["string", "number", "boolean", "json"]
|
|
602
|
+
},
|
|
603
|
+
required: { type: "boolean" }
|
|
604
|
+
}
|
|
605
|
+
},
|
|
606
|
+
ComponentDef: {
|
|
607
|
+
type: "object",
|
|
608
|
+
required: ["view"],
|
|
609
|
+
additionalProperties: false,
|
|
610
|
+
properties: {
|
|
611
|
+
params: {
|
|
612
|
+
type: "object",
|
|
613
|
+
additionalProperties: { $ref: "#/$defs/ParamDef" }
|
|
614
|
+
},
|
|
615
|
+
view: { $ref: "#/$defs/ViewNode" }
|
|
616
|
+
}
|
|
489
617
|
}
|
|
490
618
|
}
|
|
491
619
|
};
|
|
@@ -500,8 +628,9 @@ var validate = ajv.compile(astSchema);
|
|
|
500
628
|
function isObject2(value) {
|
|
501
629
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
502
630
|
}
|
|
503
|
-
var VALID_VIEW_KINDS = ["element", "text", "if", "each"];
|
|
504
|
-
var VALID_EXPR_TYPES = ["lit", "state", "var", "bin", "not"];
|
|
631
|
+
var VALID_VIEW_KINDS = ["element", "text", "if", "each", "component", "slot"];
|
|
632
|
+
var VALID_EXPR_TYPES = ["lit", "state", "var", "bin", "not", "param"];
|
|
633
|
+
var VALID_PARAM_TYPES = ["string", "number", "boolean", "json"];
|
|
505
634
|
var VALID_ACTION_TYPES = ["set", "update", "fetch"];
|
|
506
635
|
var VALID_STATE_TYPES = ["number", "string", "list"];
|
|
507
636
|
var VALID_BIN_OPS = BINARY_OPERATORS;
|
|
@@ -516,7 +645,7 @@ function validateViewNode(node, path) {
|
|
|
516
645
|
return { path: path + "/kind", message: "kind is required" };
|
|
517
646
|
}
|
|
518
647
|
if (!VALID_VIEW_KINDS.includes(kind)) {
|
|
519
|
-
return { path: path + "/kind", message: "must be one of: element, text, if, each" };
|
|
648
|
+
return { path: path + "/kind", message: "must be one of: element, text, if, each, component, slot" };
|
|
520
649
|
}
|
|
521
650
|
switch (kind) {
|
|
522
651
|
case "element":
|
|
@@ -579,6 +708,25 @@ function validateViewNode(node, path) {
|
|
|
579
708
|
if (bodyError) return bodyError;
|
|
580
709
|
}
|
|
581
710
|
break;
|
|
711
|
+
case "component":
|
|
712
|
+
if (typeof node["name"] !== "string") {
|
|
713
|
+
return { path: path + "/name", message: "name is required" };
|
|
714
|
+
}
|
|
715
|
+
if (node["props"] !== void 0 && isObject2(node["props"])) {
|
|
716
|
+
for (const [propName, propValue] of Object.entries(node["props"])) {
|
|
717
|
+
const error = validateExpression(propValue, path + "/props/" + propName);
|
|
718
|
+
if (error) return error;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
if (Array.isArray(node["children"])) {
|
|
722
|
+
for (let i = 0; i < node["children"].length; i++) {
|
|
723
|
+
const error = validateViewNode(node["children"][i], path + "/children/" + i);
|
|
724
|
+
if (error) return error;
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
break;
|
|
728
|
+
case "slot":
|
|
729
|
+
break;
|
|
582
730
|
}
|
|
583
731
|
return null;
|
|
584
732
|
}
|
|
@@ -591,7 +739,7 @@ function validateExpression(expr, path) {
|
|
|
591
739
|
return { path: path + "/expr", message: "expr is required" };
|
|
592
740
|
}
|
|
593
741
|
if (!VALID_EXPR_TYPES.includes(exprType)) {
|
|
594
|
-
return { path: path + "/expr", message: "must be one of: lit, state, var, bin, not" };
|
|
742
|
+
return { path: path + "/expr", message: "must be one of: lit, state, var, bin, not, param" };
|
|
595
743
|
}
|
|
596
744
|
switch (exprType) {
|
|
597
745
|
case "lit":
|
|
@@ -630,6 +778,14 @@ function validateExpression(expr, path) {
|
|
|
630
778
|
return { path: path + "/operand", message: "operand is required" };
|
|
631
779
|
}
|
|
632
780
|
return validateExpression(expr["operand"], path + "/operand");
|
|
781
|
+
case "param":
|
|
782
|
+
if (typeof expr["name"] !== "string") {
|
|
783
|
+
return { path: path + "/name", message: "name is required" };
|
|
784
|
+
}
|
|
785
|
+
if ("path" in expr && typeof expr["path"] !== "string") {
|
|
786
|
+
return { path: path + "/path", message: "path must be a string" };
|
|
787
|
+
}
|
|
788
|
+
break;
|
|
633
789
|
}
|
|
634
790
|
return null;
|
|
635
791
|
}
|
|
@@ -721,6 +877,39 @@ function validateStateField(field, path) {
|
|
|
721
877
|
}
|
|
722
878
|
return null;
|
|
723
879
|
}
|
|
880
|
+
function validateParamDef(param, path) {
|
|
881
|
+
if (!isObject2(param)) {
|
|
882
|
+
return { path, message: "must be an object" };
|
|
883
|
+
}
|
|
884
|
+
const paramType = param["type"];
|
|
885
|
+
if (typeof paramType !== "string") {
|
|
886
|
+
return { path: path + "/type", message: "type is required" };
|
|
887
|
+
}
|
|
888
|
+
if (!VALID_PARAM_TYPES.includes(paramType)) {
|
|
889
|
+
return { path: path + "/type", message: "must be one of: string, number, boolean, json" };
|
|
890
|
+
}
|
|
891
|
+
if ("required" in param && typeof param["required"] !== "boolean") {
|
|
892
|
+
return { path: path + "/required", message: "required must be a boolean" };
|
|
893
|
+
}
|
|
894
|
+
return null;
|
|
895
|
+
}
|
|
896
|
+
function validateComponentDef(def, path) {
|
|
897
|
+
if (!isObject2(def)) {
|
|
898
|
+
return { path, message: "must be an object" };
|
|
899
|
+
}
|
|
900
|
+
if (!("view" in def)) {
|
|
901
|
+
return { path: path + "/view", message: "view is required" };
|
|
902
|
+
}
|
|
903
|
+
if ("params" in def && isObject2(def["params"])) {
|
|
904
|
+
for (const [paramName, paramDef] of Object.entries(def["params"])) {
|
|
905
|
+
const error = validateParamDef(paramDef, path + "/params/" + paramName);
|
|
906
|
+
if (error) return error;
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
const viewError = validateViewNode(def["view"], path + "/view");
|
|
910
|
+
if (viewError) return viewError;
|
|
911
|
+
return null;
|
|
912
|
+
}
|
|
724
913
|
function customValidateAst(input) {
|
|
725
914
|
if (isObject2(input["state"])) {
|
|
726
915
|
for (const [name, field] of Object.entries(input["state"])) {
|
|
@@ -743,6 +932,12 @@ function customValidateAst(input) {
|
|
|
743
932
|
const error = validateViewNode(input["view"], "/view");
|
|
744
933
|
if (error) return error;
|
|
745
934
|
}
|
|
935
|
+
if ("components" in input && isObject2(input["components"])) {
|
|
936
|
+
for (const [name, def] of Object.entries(input["components"])) {
|
|
937
|
+
const error = validateComponentDef(def, "/components/" + name);
|
|
938
|
+
if (error) return error;
|
|
939
|
+
}
|
|
940
|
+
}
|
|
746
941
|
return null;
|
|
747
942
|
}
|
|
748
943
|
function findTopLevelRequiredError(errors) {
|
|
@@ -943,16 +1138,23 @@ export {
|
|
|
943
1138
|
BINARY_OPERATORS,
|
|
944
1139
|
ConstelaError,
|
|
945
1140
|
HTTP_METHODS,
|
|
1141
|
+
PARAM_TYPES,
|
|
946
1142
|
UPDATE_OPERATIONS,
|
|
947
1143
|
astSchema,
|
|
1144
|
+
createComponentCycleError,
|
|
1145
|
+
createComponentNotFoundError,
|
|
1146
|
+
createComponentPropMissingError,
|
|
1147
|
+
createComponentPropTypeError,
|
|
948
1148
|
createDuplicateActionError,
|
|
949
1149
|
createSchemaError,
|
|
950
1150
|
createUndefinedActionError,
|
|
1151
|
+
createUndefinedParamError,
|
|
951
1152
|
createUndefinedStateError,
|
|
952
1153
|
createUndefinedVarError,
|
|
953
1154
|
createUnsupportedVersionError,
|
|
954
1155
|
isActionStep,
|
|
955
1156
|
isBinExpr,
|
|
1157
|
+
isComponentNode,
|
|
956
1158
|
isConstelaError,
|
|
957
1159
|
isEachNode,
|
|
958
1160
|
isElementNode,
|
|
@@ -964,7 +1166,9 @@ export {
|
|
|
964
1166
|
isLitExpr,
|
|
965
1167
|
isNotExpr,
|
|
966
1168
|
isNumberField,
|
|
1169
|
+
isParamExpr,
|
|
967
1170
|
isSetStep,
|
|
1171
|
+
isSlotNode,
|
|
968
1172
|
isStateExpr,
|
|
969
1173
|
isStateField,
|
|
970
1174
|
isStringField,
|