@builder-builder/builder 0.0.14 → 0.0.16
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/bb.d.ts +9 -5
- package/dist/bb.js +12 -5
- package/dist/check.d.ts +2 -2
- package/dist/entities/builder/builder.d.ts +19 -5
- package/dist/entities/builder/builder.js +24 -5
- package/dist/entities/builder/index.d.ts +1 -2
- package/dist/entities/builder/index.js +1 -2
- package/dist/entities/collection/collection.d.ts +7 -1
- package/dist/entities/collection/collection.js +9 -2
- package/dist/entities/collection/config.d.ts +6 -1
- package/dist/entities/collection/config.js +9 -2
- package/dist/entities/component/component.d.ts +41 -1
- package/dist/entities/component/component.js +9 -2
- package/dist/entities/component/details.d.ts +11 -2
- package/dist/entities/component/details.js +9 -2
- package/dist/entities/component/field.d.ts +10 -1
- package/dist/entities/component/field.js +13 -3
- package/dist/entities/index.d.ts +5 -1
- package/dist/entities/index.js +2 -0
- package/dist/entities/kind.d.ts +1 -1
- package/dist/entities/model/methods.d.ts +3 -3
- package/dist/entities/model/model.d.ts +5 -1
- package/dist/entities/model/model.js +10 -3
- package/dist/entities/model/models.js +9 -5
- package/dist/entities/option/option.d.ts +41 -1
- package/dist/entities/option/option.js +9 -2
- package/dist/entities/option/select.d.ts +7 -1
- package/dist/entities/option/select.js +17 -6
- package/dist/entities/option/toggle.d.ts +7 -1
- package/dist/entities/option/toggle.js +16 -4
- package/dist/entities/option/values.d.ts +6 -0
- package/dist/entities/pricing/expression.d.ts +70 -0
- package/dist/entities/pricing/expression.js +43 -0
- package/dist/entities/pricing/index.d.ts +6 -0
- package/dist/entities/pricing/index.js +3 -0
- package/dist/entities/pricing/pricing.d.ts +17 -0
- package/dist/entities/pricing/pricing.js +21 -0
- package/dist/entities/pricing/rates.d.ts +3 -0
- package/dist/entities/pricing/rates.js +3 -0
- package/dist/entities/serialise.d.ts +549 -495
- package/dist/entities/serialise.js +65 -41
- package/dist/entities/tags.d.ts +3 -0
- package/dist/entities/tags.js +2 -0
- package/dist/entities/ui/describe.d.ts +10 -1
- package/dist/entities/ui/describe.js +9 -2
- package/dist/entities/ui/input.d.ts +10 -1
- package/dist/entities/ui/input.js +17 -5
- package/dist/entities/ui/page.d.ts +10 -1
- package/dist/entities/ui/page.js +9 -2
- package/dist/entities/ui/pages.d.ts +5 -1
- package/dist/entities/ui/pages.js +9 -2
- package/dist/entities/ui/ui.d.ts +6 -1
- package/dist/entities/ui/ui.js +27 -12
- package/dist/entities/validated.d.ts +3 -1
- package/dist/environment.d.ts +1 -1
- package/dist/exception.d.ts +2 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/dist/instance.d.ts +9 -0
- package/dist/instance.js +3 -1
- package/dist/mappers/index.d.ts +3 -2
- package/dist/mappers/index.js +2 -1
- package/dist/mappers/price.d.ts +3 -0
- package/dist/mappers/price.js +111 -0
- package/dist/validate/builder.js +16 -7
- package/dist/validate/errors.d.ts +19 -1
- package/dist/validate/errors.js +15 -0
- package/dist/validate/index.d.ts +3 -1
- package/dist/validate/index.js +1 -0
- package/dist/validate/model.js +5 -62
- package/dist/validate/paths.d.ts +5 -0
- package/dist/validate/paths.js +68 -0
- package/dist/validate/pricing.d.ts +8 -0
- package/dist/validate/pricing.js +127 -0
- package/dist/validate/ui.js +60 -1
- package/dist/validate/variants.js +4 -0
- package/package.json +1 -10
- package/dist/cli.d.ts +0 -2
- package/dist/cli.js +0 -53
- package/dist/codegen/index.d.ts +0 -7
- package/dist/codegen/index.js +0 -212
- package/dist/codegen/template.d.ts +0 -5
- package/dist/codegen/template.js +0 -17
- package/dist/entities/builder/factory.d.ts +0 -7
- package/dist/entities/builder/factory.js +0 -4
|
@@ -7,8 +7,9 @@ import type { BuilderCollectionConfigSerialised, BuilderCollectionSerialised, Bu
|
|
|
7
7
|
import type { BuilderComponentDetailsSerialised, BuilderComponentSerialised, BuilderComponentsSerialised } from './component/index';
|
|
8
8
|
import type { BuilderModelSerialised } from './model/index';
|
|
9
9
|
import type { BuilderOptionSerialised, BuilderOptionsSerialised, BuilderOptionValuesSerialised } from './option/index';
|
|
10
|
+
import type { BuilderPricingSerialised } from './pricing/index';
|
|
10
11
|
import type { BuilderUIDescribeSerialised, BuilderUIItemsSerialised, BuilderUIPageSerialised, BuilderUISerialised } from './ui/index';
|
|
11
|
-
export type Validated<Input> = Input extends BuilderComponentVariants | BuilderInstance | BuilderModelSerialised | BuilderSerialised | BuilderUISerialised ? Validate<Input> & BuilderValidatedBrand : Validate<Input>;
|
|
12
|
+
export type Validated<Input> = Input extends BuilderComponentVariants | BuilderInstance | BuilderModelSerialised | BuilderPricingSerialised | BuilderSerialised | BuilderUISerialised ? Validate<Input> & BuilderValidatedBrand : Validate<Input>;
|
|
12
13
|
type Validate<Input> = Input extends BuilderParameter<string> | BuilderParameterSerialised | BuilderRef | BuilderRefSerialised ? never : Input extends ReadonlyArray<unknown> ? ValidatedTuple<Input> : Input extends object ? {
|
|
13
14
|
readonly [Key in keyof Input]: Validated<Input[Key]>;
|
|
14
15
|
} : Input;
|
|
@@ -31,6 +32,7 @@ export type BuilderComponentDetailsValidated = Prettify<Validated<BuilderCompone
|
|
|
31
32
|
export type BuilderCollectionValidated = Prettify<Validated<BuilderCollectionSerialised>>;
|
|
32
33
|
export type BuilderCollectionsValidated = Prettify<Validated<BuilderCollectionsSerialised>>;
|
|
33
34
|
export type BuilderCollectionConfigValidated = Prettify<Validated<BuilderCollectionConfigSerialised>>;
|
|
35
|
+
export type BuilderPricingValidated = Prettify<Validated<BuilderPricingSerialised>>;
|
|
34
36
|
export type BuilderUIItemsValidated = Prettify<Validated<BuilderUIItemsSerialised>>;
|
|
35
37
|
export type BuilderUIPageValidated = Prettify<Validated<BuilderUIPageSerialised>>;
|
|
36
38
|
export type BuilderUIDescribeValidated = Prettify<Validated<BuilderUIDescribeSerialised>>;
|
package/dist/environment.d.ts
CHANGED
|
@@ -2,4 +2,4 @@ import type { BuilderErrors } from './exception';
|
|
|
2
2
|
import * as v from 'valibot';
|
|
3
3
|
export declare const BuilderEnvironmentSchema: v.PicklistSchema<["development", "staging", "production"], undefined>;
|
|
4
4
|
export type BuilderEnvironment = v.InferOutput<typeof BuilderEnvironmentSchema>;
|
|
5
|
-
export type BuilderEnvironmentResult<EntityType, Env extends BuilderEnvironment = 'production'> = Env extends '
|
|
5
|
+
export type BuilderEnvironmentResult<EntityType, Env extends BuilderEnvironment = 'production'> = Env extends 'development' ? readonly [EntityType, BuilderErrors] : EntityType;
|
package/dist/exception.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type { BuilderErrorDuplicateName, BuilderErrorInvalidCollection, BuilderErrorInvalidCollectionBounds, BuilderErrorInvalidDetail, BuilderErrorInvalidInput, BuilderErrorInvalidOption, BuilderErrorInvalidPath, BuilderErrorInvalidSelectMapKey, BuilderErrorInvalidVariant, BuilderErrorMissingComponent, BuilderErrorMissingDetail, BuilderErrorMissingReference, BuilderErrorMissingVariant, BuilderErrorUnboundParameter, BuilderErrorUnexpectedComponent, BuilderErrorUnexpectedDetail, BuilderErrorUnmetExpectation, BuilderErrorUnvalidated } from './validate/index';
|
|
1
|
+
import type { BuilderErrorDuplicateName, BuilderErrorInvalidCollection, BuilderErrorInvalidCollectionBounds, BuilderErrorInvalidDetail, BuilderErrorInvalidInput, BuilderErrorInvalidOption, BuilderErrorInvalidPath, BuilderErrorInvalidPricing, BuilderErrorInvalidSelectMapKey, BuilderErrorInvalidVariant, BuilderErrorMissingComponent, BuilderErrorMissingDetail, BuilderErrorMissingReference, BuilderErrorMissingVariant, BuilderErrorUnboundParameter, BuilderErrorUnexpectedComponent, BuilderErrorUnexpectedDetail, BuilderErrorUnmetExpectation, BuilderErrorUnvalidated } from './validate/index';
|
|
2
2
|
export type BuilderErrorLocation = ReadonlyArray<string | number>;
|
|
3
3
|
export declare function builderError<Kind extends string>(kind: Kind, location: BuilderErrorLocation): {
|
|
4
4
|
kind: Kind;
|
|
5
5
|
location: BuilderErrorLocation;
|
|
6
6
|
};
|
|
7
7
|
export type BuilderErrorBase = ReturnType<typeof builderError>;
|
|
8
|
-
export type BuilderError = BuilderErrorUnmetExpectation | BuilderErrorUnboundParameter | BuilderErrorMissingReference | BuilderErrorInvalidPath | BuilderErrorInvalidSelectMapKey | BuilderErrorDuplicateName | BuilderErrorInvalidCollectionBounds | BuilderErrorInvalidOption | BuilderErrorInvalidCollection | BuilderErrorMissingComponent | BuilderErrorUnexpectedComponent | BuilderErrorMissingVariant | BuilderErrorInvalidVariant | BuilderErrorMissingDetail | BuilderErrorUnexpectedDetail | BuilderErrorInvalidDetail | BuilderErrorInvalidInput | BuilderErrorUnvalidated;
|
|
8
|
+
export type BuilderError = BuilderErrorUnmetExpectation | BuilderErrorUnboundParameter | BuilderErrorMissingReference | BuilderErrorInvalidPath | BuilderErrorInvalidPricing | BuilderErrorInvalidSelectMapKey | BuilderErrorDuplicateName | BuilderErrorInvalidCollectionBounds | BuilderErrorInvalidOption | BuilderErrorInvalidCollection | BuilderErrorMissingComponent | BuilderErrorUnexpectedComponent | BuilderErrorMissingVariant | BuilderErrorInvalidVariant | BuilderErrorMissingDetail | BuilderErrorUnexpectedDetail | BuilderErrorInvalidDetail | BuilderErrorInvalidInput | BuilderErrorUnvalidated;
|
|
9
9
|
export type BuilderErrors = ReadonlyArray<BuilderError>;
|
|
10
10
|
export declare class BuilderException extends globalThis.Error {
|
|
11
11
|
readonly errors: BuilderErrors;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
export type { BB, BBOptions } from './bb';
|
|
2
|
-
export type { BuilderBindings, BuilderBindingsSerialised, BuilderCollection, BuilderCollectionConfig, BuilderCollectionConfigSerialised, BuilderCollections, BuilderCollectionSerialised, BuilderCollectionsSerialised, BuilderCollectionWhen, BuilderCollectionWhenSerialised, BuilderComponent, BuilderComponentDetails, BuilderComponentDetailsSerialised, BuilderComponentField, BuilderComponentFields, BuilderComponentFieldSerialised, BuilderComponentFieldsSerialised, BuilderComponentFieldValueType, BuilderComponents, BuilderComponentSerialised, BuilderComponentsSerialised, BuilderComponentWhen, BuilderComponentWhenSerialised, BuilderDescription, BuilderDescriptionItem, BuilderEntityKind, BuilderEntitySerialised, BuilderExpectation, BuilderExpectationKind, BuilderExpectations, BuilderExpectationSerialised, BuilderExpectationsSerialised, BuilderInstanceOf, BuilderModel, BuilderModels, BuilderModelSerialised, BuilderModelValidated, BuilderOption, BuilderOptions, BuilderOptionSerialised, BuilderOptionsSerialised, BuilderOptionValues, BuilderOptionValuesSerialised, BuilderOptionWhen, BuilderOptionWhenSerialised, BuilderRefEntities, BuilderRefEntity, BuilderSelectType, BuilderSelectTypeLabels, BuilderSelectTypeSerialised, BuilderSelectTypeValues, BuilderSerialised, BuilderToggleType, BuilderToggleTypeSerialised, BuilderToggleValueType, BuilderUI, BuilderUIDescribe, BuilderUIDescribeSerialised, BuilderUIInput, BuilderUIInputMetadata, BuilderUIInputMetadataSerialised, BuilderUIInputs,
|
|
2
|
+
export type { Builder, BuilderBindings, BuilderBindingsSerialised, BuilderCollection, BuilderCollectionConfig, BuilderCollectionConfigSerialised, BuilderCollections, BuilderCollectionSerialised, BuilderCollectionsSerialised, BuilderCollectionWhen, BuilderCollectionWhenSerialised, BuilderComponent, BuilderComponentDetails, BuilderComponentDetailsSerialised, BuilderComponentField, BuilderComponentFields, BuilderComponentFieldSerialised, BuilderComponentFieldsSerialised, BuilderComponentFieldValueType, BuilderComponents, BuilderComponentSerialised, BuilderComponentsSerialised, BuilderComponentVariantsValidated, BuilderComponentWhen, BuilderComponentWhenSerialised, BuilderDescription, BuilderDescriptionItem, BuilderEnableConfig, BuilderEntityKind, BuilderEntitySerialised, BuilderExpectation, BuilderExpectationKind, BuilderExpectations, BuilderExpectationSerialised, BuilderExpectationsSerialised, BuilderInstanceOf, BuilderInstanceValidated, BuilderMatchConfig, BuilderMatchSelectMap, BuilderModel, BuilderModels, BuilderModelSerialised, BuilderModelValidated, BuilderOption, BuilderOptions, BuilderOptionSerialised, BuilderOptionsSerialised, BuilderOptionValues, BuilderOptionValuesSerialised, BuilderOptionWhen, BuilderOptionWhenSerialised, BuilderPricing, BuilderPricingExpression, BuilderPricingLookupKey, BuilderPricingReduce, BuilderPricingSerialised, BuilderRefEntities, BuilderRefEntity, BuilderSelectType, BuilderSelectTypeLabels, BuilderSelectTypeSerialised, BuilderSelectTypeValues, BuilderSerialised, BuilderTags, BuilderToggleType, BuilderToggleTypeSerialised, BuilderToggleValueType, BuilderUI, BuilderUIDescribe, BuilderUIDescribeSerialised, BuilderUIInput, BuilderUIInputMetadata, BuilderUIInputMetadataSerialised, BuilderUIInputs, BuilderUIInputSerialised, BuilderUIInputsSerialised, BuilderUIItem, BuilderUIItems, BuilderUIItemsSerialised, BuilderUIPage, BuilderUIPages, BuilderUIPageSerialised, BuilderUIPagesSerialised, BuilderUIs, BuilderUISerialised, BuilderUIsSerialised, BuilderUIValidated, BuilderUnlessConfig, BuilderValidated, BuilderWhen, BuilderWhenConfig, BuilderWhenSerialised } from './entities/index';
|
|
3
3
|
export type { BuilderEnvironment } from './environment';
|
|
4
4
|
export type { BuilderError, BuilderErrorBase, BuilderErrorLocation, BuilderErrors } from './exception';
|
|
5
|
-
export type { BuilderComponentVariantsValidationResult, BuilderErrorDuplicateName, BuilderErrorInvalidCollection, BuilderErrorInvalidCollectionBounds, BuilderErrorInvalidDetail, BuilderErrorInvalidInput, BuilderErrorInvalidOption, BuilderErrorInvalidPath, BuilderErrorInvalidPathReason, BuilderErrorInvalidSelectMapKey, BuilderErrorInvalidVariant, BuilderErrorMissingComponent, BuilderErrorMissingDetail, BuilderErrorMissingReference, BuilderErrorMissingVariant, BuilderErrorUnboundParameter, BuilderErrorUnexpectedComponent, BuilderErrorUnexpectedDetail, BuilderErrorUnmetExpectation, BuilderErrorUnvalidated, BuilderInstanceValidationResult, BuilderModelValidationResult, BuilderOrder, BuilderRenderMetadata, BuilderRenderOption, BuilderRenderOptions, BuilderRenderPage, BuilderRenderPages, BuilderRenderResult, BuilderRenderUpdate, BuilderUIValidationResult, BuilderValidationResult, BuilderVariantsValidationOptions } from './mappers/index';
|
|
6
5
|
export type { BuilderComponentVariants, BuilderInstance, BuilderInstanceInput, BuilderInstances, BuilderVariant, BuilderVariants } from './instance';
|
|
6
|
+
export type { BuilderComponentVariantsValidationResult, BuilderErrorDuplicateName, BuilderErrorInvalidCollection, BuilderErrorInvalidCollectionBounds, BuilderErrorInvalidDetail, BuilderErrorInvalidInput, BuilderErrorInvalidOption, BuilderErrorInvalidPath, BuilderErrorInvalidPathReason, BuilderErrorInvalidPricing, BuilderErrorInvalidSelectMapKey, BuilderErrorInvalidPricingReason, BuilderErrorInvalidVariant, BuilderErrorMissingComponent, BuilderErrorMissingDetail, BuilderErrorMissingRate, BuilderErrorMissingReference, BuilderErrorMissingVariant, BuilderErrorUnboundParameter, BuilderErrorUnexpectedComponent, BuilderErrorUnexpectedDetail, BuilderErrorUnmetExpectation, BuilderErrorUnvalidated, BuilderInstanceValidationResult, BuilderModelValidationResult, BuilderOrder, BuilderRenderMetadata, BuilderRenderOption, BuilderRenderOptions, BuilderRenderPage, BuilderRenderPages, BuilderRenderResult, BuilderRenderUpdate, BuilderUIValidationResult, BuilderValidationResult, BuilderVariantsValidationOptions } from './mappers/index';
|
|
7
7
|
export type { BuilderPath, BuilderPaths } from './paths';
|
|
8
8
|
export type { BuilderPrimitive, BuilderPrimitives } from './primitive';
|
|
9
9
|
export type { BuilderParameter, BuilderParameterSerialised, BuilderRef, Paramable, ParamableSerialised } from './references';
|
|
10
10
|
export { bb } from './bb.js';
|
|
11
|
-
export {
|
|
11
|
+
export { builder, detailBoolean, detailNumber, detailString, input, model, parameter, pricing, ref, select, serialise, toggleBoolean, toggleNumber, toggleString } from './entities/index.js';
|
|
12
12
|
export { BuilderException } from './exception.js';
|
|
13
13
|
export { ordinal } from './mappers/index.js';
|
|
14
14
|
import { collectionConfig, collectionExpectation, componentDetails, componentExpectation, optionExpectation, uis } from './entities/index.js';
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { bb } from './bb.js';
|
|
2
|
-
export {
|
|
2
|
+
export { builder, detailBoolean, detailNumber, detailString, input, model, parameter, pricing, ref, select, serialise, toggleBoolean, toggleNumber, toggleString } from './entities/index.js';
|
|
3
3
|
export { BuilderException } from './exception.js';
|
|
4
4
|
export { ordinal } from './mappers/index.js';
|
|
5
5
|
import { collectionConfig, collectionExpectation, collectionWhen, componentDetails, componentExpectation, componentWhen, optionExpectation, optionWhen, uis } from './entities/index.js';
|
package/dist/instance.d.ts
CHANGED
|
@@ -10,47 +10,56 @@ export type BuilderInstanceInput = Readonly<Record<string, unknown>>;
|
|
|
10
10
|
export declare const BuilderVariantSchema: v.SchemaWithPipe<readonly [v.ObjectSchema<{
|
|
11
11
|
readonly instance: v.GenericSchema<BuilderInstance>;
|
|
12
12
|
readonly details: v.OptionalSchema<v.RecordSchema<v.StringSchema<undefined>, v.NullableSchema<v.UnionSchema<[v.StringSchema<undefined>, v.BooleanSchema<undefined>, v.NumberSchema<undefined>], undefined>, undefined>, undefined>, undefined>;
|
|
13
|
+
readonly tags: v.OptionalSchema<v.SchemaWithPipe<readonly [v.ArraySchema<v.StringSchema<undefined>, undefined>, v.ReadonlyAction<string[]>]>, undefined>;
|
|
13
14
|
}, undefined>, v.ReadonlyAction<{
|
|
14
15
|
instance: BuilderInstance;
|
|
15
16
|
details?: {
|
|
16
17
|
[x: string]: string | number | boolean | null;
|
|
17
18
|
} | undefined;
|
|
19
|
+
tags?: readonly string[] | undefined;
|
|
18
20
|
}>]>;
|
|
19
21
|
export type BuilderVariant = v.InferOutput<typeof BuilderVariantSchema>;
|
|
20
22
|
export declare const BuilderVariantsSchema: v.SchemaWithPipe<readonly [v.ArraySchema<v.SchemaWithPipe<readonly [v.ObjectSchema<{
|
|
21
23
|
readonly instance: v.GenericSchema<BuilderInstance>;
|
|
22
24
|
readonly details: v.OptionalSchema<v.RecordSchema<v.StringSchema<undefined>, v.NullableSchema<v.UnionSchema<[v.StringSchema<undefined>, v.BooleanSchema<undefined>, v.NumberSchema<undefined>], undefined>, undefined>, undefined>, undefined>;
|
|
25
|
+
readonly tags: v.OptionalSchema<v.SchemaWithPipe<readonly [v.ArraySchema<v.StringSchema<undefined>, undefined>, v.ReadonlyAction<string[]>]>, undefined>;
|
|
23
26
|
}, undefined>, v.ReadonlyAction<{
|
|
24
27
|
instance: BuilderInstance;
|
|
25
28
|
details?: {
|
|
26
29
|
[x: string]: string | number | boolean | null;
|
|
27
30
|
} | undefined;
|
|
31
|
+
tags?: readonly string[] | undefined;
|
|
28
32
|
}>]>, undefined>, v.ReadonlyAction<Readonly<{
|
|
29
33
|
instance: BuilderInstance;
|
|
30
34
|
details?: {
|
|
31
35
|
[x: string]: string | number | boolean | null;
|
|
32
36
|
} | undefined;
|
|
37
|
+
tags?: readonly string[] | undefined;
|
|
33
38
|
}>[]>]>;
|
|
34
39
|
export type BuilderVariants = v.InferOutput<typeof BuilderVariantsSchema>;
|
|
35
40
|
export declare const BuilderComponentVariantsSchema: v.SchemaWithPipe<readonly [v.RecordSchema<v.StringSchema<undefined>, v.SchemaWithPipe<readonly [v.ArraySchema<v.SchemaWithPipe<readonly [v.ObjectSchema<{
|
|
36
41
|
readonly instance: v.GenericSchema<BuilderInstance>;
|
|
37
42
|
readonly details: v.OptionalSchema<v.RecordSchema<v.StringSchema<undefined>, v.NullableSchema<v.UnionSchema<[v.StringSchema<undefined>, v.BooleanSchema<undefined>, v.NumberSchema<undefined>], undefined>, undefined>, undefined>, undefined>;
|
|
43
|
+
readonly tags: v.OptionalSchema<v.SchemaWithPipe<readonly [v.ArraySchema<v.StringSchema<undefined>, undefined>, v.ReadonlyAction<string[]>]>, undefined>;
|
|
38
44
|
}, undefined>, v.ReadonlyAction<{
|
|
39
45
|
instance: BuilderInstance;
|
|
40
46
|
details?: {
|
|
41
47
|
[x: string]: string | number | boolean | null;
|
|
42
48
|
} | undefined;
|
|
49
|
+
tags?: readonly string[] | undefined;
|
|
43
50
|
}>]>, undefined>, v.ReadonlyAction<Readonly<{
|
|
44
51
|
instance: BuilderInstance;
|
|
45
52
|
details?: {
|
|
46
53
|
[x: string]: string | number | boolean | null;
|
|
47
54
|
} | undefined;
|
|
55
|
+
tags?: readonly string[] | undefined;
|
|
48
56
|
}>[]>]>, undefined>, v.ReadonlyAction<{
|
|
49
57
|
readonly [x: string]: readonly Readonly<{
|
|
50
58
|
instance: BuilderInstance;
|
|
51
59
|
details?: {
|
|
52
60
|
[x: string]: string | number | boolean | null;
|
|
53
61
|
} | undefined;
|
|
62
|
+
tags?: readonly string[] | undefined;
|
|
54
63
|
}>[];
|
|
55
64
|
}>]>;
|
|
56
65
|
export type BuilderComponentVariants = v.InferOutput<typeof BuilderComponentVariantsSchema>;
|
package/dist/instance.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import * as v from 'valibot';
|
|
2
2
|
import { BuilderPrimitiveSchema } from './primitive.js';
|
|
3
|
+
import { BuilderTagsSchema } from './entities/tags.js';
|
|
3
4
|
export const BuilderInstanceSchema = v.pipe(v.record(v.string(), v.union([BuilderPrimitiveSchema, v.lazy(() => BuilderInstancesSchema)])), v.readonly());
|
|
4
5
|
export const BuilderInstancesSchema = v.pipe(v.array(BuilderInstanceSchema), v.readonly());
|
|
5
6
|
export const BuilderVariantSchema = v.pipe(v.object({
|
|
6
7
|
instance: BuilderInstanceSchema,
|
|
7
|
-
details: v.optional(v.record(v.string(), BuilderPrimitiveSchema))
|
|
8
|
+
details: v.optional(v.record(v.string(), BuilderPrimitiveSchema)),
|
|
9
|
+
tags: v.optional(BuilderTagsSchema)
|
|
8
10
|
}), v.readonly());
|
|
9
11
|
export const BuilderVariantsSchema = v.pipe(v.array(BuilderVariantSchema), v.readonly());
|
|
10
12
|
export const BuilderComponentVariantsSchema = v.pipe(v.record(v.string(), BuilderVariantsSchema), v.readonly());
|
package/dist/mappers/index.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
export type { BuilderComponentVariantsValidationResult, BuilderErrorDuplicateName, BuilderErrorInvalidCollection, BuilderErrorInvalidCollectionBounds, BuilderErrorInvalidDetail, BuilderErrorInvalidInput, BuilderErrorInvalidOption, BuilderErrorInvalidPath, BuilderErrorInvalidPathReason, BuilderErrorInvalidSelectMapKey, BuilderErrorInvalidVariant, BuilderErrorMissingComponent, BuilderErrorMissingDetail, BuilderErrorMissingReference, BuilderErrorMissingVariant, BuilderErrorUnboundParameter, BuilderErrorUnexpectedComponent, BuilderErrorUnexpectedDetail, BuilderErrorUnmetExpectation, BuilderErrorUnvalidated, BuilderInstanceValidationResult, BuilderModelValidationResult, BuilderUIValidationResult, BuilderValidationResult, BuilderVariantsValidationOptions } from '../validate/index';
|
|
1
|
+
export type { BuilderComponentVariantsValidationResult, BuilderErrorDuplicateName, BuilderErrorInvalidCollection, BuilderErrorInvalidCollectionBounds, BuilderErrorInvalidDetail, BuilderErrorInvalidInput, BuilderErrorInvalidOption, BuilderErrorInvalidPath, BuilderErrorInvalidPathReason, BuilderErrorInvalidPricing, BuilderErrorInvalidSelectMapKey, BuilderErrorInvalidPricingReason, BuilderErrorInvalidVariant, BuilderErrorMissingComponent, BuilderErrorMissingDetail, BuilderErrorMissingRate, BuilderErrorMissingReference, BuilderErrorMissingVariant, BuilderErrorUnboundParameter, BuilderErrorUnexpectedComponent, BuilderErrorUnexpectedDetail, BuilderErrorUnmetExpectation, BuilderErrorUnvalidated, BuilderInstanceValidationResult, BuilderModelValidationResult, BuilderPricingValidationResult, BuilderUIValidationResult, BuilderValidationResult, BuilderVariantsValidationOptions } from '../validate/index';
|
|
2
2
|
export type { BuilderOrder } from './order';
|
|
3
3
|
export type { BuilderRenderMetadata, BuilderRenderOption, BuilderRenderOptions, BuilderRenderPage, BuilderRenderPages, BuilderRenderResult, BuilderRenderUpdate } from './render/index';
|
|
4
|
-
export { assertValidated, validateBuilder, validateInstance, validateModel, validateUI, validateVariants } from '../validate/index.js';
|
|
4
|
+
export { assertValidated, validateBuilder, validateInstance, validateModel, validatePricing, validateUI, validateVariants } from '../validate/index.js';
|
|
5
5
|
export type { BuilderOptionGraph } from './variants/index.js';
|
|
6
6
|
export { createInstance } from './instance.js';
|
|
7
7
|
export { createVariants, optionGraph, variantsFor } from './variants/index.js';
|
|
8
8
|
export { order } from './order.js';
|
|
9
|
+
export { price } from './price.js';
|
|
9
10
|
export { ordinal, render } from './render/index.js';
|
|
10
11
|
export { resolveCollection, resolveComponent, resolveOption } from './resolve.js';
|
package/dist/mappers/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
export { assertValidated, validateBuilder, validateInstance, validateModel, validateUI, validateVariants } from '../validate/index.js';
|
|
1
|
+
export { assertValidated, validateBuilder, validateInstance, validateModel, validatePricing, validateUI, validateVariants } from '../validate/index.js';
|
|
2
2
|
export { createInstance } from './instance.js';
|
|
3
3
|
export { createVariants, optionGraph, variantsFor } from './variants/index.js';
|
|
4
4
|
export { order } from './order.js';
|
|
5
|
+
export { price } from './price.js';
|
|
5
6
|
export { ordinal, render } from './render/index.js';
|
|
6
7
|
export { resolveCollection, resolveComponent, resolveOption } from './resolve.js';
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import * as v from 'valibot';
|
|
2
|
+
import { check } from '../check.js';
|
|
3
|
+
import { BuilderPricingExpressionSchema } from '../entities/index.js';
|
|
4
|
+
import { BuilderVariantSchema } from '../instance.js';
|
|
5
|
+
const NumberSchema = v.number();
|
|
6
|
+
export function price(pricingInput, order) {
|
|
7
|
+
const { rates, formula } = pricingInput;
|
|
8
|
+
if (formula == null) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
const variants = collectVariants(order);
|
|
12
|
+
return evaluate(formula);
|
|
13
|
+
function evaluate(expression, currentVariant = null) {
|
|
14
|
+
check.assert(BuilderPricingExpressionSchema, expression);
|
|
15
|
+
if (check.is(NumberSchema, expression)) {
|
|
16
|
+
return expression;
|
|
17
|
+
}
|
|
18
|
+
switch (expression.kind) {
|
|
19
|
+
case 'variantPrice':
|
|
20
|
+
return variantPrice(currentVariant);
|
|
21
|
+
case 'lookup':
|
|
22
|
+
return evaluateLookup(expression, currentVariant);
|
|
23
|
+
case 'variants':
|
|
24
|
+
return evaluateVariants(expression);
|
|
25
|
+
case 'add':
|
|
26
|
+
return combine(expression.left, expression.right, currentVariant, (l, r) => l + r);
|
|
27
|
+
case 'sub':
|
|
28
|
+
return combine(expression.left, expression.right, currentVariant, (l, r) => l - r);
|
|
29
|
+
case 'mul':
|
|
30
|
+
return combine(expression.left, expression.right, currentVariant, (l, r) => l * r);
|
|
31
|
+
case 'div':
|
|
32
|
+
return combine(expression.left, expression.right, currentVariant, (l, r) => l / r);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function combine(left, right, currentVariant, operation) {
|
|
36
|
+
const leftValue = evaluate(left, currentVariant);
|
|
37
|
+
const rightValue = evaluate(right, currentVariant);
|
|
38
|
+
if (leftValue == null || rightValue == null) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
return operation(leftValue, rightValue);
|
|
42
|
+
}
|
|
43
|
+
function lookupRate(rate, key) {
|
|
44
|
+
let value = null;
|
|
45
|
+
rates.forEach((entry) => {
|
|
46
|
+
const candidate = entry[rate]?.[key];
|
|
47
|
+
if (check.is(NumberSchema, candidate)) {
|
|
48
|
+
value = candidate;
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
function variantPrice(variant) {
|
|
54
|
+
const candidate = variant?.details?.price;
|
|
55
|
+
return check.is(NumberSchema, candidate) ? candidate : null;
|
|
56
|
+
}
|
|
57
|
+
function evaluateLookup(expression, currentVariant) {
|
|
58
|
+
const keys = resolveKey(expression.key, currentVariant);
|
|
59
|
+
const matches = keys
|
|
60
|
+
.map((key) => lookupRate(expression.rate, key))
|
|
61
|
+
.filter((value) => value != null);
|
|
62
|
+
if (matches.length === 0) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
return reduceValues(matches, expression.reduce ?? 'product');
|
|
66
|
+
}
|
|
67
|
+
function evaluateVariants(expression) {
|
|
68
|
+
const { tag } = expression;
|
|
69
|
+
const candidates = tag == null ? variants : variants.filter((variant) => (variant.tags ?? []).includes(tag));
|
|
70
|
+
const results = candidates.map((variant) => evaluate(expression.expression, variant));
|
|
71
|
+
if (results.some((value) => value == null)) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
return reduceValues(results, expression.reduce ?? 'sum');
|
|
75
|
+
}
|
|
76
|
+
function resolveKey(key, currentVariant) {
|
|
77
|
+
switch (key.kind) {
|
|
78
|
+
case 'variantTags':
|
|
79
|
+
return currentVariant?.tags ?? [];
|
|
80
|
+
case 'option': {
|
|
81
|
+
const value = currentVariant?.instance?.[key.name];
|
|
82
|
+
return value == null ? [] : [String(value)];
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function reduceValues(values, mode) {
|
|
88
|
+
if (mode === 'product') {
|
|
89
|
+
return values.reduce((accumulator, value) => accumulator * value, 1);
|
|
90
|
+
}
|
|
91
|
+
if (mode === 'sum') {
|
|
92
|
+
return values.reduce((accumulator, value) => accumulator + value, 0);
|
|
93
|
+
}
|
|
94
|
+
check.truthy(values.length > 0, 'Pricing: cannot reduce empty set with "first"! ❌');
|
|
95
|
+
const [first] = values;
|
|
96
|
+
return first;
|
|
97
|
+
}
|
|
98
|
+
function collectVariants(order) {
|
|
99
|
+
return Object.values(order).flatMap((value) => {
|
|
100
|
+
if (value == null) {
|
|
101
|
+
return [];
|
|
102
|
+
}
|
|
103
|
+
if (check.is(BuilderVariantSchema, value)) {
|
|
104
|
+
return [value];
|
|
105
|
+
}
|
|
106
|
+
if (Array.isArray(value)) {
|
|
107
|
+
return value.flatMap(collectVariants);
|
|
108
|
+
}
|
|
109
|
+
return collectVariants(value);
|
|
110
|
+
});
|
|
111
|
+
}
|
package/dist/validate/builder.js
CHANGED
|
@@ -3,27 +3,36 @@ import { builder, BuilderSerialisedSchema, modelsMerge, serialise } from '../ent
|
|
|
3
3
|
import { validate } from './brand.js';
|
|
4
4
|
import { BuilderValidateErrors } from './errors.js';
|
|
5
5
|
import { checkModelExpectations, validateModelStructure } from './model.js';
|
|
6
|
+
import { checkPricingExpectations, validatePricingStructure } from './pricing.js';
|
|
6
7
|
import { resolver } from './resolve.js';
|
|
7
8
|
import { checkUIExpectations, validateUIStructure } from './ui.js';
|
|
9
|
+
const EMPTY_BUILDER = validate(serialise.builder(builder()));
|
|
8
10
|
export function validateBuilder(input, references = [], errors = new BuilderValidateErrors()) {
|
|
9
11
|
if (!check.is(BuilderSerialisedSchema, input)) {
|
|
10
12
|
errors.invalidInput('builder');
|
|
11
|
-
return [
|
|
13
|
+
return [EMPTY_BUILDER, errors.errors];
|
|
12
14
|
}
|
|
13
15
|
const resolve = resolver(errors, references, input.bindings);
|
|
14
16
|
const validatedModel = errors.scope('model', () => validateModelStructure(input.model, resolve, errors));
|
|
15
|
-
const validatedUI = errors.scope('ui', () => validateUIStructure(input.ui, resolve, errors));
|
|
16
17
|
const mergedModel = modelsMerge(validatedModel);
|
|
17
18
|
errors.scope('model', () => {
|
|
18
19
|
checkModelExpectations(mergedModel, validatedModel, errors);
|
|
19
20
|
});
|
|
20
|
-
errors.scope('ui', () => {
|
|
21
|
-
|
|
21
|
+
const validatedUI = errors.scope('ui', () => {
|
|
22
|
+
const validated = validateUIStructure(input.ui, resolve, errors);
|
|
23
|
+
checkUIExpectations(mergedModel, validated, errors);
|
|
24
|
+
return validated;
|
|
25
|
+
});
|
|
26
|
+
const validatedPricing = errors.scope('pricing', () => {
|
|
27
|
+
const validated = validatePricingStructure(input.pricing, resolve, errors);
|
|
28
|
+
checkPricingExpectations(mergedModel, validated, errors);
|
|
29
|
+
return validated;
|
|
22
30
|
});
|
|
23
31
|
const data = validate({
|
|
24
|
-
...
|
|
25
|
-
model: mergedModel,
|
|
26
|
-
ui: validatedUI
|
|
32
|
+
...input,
|
|
33
|
+
model: validate(mergedModel),
|
|
34
|
+
ui: validate(validatedUI),
|
|
35
|
+
pricing: validate(validatedPricing)
|
|
27
36
|
});
|
|
28
37
|
return [data, errors.errors];
|
|
29
38
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { BuilderExpectationKind } from '../entities/index';
|
|
2
2
|
import type { BuilderErrorLocation, BuilderErrors } from '../exception';
|
|
3
3
|
import type { BuilderInstance } from '../instance';
|
|
4
|
-
export type BuilderInvalidInputTarget = 'builder' | 'model' | 'ui' | 'variants';
|
|
4
|
+
export type BuilderInvalidInputTarget = 'builder' | 'model' | 'pricing' | 'ui' | 'variants';
|
|
5
5
|
export type BuilderErrorInvalidPathReason = 'shape' | 'out-of-bounds' | 'missing-collection' | 'option-not-found';
|
|
6
|
+
export type BuilderErrorInvalidPricingReason = 'scope' | 'nested-variants';
|
|
6
7
|
export declare class BuilderValidateErrors {
|
|
7
8
|
#private;
|
|
8
9
|
get errors(): BuilderErrors;
|
|
@@ -109,6 +110,20 @@ export declare class BuilderValidateErrors {
|
|
|
109
110
|
kind: "invalid-detail";
|
|
110
111
|
location: BuilderErrorLocation;
|
|
111
112
|
};
|
|
113
|
+
invalidPricing(reason: BuilderErrorInvalidPricingReason): {
|
|
114
|
+
reason: BuilderErrorInvalidPricingReason;
|
|
115
|
+
kind: "invalid-pricing";
|
|
116
|
+
location: BuilderErrorLocation;
|
|
117
|
+
};
|
|
118
|
+
missingRate(rate: string): {
|
|
119
|
+
rate: string;
|
|
120
|
+
kind: "missing-rate";
|
|
121
|
+
location: BuilderErrorLocation;
|
|
122
|
+
};
|
|
123
|
+
noComponents(): {
|
|
124
|
+
kind: "no-components";
|
|
125
|
+
location: BuilderErrorLocation;
|
|
126
|
+
};
|
|
112
127
|
}
|
|
113
128
|
export type BuilderErrorInvalidInput = ReturnType<BuilderValidateErrors['invalidInput']>;
|
|
114
129
|
export type BuilderErrorInvalidOption = ReturnType<BuilderValidateErrors['invalidOption']>;
|
|
@@ -128,3 +143,6 @@ export type BuilderErrorInvalidVariant = ReturnType<BuilderValidateErrors['inval
|
|
|
128
143
|
export type BuilderErrorMissingDetail = ReturnType<BuilderValidateErrors['missingDetail']>;
|
|
129
144
|
export type BuilderErrorUnexpectedDetail = ReturnType<BuilderValidateErrors['unexpectedDetail']>;
|
|
130
145
|
export type BuilderErrorInvalidDetail = ReturnType<BuilderValidateErrors['invalidDetail']>;
|
|
146
|
+
export type BuilderErrorInvalidPricing = ReturnType<BuilderValidateErrors['invalidPricing']>;
|
|
147
|
+
export type BuilderErrorMissingRate = ReturnType<BuilderValidateErrors['missingRate']>;
|
|
148
|
+
export type BuilderErrorNoComponents = ReturnType<BuilderValidateErrors['noComponents']>;
|
package/dist/validate/errors.js
CHANGED
|
@@ -134,6 +134,21 @@ export class BuilderValidateErrors {
|
|
|
134
134
|
instance
|
|
135
135
|
});
|
|
136
136
|
}
|
|
137
|
+
invalidPricing(reason) {
|
|
138
|
+
return this.#addError({
|
|
139
|
+
...builderError('invalid-pricing', this.#location),
|
|
140
|
+
reason
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
missingRate(rate) {
|
|
144
|
+
return this.#addError({
|
|
145
|
+
...builderError('missing-rate', this.#location),
|
|
146
|
+
rate
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
noComponents() {
|
|
150
|
+
return this.#addError(builderError('no-components', this.#location));
|
|
151
|
+
}
|
|
137
152
|
#addError(error) {
|
|
138
153
|
this.#errors = [...this.#errors, error];
|
|
139
154
|
return error;
|
package/dist/validate/index.d.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
export type { BuilderValidationResult } from './builder';
|
|
2
|
-
export type { BuilderErrorDuplicateName, BuilderErrorInvalidCollection, BuilderErrorInvalidCollectionBounds, BuilderErrorInvalidDetail, BuilderErrorInvalidInput, BuilderErrorInvalidOption, BuilderErrorInvalidPath, BuilderErrorInvalidPathReason, BuilderErrorInvalidSelectMapKey, BuilderErrorInvalidVariant, BuilderErrorMissingComponent, BuilderErrorMissingDetail, BuilderErrorMissingReference, BuilderErrorMissingVariant, BuilderErrorUnboundParameter, BuilderErrorUnexpectedComponent, BuilderErrorUnexpectedDetail, BuilderErrorUnmetExpectation, BuilderErrorUnvalidated, BuilderInvalidInputTarget } from './errors';
|
|
2
|
+
export type { BuilderErrorDuplicateName, BuilderErrorInvalidCollection, BuilderErrorInvalidCollectionBounds, BuilderErrorInvalidDetail, BuilderErrorInvalidInput, BuilderErrorInvalidOption, BuilderErrorInvalidPath, BuilderErrorInvalidPathReason, BuilderErrorInvalidPricing, BuilderErrorInvalidSelectMapKey, BuilderErrorInvalidPricingReason, BuilderErrorInvalidVariant, BuilderErrorMissingComponent, BuilderErrorMissingDetail, BuilderErrorMissingRate, BuilderErrorMissingReference, BuilderErrorMissingVariant, BuilderErrorUnboundParameter, BuilderErrorUnexpectedComponent, BuilderErrorUnexpectedDetail, BuilderErrorUnmetExpectation, BuilderErrorUnvalidated, BuilderInvalidInputTarget } from './errors';
|
|
3
3
|
export type { BuilderInstanceValidationResult } from './instance';
|
|
4
4
|
export type { BuilderModelValidationResult } from './model';
|
|
5
|
+
export type { BuilderPricingValidationResult } from './pricing';
|
|
5
6
|
export type { BuilderUIValidationResult } from './ui';
|
|
6
7
|
export type { BuilderComponentVariantsValidationResult, BuilderVariantsValidationOptions } from './variants';
|
|
7
8
|
export { assertValidated } from './brand.js';
|
|
8
9
|
export { validateBuilder } from './builder.js';
|
|
9
10
|
export { validateInstance } from './instance.js';
|
|
10
11
|
export { validateModel } from './model.js';
|
|
12
|
+
export { validatePricing } from './pricing.js';
|
|
11
13
|
export { validateUI } from './ui.js';
|
|
12
14
|
export { validateVariants } from './variants.js';
|
package/dist/validate/index.js
CHANGED
|
@@ -2,5 +2,6 @@ export { assertValidated } from './brand.js';
|
|
|
2
2
|
export { validateBuilder } from './builder.js';
|
|
3
3
|
export { validateInstance } from './instance.js';
|
|
4
4
|
export { validateModel } from './model.js';
|
|
5
|
+
export { validatePricing } from './pricing.js';
|
|
5
6
|
export { validateUI } from './ui.js';
|
|
6
7
|
export { validateVariants } from './variants.js';
|
package/dist/validate/model.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { check } from '../check.js';
|
|
2
|
-
import {
|
|
2
|
+
import { BuilderModelSerialisedSchema, BuilderWhenSerialisedSchema, model, modelsMerge, serialise } from '../entities/index.js';
|
|
3
3
|
import { validate } from './brand.js';
|
|
4
4
|
import { BuilderValidateErrors } from './errors.js';
|
|
5
5
|
import { checkExpectations } from './expectations.js';
|
|
6
|
+
import { checkPath, collectionConfigs } from './paths.js';
|
|
6
7
|
import { resolver } from './resolve.js';
|
|
7
8
|
const EMPTY_MODEL = validate(serialise.model(model()));
|
|
8
9
|
export function validateModel(input, references = [], errors = new BuilderValidateErrors()) {
|
|
@@ -106,23 +107,13 @@ export function validateModelStructure(input, resolve, errors) {
|
|
|
106
107
|
errors.scope('paths', () => {
|
|
107
108
|
paths.forEach((path, pathIndex) => {
|
|
108
109
|
errors.scope(pathIndex, () => {
|
|
109
|
-
checkPath(path);
|
|
110
|
+
checkPath(modelInput, path, errors);
|
|
110
111
|
});
|
|
111
112
|
});
|
|
112
113
|
});
|
|
113
114
|
}
|
|
114
115
|
checkWhenPaths(payload);
|
|
115
116
|
}
|
|
116
|
-
function checkPath(path) {
|
|
117
|
-
const reached = walkPath([modelInput], path.slice(0, -1));
|
|
118
|
-
if (reached == null) {
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
const optionName = path.at(-1);
|
|
122
|
-
if (!reached.some((candidate) => candidate.options.some((option) => option.name === optionName))) {
|
|
123
|
-
errors.invalidPath('option-not-found');
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
117
|
function checkWhenPaths(payload) {
|
|
127
118
|
if (!check.is(BuilderWhenSerialisedSchema, payload)) {
|
|
128
119
|
return;
|
|
@@ -130,7 +121,7 @@ export function validateModelStructure(input, resolve, errors) {
|
|
|
130
121
|
if (payload.type === 'match' && Array.isArray(payload.matchPath)) {
|
|
131
122
|
errors.scope('payload', () => {
|
|
132
123
|
errors.scope('matchPath', () => {
|
|
133
|
-
checkPath(payload.matchPath);
|
|
124
|
+
checkPath(modelInput, payload.matchPath, errors);
|
|
134
125
|
});
|
|
135
126
|
});
|
|
136
127
|
return;
|
|
@@ -138,42 +129,11 @@ export function validateModelStructure(input, resolve, errors) {
|
|
|
138
129
|
if (payload.type === 'unless' && Array.isArray(payload.unlessPath)) {
|
|
139
130
|
errors.scope('payload', () => {
|
|
140
131
|
errors.scope('unlessPath', () => {
|
|
141
|
-
checkPath(payload.unlessPath);
|
|
132
|
+
checkPath(modelInput, payload.unlessPath, errors);
|
|
142
133
|
});
|
|
143
134
|
});
|
|
144
135
|
}
|
|
145
136
|
}
|
|
146
|
-
function walkPath(candidates, remaining) {
|
|
147
|
-
if (remaining.length === 0) {
|
|
148
|
-
return candidates;
|
|
149
|
-
}
|
|
150
|
-
const [collectionName, index, ...rest] = remaining;
|
|
151
|
-
if (typeof collectionName !== 'string' || typeof index !== 'number') {
|
|
152
|
-
errors.invalidPath('shape');
|
|
153
|
-
return null;
|
|
154
|
-
}
|
|
155
|
-
const matchedConfigs = candidates.flatMap((current) => {
|
|
156
|
-
const collection = current.collections.find((entry) => entry.name === collectionName);
|
|
157
|
-
return collection == null ? [] : [collectionConfigs(collection)];
|
|
158
|
-
});
|
|
159
|
-
if (matchedConfigs.length === 0) {
|
|
160
|
-
errors.invalidPath('missing-collection');
|
|
161
|
-
return null;
|
|
162
|
-
}
|
|
163
|
-
const anyOutOfBounds = matchedConfigs.some((configs) => configs.length > 0 && configs.every(({ max }) => typeof max === 'number' && index >= max));
|
|
164
|
-
if (anyOutOfBounds) {
|
|
165
|
-
errors.invalidPath('out-of-bounds');
|
|
166
|
-
return null;
|
|
167
|
-
}
|
|
168
|
-
const next = matchedConfigs.flatMap((configs) => configs
|
|
169
|
-
.filter(({ max }) => typeof max !== 'number' || index < max)
|
|
170
|
-
.flatMap(({ model: configModel }) => check.is(BuilderModelSerialisedSchema, configModel) ? [configModel] : []));
|
|
171
|
-
if (next.length === 0) {
|
|
172
|
-
errors.invalidPath('missing-collection');
|
|
173
|
-
return null;
|
|
174
|
-
}
|
|
175
|
-
return walkPath(next, rest);
|
|
176
|
-
}
|
|
177
137
|
function checkCollectionBounds(collection) {
|
|
178
138
|
collectionConfigs(collection).forEach(({ min, max }) => {
|
|
179
139
|
if (typeof min !== 'number' || typeof max !== 'number') {
|
|
@@ -185,20 +145,3 @@ export function validateModelStructure(input, resolve, errors) {
|
|
|
185
145
|
});
|
|
186
146
|
}
|
|
187
147
|
}
|
|
188
|
-
function collectionConfigs(collection) {
|
|
189
|
-
const { payload } = collection;
|
|
190
|
-
if (check.is(BuilderCollectionConfigSerialisedSchema, payload)) {
|
|
191
|
-
return [payload];
|
|
192
|
-
}
|
|
193
|
-
if (!check.is(BuilderWhenSerialisedSchema, payload)) {
|
|
194
|
-
return [];
|
|
195
|
-
}
|
|
196
|
-
if (payload.type === 'match') {
|
|
197
|
-
return Object.entries(payload.selectMap).flatMap(([, value]) => check.is(BuilderCollectionConfigSerialisedSchema, value)
|
|
198
|
-
? [value]
|
|
199
|
-
: []);
|
|
200
|
-
}
|
|
201
|
-
return check.is(BuilderCollectionConfigSerialisedSchema, payload.payload)
|
|
202
|
-
? [payload.payload]
|
|
203
|
-
: [];
|
|
204
|
-
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { BuilderCollectionConfigSerialised, BuilderCollectionSerialised, BuilderModelSerialised } from '../entities/index';
|
|
2
|
+
import type { BuilderPath } from '../paths';
|
|
3
|
+
import type { BuilderValidateErrors } from './errors';
|
|
4
|
+
export declare function checkPath(model: BuilderModelSerialised, path: BuilderPath, errors: BuilderValidateErrors): void;
|
|
5
|
+
export declare function collectionConfigs(collection: BuilderCollectionSerialised): ReadonlyArray<BuilderCollectionConfigSerialised>;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import * as v from 'valibot';
|
|
2
|
+
import { check } from '../check.js';
|
|
3
|
+
import { BuilderCollectionConfigSerialisedSchema, BuilderCollectionSelectMapSerialisedSchema, BuilderModelSerialisedSchema, BuilderWhenSerialisedSchema } from '../entities/index.js';
|
|
4
|
+
const NumberSchema = v.number();
|
|
5
|
+
const StringSchema = v.string();
|
|
6
|
+
export function checkPath(model, path, errors) {
|
|
7
|
+
const models = walkPath([model], path.slice(0, -1), errors);
|
|
8
|
+
if (models == null) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const optionName = path.at(-1);
|
|
12
|
+
if (!check.is(StringSchema, optionName)) {
|
|
13
|
+
errors.invalidPath('shape');
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (!models.some((model) => model.options.some((option) => option.name === optionName))) {
|
|
17
|
+
errors.invalidPath('option-not-found');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export function collectionConfigs(collection) {
|
|
21
|
+
const { payload } = collection;
|
|
22
|
+
if (check.is(BuilderCollectionConfigSerialisedSchema, payload)) {
|
|
23
|
+
return [payload];
|
|
24
|
+
}
|
|
25
|
+
if (!check.is(BuilderWhenSerialisedSchema, payload)) {
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
if (payload.type === 'match') {
|
|
29
|
+
if (!check.is(BuilderCollectionSelectMapSerialisedSchema, payload.selectMap)) {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
return Object.values(payload.selectMap).flatMap((value) => check.is(BuilderCollectionConfigSerialisedSchema, value) ? [value] : []);
|
|
33
|
+
}
|
|
34
|
+
return check.is(BuilderCollectionConfigSerialisedSchema, payload.payload)
|
|
35
|
+
? [payload.payload]
|
|
36
|
+
: [];
|
|
37
|
+
}
|
|
38
|
+
function walkPath(candidates, remaining, errors) {
|
|
39
|
+
if (remaining.length === 0) {
|
|
40
|
+
return candidates;
|
|
41
|
+
}
|
|
42
|
+
const [collectionName, index, ...rest] = remaining;
|
|
43
|
+
if (!check.is(StringSchema, collectionName) || !check.is(NumberSchema, index)) {
|
|
44
|
+
errors.invalidPath('shape');
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
const matchedConfigs = candidates.flatMap((current) => {
|
|
48
|
+
const collection = current.collections.find((entry) => entry.name === collectionName);
|
|
49
|
+
return collection == null ? [] : [collectionConfigs(collection)];
|
|
50
|
+
});
|
|
51
|
+
if (matchedConfigs.length === 0) {
|
|
52
|
+
errors.invalidPath('missing-collection');
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
const anyOutOfBounds = matchedConfigs.some((configs) => configs.length > 0 && configs.every(({ max }) => check.is(NumberSchema, max) && index >= max));
|
|
56
|
+
if (anyOutOfBounds) {
|
|
57
|
+
errors.invalidPath('out-of-bounds');
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
const next = matchedConfigs.flatMap((configs) => configs
|
|
61
|
+
.filter(({ max }) => !check.is(NumberSchema, max) || index < max)
|
|
62
|
+
.flatMap(({ model: configModel }) => check.is(BuilderModelSerialisedSchema, configModel) ? [configModel] : []));
|
|
63
|
+
if (next.length === 0) {
|
|
64
|
+
errors.invalidPath('missing-collection');
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
return walkPath(next, rest, errors);
|
|
68
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { BuilderModelSerialised, BuilderPricingSerialised, BuilderPricingValidated, BuilderRefEntities } from '../entities/index';
|
|
2
|
+
import type { BuilderResolve } from './resolve';
|
|
3
|
+
import type { ValidationResult } from './result';
|
|
4
|
+
import { BuilderValidateErrors } from './errors.js';
|
|
5
|
+
export type BuilderPricingValidationResult = ValidationResult<BuilderPricingValidated>;
|
|
6
|
+
export declare function validatePricing(input: unknown, references?: BuilderRefEntities, errors?: BuilderValidateErrors): BuilderPricingValidationResult;
|
|
7
|
+
export declare function validatePricingStructure(input: BuilderPricingSerialised, resolve: BuilderResolve, errors: BuilderValidateErrors): BuilderPricingSerialised;
|
|
8
|
+
export declare function checkPricingExpectations(model: BuilderModelSerialised, pricing: BuilderPricingSerialised, errors: BuilderValidateErrors): void;
|