@builder-builder/builder 0.0.13 → 0.0.15

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.
Files changed (96) hide show
  1. package/dist/bb.d.ts +3 -1
  2. package/dist/bb.js +6 -1
  3. package/dist/check.d.ts +2 -2
  4. package/dist/cli.d.ts +2 -0
  5. package/dist/cli.js +53 -0
  6. package/dist/codegen/index.d.ts +7 -0
  7. package/dist/codegen/index.js +212 -0
  8. package/dist/codegen/template.d.ts +5 -0
  9. package/dist/codegen/template.js +17 -0
  10. package/dist/entities/builder/builder.d.ts +11 -1
  11. package/dist/entities/builder/builder.js +22 -6
  12. package/dist/entities/collection/collection.d.ts +7 -1
  13. package/dist/entities/collection/collection.js +9 -2
  14. package/dist/entities/collection/config.d.ts +6 -1
  15. package/dist/entities/collection/config.js +9 -2
  16. package/dist/entities/component/component.d.ts +41 -1
  17. package/dist/entities/component/component.js +9 -2
  18. package/dist/entities/component/details.d.ts +11 -2
  19. package/dist/entities/component/details.js +9 -2
  20. package/dist/entities/component/field.d.ts +10 -1
  21. package/dist/entities/component/field.js +13 -3
  22. package/dist/entities/index.d.ts +7 -3
  23. package/dist/entities/index.js +3 -1
  24. package/dist/entities/kind.d.ts +1 -1
  25. package/dist/entities/model/model.d.ts +5 -1
  26. package/dist/entities/model/model.js +10 -3
  27. package/dist/entities/model/models.js +9 -5
  28. package/dist/entities/option/option.d.ts +41 -1
  29. package/dist/entities/option/option.js +9 -2
  30. package/dist/entities/option/select.d.ts +7 -1
  31. package/dist/entities/option/select.js +17 -6
  32. package/dist/entities/option/toggle.d.ts +7 -1
  33. package/dist/entities/option/toggle.js +16 -4
  34. package/dist/entities/option/values.d.ts +6 -0
  35. package/dist/entities/pricing.d.ts +64 -0
  36. package/dist/entities/pricing.js +48 -0
  37. package/dist/entities/serialise.d.ts +632 -8
  38. package/dist/entities/serialise.js +33 -12
  39. package/dist/entities/tags.d.ts +3 -0
  40. package/dist/entities/tags.js +2 -0
  41. package/dist/entities/ui/describe.d.ts +231 -8
  42. package/dist/entities/ui/describe.js +12 -5
  43. package/dist/entities/ui/index.d.ts +2 -0
  44. package/dist/entities/ui/index.js +1 -0
  45. package/dist/entities/ui/input.d.ts +343 -0
  46. package/dist/entities/ui/input.js +51 -0
  47. package/dist/entities/ui/page.d.ts +231 -8
  48. package/dist/entities/ui/page.js +12 -5
  49. package/dist/entities/ui/pages.d.ts +5 -1
  50. package/dist/entities/ui/pages.js +9 -2
  51. package/dist/entities/ui/ui.d.ts +9 -4
  52. package/dist/entities/ui/ui.js +29 -11
  53. package/dist/entities/validated.d.ts +7 -3
  54. package/dist/exception.d.ts +2 -2
  55. package/dist/index.d.ts +3 -3
  56. package/dist/index.js +1 -1
  57. package/dist/instance.d.ts +9 -0
  58. package/dist/instance.js +3 -1
  59. package/dist/mappers/index.d.ts +6 -4
  60. package/dist/mappers/index.js +3 -2
  61. package/dist/mappers/pricing.d.ts +3 -0
  62. package/dist/mappers/pricing.js +101 -0
  63. package/dist/mappers/render/index.d.ts +1 -1
  64. package/dist/mappers/render/pages.d.ts +8 -0
  65. package/dist/mappers/render/pages.js +2 -1
  66. package/dist/mappers/render/render.js +19 -3
  67. package/dist/mappers/resolve.d.ts +4 -4
  68. package/dist/mappers/variants/index.d.ts +2 -1
  69. package/dist/mappers/variants/index.js +2 -1
  70. package/dist/mappers/variants/variants.d.ts +5 -2
  71. package/dist/mappers/variants/variants.js +2 -2
  72. package/dist/validate/brand.d.ts +0 -7
  73. package/dist/validate/brand.js +5 -5
  74. package/dist/validate/builder.d.ts +2 -1
  75. package/dist/validate/builder.js +19 -13
  76. package/dist/validate/errors.d.ts +138 -0
  77. package/dist/validate/errors.js +148 -0
  78. package/dist/validate/expectations.d.ts +3 -10
  79. package/dist/validate/expectations.js +8 -10
  80. package/dist/validate/index.d.ts +10 -14
  81. package/dist/validate/index.js +5 -7
  82. package/dist/validate/instance.d.ts +2 -15
  83. package/dist/validate/instance.js +41 -40
  84. package/dist/validate/model.d.ts +4 -31
  85. package/dist/validate/model.js +157 -176
  86. package/dist/validate/pricing.d.ts +6 -0
  87. package/dist/validate/pricing.js +71 -0
  88. package/dist/validate/resolve.d.ts +3 -15
  89. package/dist/validate/resolve.js +66 -69
  90. package/dist/validate/result.d.ts +1 -7
  91. package/dist/validate/result.js +1 -4
  92. package/dist/validate/ui.d.ts +4 -4
  93. package/dist/validate/ui.js +80 -62
  94. package/dist/validate/variants.d.ts +2 -53
  95. package/dist/validate/variants.js +83 -86
  96. package/package.json +12 -3
@@ -24,10 +24,10 @@ function buildVariants(model) {
24
24
  ]))
25
25
  };
26
26
  }
27
- function optionGraph(model) {
27
+ export function optionGraph(model) {
28
28
  return model.options.reduce((graph, option) => graph.add(option, model), new BuilderOptionGraph());
29
29
  }
30
- function variantsFor(entity, options) {
30
+ export function variantsFor(entity, options) {
31
31
  const keys = new Set(dependencyKeys(entity.payload, entity.paths));
32
32
  const graphPaths = Array.from(keys)
33
33
  .map((key) => options.get(key))
@@ -1,14 +1,7 @@
1
- import type { BuilderErrorLocation } from '../exception';
2
1
  declare const VALIDATED: unique symbol;
3
2
  export type BuilderValidatedBrand = {
4
3
  readonly [VALIDATED]: true;
5
4
  };
6
- export declare function builderErrorUnvalidated(value: unknown, location?: BuilderErrorLocation): {
7
- value: unknown;
8
- kind: "unvalidated";
9
- location: BuilderErrorLocation;
10
- };
11
- export type BuilderErrorUnvalidated = ReturnType<typeof builderErrorUnvalidated>;
12
5
  export declare function validate<Input extends object>(value: Input): Input & BuilderValidatedBrand;
13
6
  export declare function assertValidated<Input>(value: Input): asserts value is Input & BuilderValidatedBrand;
14
7
  export {};
@@ -1,8 +1,6 @@
1
- import { builderError, BuilderException } from '../exception.js';
1
+ import { BuilderException } from '../exception.js';
2
+ import { BuilderValidateErrors } from './errors.js';
2
3
  const VALIDATED = Symbol('builder.validated');
3
- export function builderErrorUnvalidated(value, location = []) {
4
- return { ...builderError('unvalidated', location), value };
5
- }
6
4
  export function validate(value) {
7
5
  // Descriptor flags chosen for Svelte 5 `$state` proxy compatibility — `$state`
8
6
  // rejects any property that isn't writable, configurable, and enumerable.
@@ -18,6 +16,8 @@ export function validate(value) {
18
16
  }
19
17
  export function assertValidated(value) {
20
18
  if (typeof value !== 'object' || value === null || !(VALIDATED in value)) {
21
- throw new BuilderException([builderErrorUnvalidated(value)]);
19
+ const errors = new BuilderValidateErrors();
20
+ errors.unvalidated(value);
21
+ throw new BuilderException(errors.errors);
22
22
  }
23
23
  }
@@ -1,4 +1,5 @@
1
1
  import type { BuilderRefEntities, BuilderValidated } from '../entities/index';
2
2
  import type { ValidationResult } from './result';
3
+ import { BuilderValidateErrors } from './errors.js';
3
4
  export type BuilderValidationResult = ValidationResult<BuilderValidated>;
4
- export declare function validateBuilder(input: unknown, references?: BuilderRefEntities): BuilderValidationResult;
5
+ export declare function validateBuilder(input: unknown, references?: BuilderRefEntities, errors?: BuilderValidateErrors): BuilderValidationResult;
@@ -1,27 +1,33 @@
1
1
  import { check } from '../check.js';
2
2
  import { builder, BuilderSerialisedSchema, modelsMerge, serialise } from '../entities/index.js';
3
3
  import { validate } from './brand.js';
4
+ import { BuilderValidateErrors } from './errors.js';
4
5
  import { checkModelExpectations, validateModelStructure } from './model.js';
6
+ import { validatePricingStructure } from './pricing.js';
5
7
  import { resolver } from './resolve.js';
6
- import { builderErrorInvalidInput } from './result.js';
7
8
  import { checkUIExpectations, validateUIStructure } from './ui.js';
8
- export function validateBuilder(input, references = []) {
9
+ export function validateBuilder(input, references = [], errors = new BuilderValidateErrors()) {
9
10
  if (!check.is(BuilderSerialisedSchema, input)) {
10
- const errors = [builderErrorInvalidInput('builder')];
11
- return [validate(serialise.builder(builder())), errors];
11
+ errors.invalidInput('builder');
12
+ return [validate(serialise.builder(builder())), errors.errors];
12
13
  }
13
- const resolve = resolver(references, input.bindings);
14
- const [validatedModel, modelErrors] = validateModelStructure(input.model, resolve, ['model']);
15
- const [validatedUI, uiErrors] = validateUIStructure(input.ui, resolve, ['ui']);
14
+ const resolve = resolver(errors, references, input.bindings);
15
+ const validatedModel = errors.scope('model', () => validateModelStructure(input.model, resolve, errors));
16
+ const validatedUI = errors.scope('ui', () => validateUIStructure(input.ui, resolve, errors));
16
17
  const mergedModel = modelsMerge(validatedModel);
17
- const expectationErrors = [
18
- ...checkModelExpectations(mergedModel, validatedModel, ['model']),
19
- ...checkUIExpectations(mergedModel, validatedUI, ['ui'])
20
- ];
18
+ errors.scope('model', () => {
19
+ checkModelExpectations(mergedModel, validatedModel, errors);
20
+ });
21
+ errors.scope('ui', () => {
22
+ checkUIExpectations(mergedModel, validatedUI, errors);
23
+ });
24
+ if (input.pricing) {
25
+ errors.scope('pricing', () => validatePricingStructure(resolve(input.pricing) ?? input.pricing, errors));
26
+ }
21
27
  const data = validate({
22
- ...serialise.builder(builder()),
28
+ ...input,
23
29
  model: mergedModel,
24
30
  ui: validatedUI
25
31
  });
26
- return [data, [...expectationErrors, ...modelErrors, ...uiErrors]];
32
+ return [data, errors.errors];
27
33
  }
@@ -0,0 +1,138 @@
1
+ import type { BuilderExpectationKind } from '../entities/index';
2
+ import type { BuilderErrorLocation, BuilderErrors } from '../exception';
3
+ import type { BuilderInstance } from '../instance';
4
+ export type BuilderInvalidInputTarget = 'builder' | 'model' | 'pricing' | 'ui' | 'variants';
5
+ export type BuilderErrorInvalidPathReason = 'shape' | 'out-of-bounds' | 'missing-collection' | 'option-not-found';
6
+ export type BuilderErrorInvalidPricingReason = 'scope' | 'nested-variants' | 'missing-rate' | 'invalid-filter';
7
+ export declare class BuilderValidateErrors {
8
+ #private;
9
+ get errors(): BuilderErrors;
10
+ scope<Result>(part: string | number, fn: () => Result): Result;
11
+ invalidInput(target: BuilderInvalidInputTarget): {
12
+ target: BuilderInvalidInputTarget;
13
+ kind: "invalid-input";
14
+ location: BuilderErrorLocation;
15
+ };
16
+ invalidOption(name: string, value: unknown): {
17
+ name: string;
18
+ value: unknown;
19
+ kind: "invalid-option";
20
+ location: BuilderErrorLocation;
21
+ };
22
+ invalidCollection(name: string): {
23
+ name: string;
24
+ kind: "invalid-collection";
25
+ location: BuilderErrorLocation;
26
+ };
27
+ duplicateName(name: string): {
28
+ name: string;
29
+ kind: "duplicate-name";
30
+ location: BuilderErrorLocation;
31
+ };
32
+ invalidCollectionBounds(name: string, min: number, max: number): {
33
+ name: string;
34
+ min: number;
35
+ max: number;
36
+ kind: "invalid-collection-bounds";
37
+ location: BuilderErrorLocation;
38
+ };
39
+ invalidPath(reason: BuilderErrorInvalidPathReason): {
40
+ reason: BuilderErrorInvalidPathReason;
41
+ kind: "invalid-path";
42
+ location: BuilderErrorLocation;
43
+ };
44
+ invalidSelectMapKey(key: string): {
45
+ key: string;
46
+ kind: "invalid-select-map-key";
47
+ location: BuilderErrorLocation;
48
+ };
49
+ unboundParameter(name: string): {
50
+ name: string;
51
+ kind: "unbound-parameter";
52
+ location: BuilderErrorLocation;
53
+ };
54
+ missingReference(id: string): {
55
+ id: string;
56
+ kind: "missing-reference";
57
+ location: BuilderErrorLocation;
58
+ };
59
+ unmetExpectation(expectationKind: BuilderExpectationKind, name: string): {
60
+ expectationKind: "option" | "component" | "collection";
61
+ name: string;
62
+ kind: "unmet-expectation";
63
+ location: BuilderErrorLocation;
64
+ };
65
+ unvalidated(value: unknown): {
66
+ value: unknown;
67
+ kind: "unvalidated";
68
+ location: BuilderErrorLocation;
69
+ };
70
+ missingComponent(component: string): {
71
+ component: string;
72
+ kind: "missing-component";
73
+ location: BuilderErrorLocation;
74
+ };
75
+ unexpectedComponent(component: string): {
76
+ component: string;
77
+ kind: "unexpected-component";
78
+ location: BuilderErrorLocation;
79
+ };
80
+ missingVariant(component: string, instance: BuilderInstance): {
81
+ component: string;
82
+ instance: BuilderInstance;
83
+ kind: "missing-variant";
84
+ location: BuilderErrorLocation;
85
+ };
86
+ invalidVariant(component: string, instance: BuilderInstance): {
87
+ component: string;
88
+ instance: BuilderInstance;
89
+ kind: "invalid-variant";
90
+ location: BuilderErrorLocation;
91
+ };
92
+ missingDetail(component: string, detail: string, instance: BuilderInstance): {
93
+ component: string;
94
+ detail: string;
95
+ instance: BuilderInstance;
96
+ kind: "missing-detail";
97
+ location: BuilderErrorLocation;
98
+ };
99
+ unexpectedDetail(component: string, detail: string, instance: BuilderInstance): {
100
+ component: string;
101
+ detail: string;
102
+ instance: BuilderInstance;
103
+ kind: "unexpected-detail";
104
+ location: BuilderErrorLocation;
105
+ };
106
+ invalidDetail(component: string, detail: string, instance: BuilderInstance): {
107
+ component: string;
108
+ detail: string;
109
+ instance: BuilderInstance;
110
+ kind: "invalid-detail";
111
+ location: BuilderErrorLocation;
112
+ };
113
+ invalidPricing(reason: BuilderErrorInvalidPricingReason, detail?: string): {
114
+ reason: BuilderErrorInvalidPricingReason;
115
+ detail: string | undefined;
116
+ kind: "invalid-pricing";
117
+ location: BuilderErrorLocation;
118
+ };
119
+ }
120
+ export type BuilderErrorInvalidInput = ReturnType<BuilderValidateErrors['invalidInput']>;
121
+ export type BuilderErrorInvalidOption = ReturnType<BuilderValidateErrors['invalidOption']>;
122
+ export type BuilderErrorInvalidCollection = ReturnType<BuilderValidateErrors['invalidCollection']>;
123
+ export type BuilderErrorDuplicateName = ReturnType<BuilderValidateErrors['duplicateName']>;
124
+ export type BuilderErrorInvalidCollectionBounds = ReturnType<BuilderValidateErrors['invalidCollectionBounds']>;
125
+ export type BuilderErrorInvalidPath = ReturnType<BuilderValidateErrors['invalidPath']>;
126
+ export type BuilderErrorInvalidSelectMapKey = ReturnType<BuilderValidateErrors['invalidSelectMapKey']>;
127
+ export type BuilderErrorUnboundParameter = ReturnType<BuilderValidateErrors['unboundParameter']>;
128
+ export type BuilderErrorMissingReference = ReturnType<BuilderValidateErrors['missingReference']>;
129
+ export type BuilderErrorUnmetExpectation = ReturnType<BuilderValidateErrors['unmetExpectation']>;
130
+ export type BuilderErrorUnvalidated = ReturnType<BuilderValidateErrors['unvalidated']>;
131
+ export type BuilderErrorMissingComponent = ReturnType<BuilderValidateErrors['missingComponent']>;
132
+ export type BuilderErrorUnexpectedComponent = ReturnType<BuilderValidateErrors['unexpectedComponent']>;
133
+ export type BuilderErrorMissingVariant = ReturnType<BuilderValidateErrors['missingVariant']>;
134
+ export type BuilderErrorInvalidVariant = ReturnType<BuilderValidateErrors['invalidVariant']>;
135
+ export type BuilderErrorMissingDetail = ReturnType<BuilderValidateErrors['missingDetail']>;
136
+ export type BuilderErrorUnexpectedDetail = ReturnType<BuilderValidateErrors['unexpectedDetail']>;
137
+ export type BuilderErrorInvalidDetail = ReturnType<BuilderValidateErrors['invalidDetail']>;
138
+ export type BuilderErrorInvalidPricing = ReturnType<BuilderValidateErrors['invalidPricing']>;
@@ -0,0 +1,148 @@
1
+ import { builderError } from '../exception.js';
2
+ export class BuilderValidateErrors {
3
+ #errors = [];
4
+ #location = [];
5
+ get errors() {
6
+ return this.#errors;
7
+ }
8
+ scope(part, fn) {
9
+ this.#location = [...this.#location, part];
10
+ try {
11
+ return fn();
12
+ }
13
+ finally {
14
+ this.#location = this.#location.slice(0, -1);
15
+ }
16
+ }
17
+ invalidInput(target) {
18
+ return this.#addError({
19
+ ...builderError('invalid-input', this.#location),
20
+ target
21
+ });
22
+ }
23
+ invalidOption(name, value) {
24
+ return this.#addError({
25
+ ...builderError('invalid-option', this.#location),
26
+ name,
27
+ value
28
+ });
29
+ }
30
+ invalidCollection(name) {
31
+ return this.#addError({
32
+ ...builderError('invalid-collection', this.#location),
33
+ name
34
+ });
35
+ }
36
+ duplicateName(name) {
37
+ return this.#addError({
38
+ ...builderError('duplicate-name', this.#location),
39
+ name
40
+ });
41
+ }
42
+ invalidCollectionBounds(name, min, max) {
43
+ return this.#addError({
44
+ ...builderError('invalid-collection-bounds', this.#location),
45
+ name,
46
+ min,
47
+ max
48
+ });
49
+ }
50
+ invalidPath(reason) {
51
+ return this.#addError({
52
+ ...builderError('invalid-path', this.#location),
53
+ reason
54
+ });
55
+ }
56
+ invalidSelectMapKey(key) {
57
+ return this.#addError({
58
+ ...builderError('invalid-select-map-key', this.#location),
59
+ key
60
+ });
61
+ }
62
+ unboundParameter(name) {
63
+ return this.#addError({
64
+ ...builderError('unbound-parameter', this.#location),
65
+ name
66
+ });
67
+ }
68
+ missingReference(id) {
69
+ return this.#addError({
70
+ ...builderError('missing-reference', this.#location),
71
+ id
72
+ });
73
+ }
74
+ unmetExpectation(expectationKind, name) {
75
+ return this.#addError({
76
+ ...builderError('unmet-expectation', this.#location),
77
+ expectationKind,
78
+ name
79
+ });
80
+ }
81
+ unvalidated(value) {
82
+ return this.#addError({
83
+ ...builderError('unvalidated', this.#location),
84
+ value
85
+ });
86
+ }
87
+ missingComponent(component) {
88
+ return this.#addError({
89
+ ...builderError('missing-component', this.#location),
90
+ component
91
+ });
92
+ }
93
+ unexpectedComponent(component) {
94
+ return this.#addError({
95
+ ...builderError('unexpected-component', this.#location),
96
+ component
97
+ });
98
+ }
99
+ missingVariant(component, instance) {
100
+ return this.#addError({
101
+ ...builderError('missing-variant', this.#location),
102
+ component,
103
+ instance
104
+ });
105
+ }
106
+ invalidVariant(component, instance) {
107
+ return this.#addError({
108
+ ...builderError('invalid-variant', this.#location),
109
+ component,
110
+ instance
111
+ });
112
+ }
113
+ missingDetail(component, detail, instance) {
114
+ return this.#addError({
115
+ ...builderError('missing-detail', this.#location),
116
+ component,
117
+ detail,
118
+ instance
119
+ });
120
+ }
121
+ unexpectedDetail(component, detail, instance) {
122
+ return this.#addError({
123
+ ...builderError('unexpected-detail', this.#location),
124
+ component,
125
+ detail,
126
+ instance
127
+ });
128
+ }
129
+ invalidDetail(component, detail, instance) {
130
+ return this.#addError({
131
+ ...builderError('invalid-detail', this.#location),
132
+ component,
133
+ detail,
134
+ instance
135
+ });
136
+ }
137
+ invalidPricing(reason, detail) {
138
+ return this.#addError({
139
+ ...builderError('invalid-pricing', this.#location),
140
+ reason,
141
+ detail
142
+ });
143
+ }
144
+ #addError(error) {
145
+ this.#errors = [...this.#errors, error];
146
+ return error;
147
+ }
148
+ }
@@ -1,10 +1,3 @@
1
- import type { BuilderExpectationKind, BuilderExpectationsSerialised, BuilderModelSerialised } from '../entities/index';
2
- import type { BuilderErrorLocation, BuilderErrors } from '../exception';
3
- export declare function builderErrorUnmetExpectation(expectationKind: BuilderExpectationKind, name: string, location?: BuilderErrorLocation): {
4
- expectationKind: "option" | "component" | "collection";
5
- name: string;
6
- kind: "unmet-expectation";
7
- location: BuilderErrorLocation;
8
- };
9
- export type BuilderErrorUnmetExpectation = ReturnType<typeof builderErrorUnmetExpectation>;
10
- export declare function checkExpectations(model: BuilderModelSerialised, expectations: BuilderExpectationsSerialised, location: BuilderErrorLocation): BuilderErrors;
1
+ import type { BuilderExpectationsSerialised, BuilderModelSerialised } from '../entities/index';
2
+ import type { BuilderValidateErrors } from './errors';
3
+ export declare function checkExpectations(model: BuilderModelSerialised, expectations: BuilderExpectationsSerialised, errors: BuilderValidateErrors): void;
@@ -1,12 +1,10 @@
1
- import { builderError } from '../exception.js';
2
- export function builderErrorUnmetExpectation(expectationKind, name, location = []) {
3
- return { ...builderError('unmet-expectation', location), expectationKind, name };
4
- }
5
- export function checkExpectations(model, expectations, location) {
6
- return expectations.flatMap(({ kind, name }, index) => {
7
- if (model[`${kind}s`].some((entry) => entry.name === name)) {
8
- return [];
9
- }
10
- return [builderErrorUnmetExpectation(kind, name, [...location, index])];
1
+ export function checkExpectations(model, expectations, errors) {
2
+ expectations.forEach(({ kind, name }, index) => {
3
+ errors.scope(index, () => {
4
+ if (model[`${kind}s`].some((entry) => entry.name === name)) {
5
+ return;
6
+ }
7
+ errors.unmetExpectation(kind, name);
8
+ });
11
9
  });
12
10
  }
@@ -1,18 +1,14 @@
1
- export type { BuilderErrorUnvalidated } from './brand';
2
1
  export type { BuilderValidationResult } from './builder';
3
- export type { BuilderErrorUnmetExpectation } from './expectations';
4
- export type { BuilderErrorInvalidCollection, BuilderErrorInvalidOption, BuilderInstanceValidationResult } from './instance';
5
- export type { BuilderErrorDuplicateName, BuilderErrorInvalidCollectionBounds, BuilderErrorInvalidPath, BuilderErrorInvalidPathReason, BuilderErrorInvalidSelectMapKey, BuilderModelValidationResult } from './model';
6
- export type { BuilderErrorMissingReference, BuilderErrorUnboundParameter } from './resolve';
7
- export type { BuilderErrorInvalidInput } from './result';
2
+ export type { BuilderErrorDuplicateName, BuilderErrorInvalidCollection, BuilderErrorInvalidCollectionBounds, BuilderErrorInvalidDetail, BuilderErrorInvalidInput, BuilderErrorInvalidOption, BuilderErrorInvalidPath, BuilderErrorInvalidPathReason, BuilderErrorInvalidPricing, BuilderErrorInvalidPricingReason, BuilderErrorInvalidSelectMapKey, BuilderErrorInvalidVariant, BuilderErrorMissingComponent, BuilderErrorMissingDetail, BuilderErrorMissingReference, BuilderErrorMissingVariant, BuilderErrorUnboundParameter, BuilderErrorUnexpectedComponent, BuilderErrorUnexpectedDetail, BuilderErrorUnmetExpectation, BuilderErrorUnvalidated, BuilderInvalidInputTarget } from './errors';
3
+ export type { BuilderInstanceValidationResult } from './instance';
4
+ export type { BuilderModelValidationResult } from './model';
5
+ export type { BuilderPricingValidationResult } from './pricing';
8
6
  export type { BuilderUIValidationResult } from './ui';
9
- export type { BuilderComponentVariantsValidationResult, BuilderErrorInvalidDetail, BuilderErrorInvalidVariant, BuilderErrorMissingComponent, BuilderErrorMissingDetail, BuilderErrorMissingVariant, BuilderErrorUnexpectedComponent, BuilderErrorUnexpectedDetail, BuilderVariantsValidationOptions } from './variants';
10
- export { assertValidated, builderErrorUnvalidated } from './brand.js';
7
+ export type { BuilderComponentVariantsValidationResult, BuilderVariantsValidationOptions } from './variants';
8
+ export { assertValidated } from './brand.js';
11
9
  export { validateBuilder } from './builder.js';
12
- export { builderErrorUnmetExpectation } from './expectations.js';
13
- export { builderErrorInvalidCollection, builderErrorInvalidOption, validateInstance } from './instance.js';
14
- export { builderErrorDuplicateName, builderErrorInvalidCollectionBounds, builderErrorInvalidPath, builderErrorInvalidSelectMapKey, validateModel } from './model.js';
15
- export { builderErrorMissingReference, builderErrorUnboundParameter } from './resolve.js';
16
- export { builderErrorInvalidInput } from './result.js';
10
+ export { validateInstance } from './instance.js';
11
+ export { validateModel } from './model.js';
12
+ export { validatePricing } from './pricing.js';
17
13
  export { validateUI } from './ui.js';
18
- export { builderErrorInvalidDetail, builderErrorInvalidVariant, builderErrorMissingComponent, builderErrorMissingDetail, builderErrorMissingVariant, builderErrorUnexpectedComponent, builderErrorUnexpectedDetail, validateVariants } from './variants.js';
14
+ export { validateVariants } from './variants.js';
@@ -1,9 +1,7 @@
1
- export { assertValidated, builderErrorUnvalidated } from './brand.js';
1
+ export { assertValidated } from './brand.js';
2
2
  export { validateBuilder } from './builder.js';
3
- export { builderErrorUnmetExpectation } from './expectations.js';
4
- export { builderErrorInvalidCollection, builderErrorInvalidOption, validateInstance } from './instance.js';
5
- export { builderErrorDuplicateName, builderErrorInvalidCollectionBounds, builderErrorInvalidPath, builderErrorInvalidSelectMapKey, validateModel } from './model.js';
6
- export { builderErrorMissingReference, builderErrorUnboundParameter } from './resolve.js';
7
- export { builderErrorInvalidInput } from './result.js';
3
+ export { validateInstance } from './instance.js';
4
+ export { validateModel } from './model.js';
5
+ export { validatePricing } from './pricing.js';
8
6
  export { validateUI } from './ui.js';
9
- export { builderErrorInvalidDetail, builderErrorInvalidVariant, builderErrorMissingComponent, builderErrorMissingDetail, builderErrorMissingVariant, builderErrorUnexpectedComponent, builderErrorUnexpectedDetail, validateVariants } from './variants.js';
7
+ export { validateVariants } from './variants.js';
@@ -1,19 +1,6 @@
1
1
  import type { BuilderInstanceValidated, BuilderModelValidated } from '../entities/index';
2
- import type { BuilderErrorLocation } from '../exception';
3
2
  import type { BuilderInstance } from '../instance';
4
3
  import type { ValidationResult } from './result';
5
- export declare function builderErrorInvalidOption(name: string, value: unknown, location?: BuilderErrorLocation): {
6
- name: string;
7
- value: unknown;
8
- kind: "invalid-option";
9
- location: BuilderErrorLocation;
10
- };
11
- export type BuilderErrorInvalidOption = ReturnType<typeof builderErrorInvalidOption>;
12
- export declare function builderErrorInvalidCollection(name: string, location?: BuilderErrorLocation): {
13
- name: string;
14
- kind: "invalid-collection";
15
- location: BuilderErrorLocation;
16
- };
17
- export type BuilderErrorInvalidCollection = ReturnType<typeof builderErrorInvalidCollection>;
4
+ import { BuilderValidateErrors } from './errors.js';
18
5
  export type BuilderInstanceValidationResult = ValidationResult<BuilderInstanceValidated>;
19
- export declare function validateInstance(model: BuilderModelValidated, instance: BuilderInstance): BuilderInstanceValidationResult;
6
+ export declare function validateInstance(model: BuilderModelValidated, instance: BuilderInstance, errors?: BuilderValidateErrors): BuilderInstanceValidationResult;
@@ -1,47 +1,48 @@
1
1
  import { check } from '../check.js';
2
2
  import { optionValueSchema } from '../entities/index.js';
3
- import { builderError } from '../exception.js';
4
3
  import { BuilderInstancesSchema } from '../instance.js';
5
4
  import { resolveCollection, resolveOption } from '../mappers/index.js';
6
5
  import { validate } from './brand.js';
7
- export function builderErrorInvalidOption(name, value, location = []) {
8
- return { ...builderError('invalid-option', location), name, value };
9
- }
10
- export function builderErrorInvalidCollection(name, location = []) {
11
- return { ...builderError('invalid-collection', location), name };
12
- }
13
- export function validateInstance(model, instance) {
14
- const errors = checkInstance(model, instance, ['instance']);
15
- return [validate(instance), errors];
16
- }
17
- function checkInstance(model, instance, location) {
18
- const { options, collections } = model;
19
- const optionErrors = options.flatMap((option) => {
20
- const { name } = option;
21
- const payload = resolveOption(option, model, instance);
22
- if (!payload) {
23
- return [];
24
- }
25
- const value = instance[name];
26
- if (!check.is(optionValueSchema(payload), value)) {
27
- return [builderErrorInvalidOption(name, value, [...location, name])];
28
- }
29
- return [];
30
- });
31
- const collectionErrors = collections.flatMap((collection) => {
32
- const { name } = collection;
33
- const payload = resolveCollection(collection, model, instance);
34
- if (!payload) {
35
- return [];
36
- }
37
- const existing = instance[name];
38
- if (!check.is(BuilderInstancesSchema, existing)) {
39
- return [builderErrorInvalidCollection(name, [...location, name])];
40
- }
41
- return existing.flatMap((itemInstance, index) => checkInstance(payload.model, itemInstance, [...location, name, index]).map((error) => ({
42
- ...error,
43
- name: `${name}[${index}].${error.name}`
44
- })));
6
+ import { BuilderValidateErrors } from './errors.js';
7
+ export function validateInstance(model, instance, errors = new BuilderValidateErrors()) {
8
+ errors.scope('instance', () => {
9
+ checkInstance(model, instance);
45
10
  });
46
- return [...optionErrors, ...collectionErrors];
11
+ return [validate(instance), errors.errors];
12
+ function checkInstance(scopeModel, scopeInstance, namePrefix = '') {
13
+ scopeModel.options.forEach((option) => {
14
+ const { name } = option;
15
+ const payload = resolveOption(option, scopeModel, scopeInstance);
16
+ if (!payload) {
17
+ return;
18
+ }
19
+ const value = scopeInstance[name];
20
+ if (!check.is(optionValueSchema(payload), value)) {
21
+ errors.scope(name, () => {
22
+ errors.invalidOption(`${namePrefix}${name}`, value);
23
+ });
24
+ }
25
+ });
26
+ scopeModel.collections.forEach((collection) => {
27
+ const { name } = collection;
28
+ const payload = resolveCollection(collection, scopeModel, scopeInstance);
29
+ if (!payload) {
30
+ return;
31
+ }
32
+ const existing = scopeInstance[name];
33
+ if (!check.is(BuilderInstancesSchema, existing)) {
34
+ errors.scope(name, () => {
35
+ errors.invalidCollection(`${namePrefix}${name}`);
36
+ });
37
+ return;
38
+ }
39
+ errors.scope(name, () => {
40
+ existing.forEach((itemInstance, index) => {
41
+ errors.scope(index, () => {
42
+ checkInstance(payload.model, itemInstance, `${namePrefix}${name}[${index}].`);
43
+ });
44
+ });
45
+ });
46
+ });
47
+ }
47
48
  }
@@ -1,36 +1,9 @@
1
1
  import type { BuilderModelSerialised, BuilderModelValidated, BuilderRefEntities } from '../entities/index';
2
- import type { BuilderErrorLocation, BuilderErrors } from '../exception';
3
2
  import type { ParamableSerialised } from '../references';
4
3
  import type { BuilderResolve } from './resolve';
5
4
  import type { ValidationResult } from './result';
5
+ import { BuilderValidateErrors } from './errors.js';
6
6
  export type BuilderModelValidationResult = ValidationResult<BuilderModelValidated>;
7
- export declare function builderErrorDuplicateName(name: string, location?: BuilderErrorLocation): {
8
- name: string;
9
- kind: "duplicate-name";
10
- location: BuilderErrorLocation;
11
- };
12
- export type BuilderErrorDuplicateName = ReturnType<typeof builderErrorDuplicateName>;
13
- export declare function builderErrorInvalidCollectionBounds(name: string, min: number, max: number, location?: BuilderErrorLocation): {
14
- name: string;
15
- min: number;
16
- max: number;
17
- kind: "invalid-collection-bounds";
18
- location: BuilderErrorLocation;
19
- };
20
- export type BuilderErrorInvalidCollectionBounds = ReturnType<typeof builderErrorInvalidCollectionBounds>;
21
- export type BuilderErrorInvalidPathReason = 'shape' | 'out-of-bounds' | 'missing-collection' | 'option-not-found';
22
- export declare function builderErrorInvalidPath(reason: BuilderErrorInvalidPathReason, location?: BuilderErrorLocation): {
23
- reason: BuilderErrorInvalidPathReason;
24
- kind: "invalid-path";
25
- location: BuilderErrorLocation;
26
- };
27
- export type BuilderErrorInvalidPath = ReturnType<typeof builderErrorInvalidPath>;
28
- export declare function builderErrorInvalidSelectMapKey(key: string, location?: BuilderErrorLocation): {
29
- key: string;
30
- kind: "invalid-select-map-key";
31
- location: BuilderErrorLocation;
32
- };
33
- export type BuilderErrorInvalidSelectMapKey = ReturnType<typeof builderErrorInvalidSelectMapKey>;
34
- export declare function validateModel(input: unknown, references?: BuilderRefEntities): BuilderModelValidationResult;
35
- export declare function checkModelExpectations(mergedModel: BuilderModelSerialised, model: BuilderModelSerialised, location: BuilderErrorLocation): BuilderErrors;
36
- export declare function validateModelStructure(input: ParamableSerialised<BuilderModelSerialised>, resolve: BuilderResolve, location: BuilderErrorLocation): BuilderModelValidationResult;
7
+ export declare function validateModel(input: unknown, references?: BuilderRefEntities, errors?: BuilderValidateErrors): BuilderModelValidationResult;
8
+ export declare function checkModelExpectations(mergedModel: BuilderModelSerialised, rootModel: BuilderModelSerialised, errors: BuilderValidateErrors): void;
9
+ export declare function validateModelStructure(input: ParamableSerialised<BuilderModelSerialised>, resolve: BuilderResolve, errors: BuilderValidateErrors): BuilderModelValidated;