@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 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
- type Expression = LitExpr | StateExpr | VarExpr | BinExpr | NotExpr;
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
- type ViewNode = ElementNode | TextNode | IfNode | EachNode;
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,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@constela/core",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Core types, schema, and validator for Constela UI framework",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",