@builder-builder/builder 0.0.23 → 0.0.25
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/client/client.d.ts +3 -1
- package/dist/client/client.js +30 -18
- package/dist/client/index.d.ts +1 -4
- package/dist/client/index.js +1 -2
- package/dist/client/public.d.ts +4 -0
- package/dist/client/public.js +2 -0
- package/dist/client/schema.d.ts +23 -14
- package/dist/client/schema.js +9 -2
- package/dist/entities/collection/collection.d.ts +2 -2
- package/dist/entities/collection/config.d.ts +1 -1
- package/dist/entities/collection/config.js +1 -1
- package/dist/entities/component/component.d.ts +2 -2
- package/dist/entities/component/config.d.ts +1 -1
- package/dist/entities/component/config.js +1 -1
- package/dist/entities/expectation.d.ts +1 -1
- package/dist/entities/kind.d.ts +3 -3
- package/dist/entities/kind.js +3 -3
- package/dist/entities/option/option.d.ts +2 -2
- package/dist/entities/option/select.d.ts +1 -1
- package/dist/entities/option/select.js +7 -5
- package/dist/entities/option/toggle.d.ts +1 -1
- package/dist/entities/option/toggle.js +1 -1
- package/dist/entities/paths.d.ts +2 -2
- package/dist/entities/pricing/rates.d.ts +1 -1
- package/dist/entities/serialise.d.ts +3 -3
- package/dist/entities/ui/describe.d.ts +1 -1
- package/dist/entities/ui/describe.js +2 -2
- package/dist/entities/ui/input.d.ts +1 -1
- package/dist/entities/ui/page.d.ts +1 -1
- package/dist/entities/ui/page.js +2 -2
- package/dist/entities/ui/pages.d.ts +2 -2
- package/dist/entities/ui/pages.js +2 -2
- package/dist/errors/check.d.ts +2 -3
- package/dist/errors/check.js +5 -10
- package/dist/errors/errors.d.ts +231 -158
- package/dist/errors/errors.js +143 -173
- package/dist/errors/exception.d.ts +6 -4
- package/dist/errors/exception.js +11 -66
- package/dist/errors/index.d.ts +2 -4
- package/dist/errors/index.js +2 -2
- package/dist/errors/public.d.ts +2 -0
- package/dist/errors/public.js +1 -0
- package/dist/index.d.ts +4 -36
- package/dist/index.js +4 -19
- package/dist/mappers/price.js +1 -1
- package/dist/mappers/render/render.js +7 -7
- package/dist/mappers/resolve.js +5 -5
- package/dist/mappers/variants/option-graph.js +11 -4
- package/dist/mappers/variants/variants.js +7 -6
- package/dist/public.d.ts +37 -0
- package/dist/public.js +19 -0
- package/dist/validate/brand.js +2 -4
- package/dist/validate/builder.d.ts +2 -2
- package/dist/validate/builder.js +3 -3
- package/dist/validate/expectations.d.ts +2 -2
- package/dist/validate/expectations.js +1 -1
- package/dist/validate/index.d.ts +0 -1
- package/dist/validate/instance.d.ts +2 -2
- package/dist/validate/instance.js +6 -6
- package/dist/validate/model.d.ts +4 -4
- package/dist/validate/model.js +118 -101
- package/dist/validate/paths.d.ts +2 -2
- package/dist/validate/paths.js +45 -21
- package/dist/validate/pricing.d.ts +4 -4
- package/dist/validate/pricing.js +26 -13
- package/dist/validate/resolve.d.ts +2 -2
- package/dist/validate/resolve.js +14 -3
- package/dist/validate/ui.d.ts +4 -4
- package/dist/validate/ui.js +3 -3
- package/dist/validate/variants.d.ts +2 -2
- package/dist/validate/variants.js +16 -16
- package/package.json +11 -7
- package/dist/private.d.ts +0 -3
- package/dist/private.js +0 -3
package/dist/mappers/resolve.js
CHANGED
|
@@ -27,12 +27,12 @@ export function resolveReference(value, references) {
|
|
|
27
27
|
return value;
|
|
28
28
|
}
|
|
29
29
|
const found = references.find((entry) => entry.id === value.id);
|
|
30
|
-
check.
|
|
30
|
+
check.invariant(found);
|
|
31
31
|
return found.serialised;
|
|
32
32
|
}
|
|
33
33
|
export function resolvePath(model, instance, path, references = []) {
|
|
34
34
|
const optionName = path.at(-1);
|
|
35
|
-
check.assert(v.string(), optionName
|
|
35
|
+
check.assert(v.string(), optionName);
|
|
36
36
|
const descended = resolveItems(model, instance, path.slice(0, -1), references);
|
|
37
37
|
if (descended == null) {
|
|
38
38
|
return null;
|
|
@@ -40,7 +40,7 @@ export function resolvePath(model, instance, path, references = []) {
|
|
|
40
40
|
const [scopeModel, scopeInstance] = descended;
|
|
41
41
|
const merged = modelsMerge(scopeModel);
|
|
42
42
|
const option = merged.options.find((entry) => entry.name === optionName);
|
|
43
|
-
check.
|
|
43
|
+
check.invariant(option);
|
|
44
44
|
const payload = resolveOption(option, scopeModel, scopeInstance, references);
|
|
45
45
|
if (payload == null) {
|
|
46
46
|
return null;
|
|
@@ -54,10 +54,10 @@ export function resolveItems(model, instance, pairs, references = []) {
|
|
|
54
54
|
}
|
|
55
55
|
const [name, index, ...rest] = pairs;
|
|
56
56
|
check.assert(v.string(), name);
|
|
57
|
-
check.assert(v.number(), index
|
|
57
|
+
check.assert(v.number(), index);
|
|
58
58
|
const merged = modelsMerge(model);
|
|
59
59
|
const collection = merged.collections.find((entry) => entry.name === name);
|
|
60
|
-
check.
|
|
60
|
+
check.invariant(collection);
|
|
61
61
|
const resolved = resolveCollection(collection, model, instance, references);
|
|
62
62
|
if (resolved == null) {
|
|
63
63
|
return null;
|
|
@@ -2,7 +2,14 @@ import { BuilderPathSchema, BuilderWhenMatchSchema, BuilderWhenUnlessSchema } fr
|
|
|
2
2
|
import { check } from '../../errors/index.js';
|
|
3
3
|
import { resolveOption } from '../resolve.js';
|
|
4
4
|
export function crossProduct(left, right) {
|
|
5
|
-
return left.flatMap((leftModel) => right.
|
|
5
|
+
return left.flatMap((leftModel) => right.flatMap((rightModel) => {
|
|
6
|
+
const rightKeys = new Set(Object.keys(rightModel));
|
|
7
|
+
const conflicted = Object.keys(leftModel).some((key) => rightKeys.has(key) && leftModel[key] !== rightModel[key]);
|
|
8
|
+
if (conflicted) {
|
|
9
|
+
return [];
|
|
10
|
+
}
|
|
11
|
+
return [{ ...leftModel, ...rightModel }];
|
|
12
|
+
}));
|
|
6
13
|
}
|
|
7
14
|
export function dependencyKeys(payload, paths = []) {
|
|
8
15
|
const keys = new Set(paths.map(([first]) => String(first)));
|
|
@@ -25,7 +32,7 @@ export class BuilderOptionGraph {
|
|
|
25
32
|
}
|
|
26
33
|
get(name) {
|
|
27
34
|
const graphPath = this.paths.find((graphPath) => graphPath.name === name);
|
|
28
|
-
check.
|
|
35
|
+
check.invariant(graphPath);
|
|
29
36
|
return graphPath;
|
|
30
37
|
}
|
|
31
38
|
add(option, model) {
|
|
@@ -33,7 +40,7 @@ export class BuilderOptionGraph {
|
|
|
33
40
|
const optionDependencyKeys = dependencyKeys(payload, paths);
|
|
34
41
|
if (optionDependencyKeys.length === 0) {
|
|
35
42
|
const payload = resolveOption(option, model, {});
|
|
36
|
-
check.
|
|
43
|
+
check.invariant(payload);
|
|
37
44
|
const values = this.#optionValues(option.name, payload);
|
|
38
45
|
return new BuilderOptionGraph([
|
|
39
46
|
...this.paths,
|
|
@@ -65,7 +72,7 @@ export class BuilderOptionGraph {
|
|
|
65
72
|
#mergePaths(dependencyKeys, graphPaths) {
|
|
66
73
|
const dependencyPaths = Array.from(dependencyKeys).map((dependencyKey) => {
|
|
67
74
|
const dependencyPath = graphPaths.find((graphPath) => graphPath.name === dependencyKey);
|
|
68
|
-
check.
|
|
75
|
+
check.invariant(dependencyPath);
|
|
69
76
|
return dependencyPath;
|
|
70
77
|
});
|
|
71
78
|
const [first, ...rest] = dependencyPaths;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BuilderModelSerialisedSchema, BuilderSerialisedSchema } from '../../entities/index.js';
|
|
1
|
+
import { BuilderModelSerialisedSchema, BuilderSerialisedSchema, modelsMerge } from '../../entities/index.js';
|
|
2
2
|
import { check } from '../../errors/index.js';
|
|
3
3
|
import { resolveCollection } from '../resolve.js';
|
|
4
4
|
import { BuilderOptionGraph, crossProduct, dependencyKeys } from './option-graph.js';
|
|
@@ -7,9 +7,10 @@ export function createVariants(entity) {
|
|
|
7
7
|
return buildVariants(model);
|
|
8
8
|
}
|
|
9
9
|
function buildVariants(model) {
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
|
|
10
|
+
const merged = modelsMerge(model);
|
|
11
|
+
const options = optionGraph(merged);
|
|
12
|
+
const nestedVariants = merged.collections.flatMap((entry) => variantsFor(entry, options).flatMap((instance) => {
|
|
13
|
+
const resolved = resolveCollection(entry, merged, instance);
|
|
13
14
|
if (resolved == null) {
|
|
14
15
|
return [];
|
|
15
16
|
}
|
|
@@ -17,8 +18,8 @@ function buildVariants(model) {
|
|
|
17
18
|
return [buildVariants(resolved.model)];
|
|
18
19
|
}));
|
|
19
20
|
return {
|
|
20
|
-
...nestedVariants.reduce((
|
|
21
|
-
...Object.fromEntries(
|
|
21
|
+
...nestedVariants.reduce((accumulated, component) => ({ ...accumulated, ...component }), {}),
|
|
22
|
+
...Object.fromEntries(merged.components.map((component) => [
|
|
22
23
|
component.name,
|
|
23
24
|
variantsFor(component, options).map((instance) => ({ instance }))
|
|
24
25
|
]))
|
package/dist/public.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export type { BB, BBOptions, BuilderEntityValidators } from './bb';
|
|
2
|
+
export type { Builder, BuilderBindings, BuilderBindingsSerialised, BuilderCollection, BuilderCollectionConfig, BuilderCollectionConfigSerialised, BuilderCollections, BuilderCollectionSerialised, BuilderCollectionsSerialised, BuilderCollectionWhen, BuilderCollectionWhenSerialised, BuilderComponent, BuilderComponentConfig, BuilderComponentConfigSerialised, BuilderComponentField, BuilderComponentFields, BuilderComponentFieldSerialised, BuilderComponentFieldsSerialised, BuilderComponentFieldValueType, BuilderComponents, BuilderComponentSerialised, BuilderComponentsSerialised, BuilderComponentWhen, BuilderComponentWhenSerialised, BuilderDescription, BuilderDescriptionItem, BuilderEnableConfig, BuilderEntityKind, BuilderEntitySerialised, BuilderExpectation, BuilderExpectationKind, BuilderExpectations, BuilderExpectationSerialised, BuilderExpectationsSerialised, BuilderInstanceOf, BuilderInstanceValidated, BuilderMatchConfig, BuilderMatchSelectMap, BuilderModel, BuilderModels, BuilderModelSerialised, BuilderModelValidated, BuilderOption, BuilderOptionConfig, BuilderOptionConfigSerialised, BuilderOptions, BuilderOptionSerialised, BuilderOptionsSerialised, BuilderOptionWhen, BuilderOptionWhenSerialised, BuilderPath, BuilderPaths, BuilderPricing, BuilderPricingExpression, BuilderPricingLookupKey, BuilderPricingReduce, BuilderPricingSerialised, BuilderReference, BuilderReferences, BuilderSelectConfig, BuilderSelectConfigLabels, BuilderSelectConfigSerialised, BuilderSelectConfigValues, BuilderSerialised, BuilderTags, BuilderToggleConfig, BuilderToggleConfigSerialised, BuilderToggleValueType, BuilderUI, BuilderUIDescribe, BuilderUIDescribeSerialised, BuilderUIInput, BuilderUIInputMetadata, BuilderUIInputMetadataSerialised, BuilderUIInputs, BuilderUIInputSerialised, BuilderUIInputsSerialised, BuilderUIItem, BuilderUIItems, BuilderUIItemsSerialised, BuilderUIPage, BuilderUIPages, BuilderUIPageSerialised, BuilderUIPagesSerialised, BuilderUIs, BuilderUISerialised, BuilderUIsSerialised, BuilderUIValidated, BuilderUnlessConfig, BuilderValidated, BuilderVariantsValidated, BuilderWhen, BuilderWhenConfig, BuilderWhenSerialised } from './entities/index';
|
|
3
|
+
export type { BuilderEnvironment } from './environment';
|
|
4
|
+
export type { BuilderError, BuilderErrorLocation, BuilderErrors } from './errors/index';
|
|
5
|
+
export type { BuilderErrorKind } from './errors/index.js';
|
|
6
|
+
export type { BuilderComponentVariant, BuilderComponentVariants, BuilderInstance, BuilderInstanceInput, BuilderInstances, BuilderVariants } from './instance';
|
|
7
|
+
export type { BuilderOrder, BuilderRenderMetadata, BuilderRenderOption, BuilderRenderOptions, BuilderRenderPage, BuilderRenderPages, BuilderRenderResult, BuilderRenderUpdate } from './mappers/index';
|
|
8
|
+
export type { BuilderPrimitive, BuilderPrimitives } from './primitive';
|
|
9
|
+
export type { BuilderParameter, BuilderParameterSerialised, BuilderRef, Paramable, ParamableSerialised } from './references';
|
|
10
|
+
export type { BuilderInstanceValidationResult, BuilderModelValidationResult, BuilderPricingValidationResult, BuilderUIValidationResult, BuilderValidationResult, BuilderVariantsValidationOptions, BuilderVariantsValidationResult } from './validate/index';
|
|
11
|
+
export { bb } from './bb.js';
|
|
12
|
+
export { builder, detailBoolean, detailNumber, detailString, input, model, pricing, select, serialise, toggleBoolean, toggleNumber, toggleString } from './entities/index.js';
|
|
13
|
+
export { BuilderException } from './errors/index.js';
|
|
14
|
+
export { ordinal } from './mappers/index.js';
|
|
15
|
+
export { parameter, ref } from './references.js';
|
|
16
|
+
import { collectionConfig, collectionExpectation, componentConfig, componentExpectation, optionExpectation, uis } from './entities/index.js';
|
|
17
|
+
export declare const collection: typeof collectionConfig & {
|
|
18
|
+
enable: <const Values extends import("./references").Paramable<import("./public").BuilderCollectionConfig<import("./references").Paramable<import("./entities/model").BuilderModelGeneric>, import("./references").Paramable<number>, import("./references").Paramable<number>>>>(values: Values) => import("./public").BuilderEnableConfig<Values>;
|
|
19
|
+
match: <const MatchPayload extends import("./references").Paramable<import("./public").BuilderCollectionConfig<import("./references").Paramable<import("./entities/model").BuilderModelGeneric>, import("./references").Paramable<number>, import("./references").Paramable<number>>>, const MatchPath extends import("./references").Paramable<import("./public").BuilderPath>, const SelectMap extends import("./references").Paramable<import("./public").BuilderMatchSelectMap<import("./references").Paramable<import("./public").BuilderCollectionConfig<import("./references").Paramable<import("./entities/model").BuilderModelGeneric>, import("./references").Paramable<number>, import("./references").Paramable<number>>>>>>(matchPath: MatchPath, selectMap: SelectMap) => import("./public").BuilderMatchConfig<MatchPayload, MatchPath, SelectMap>;
|
|
20
|
+
unless: <const Values extends import("./references").Paramable<import("./public").BuilderCollectionConfig<import("./references").Paramable<import("./entities/model").BuilderModelGeneric>, import("./references").Paramable<number>, import("./references").Paramable<number>>>, const UnlessPath extends import("./references").Paramable<import("./public").BuilderPath>>(unlessPath: UnlessPath, disabledValues: import("./primitive").BuilderPrimitives, values: Values) => import("./public").BuilderUnlessConfig<Values, UnlessPath>;
|
|
21
|
+
};
|
|
22
|
+
export declare const component: typeof componentConfig & {
|
|
23
|
+
enable: <const Payload extends import("./references").Paramable<import("./public").BuilderComponentConfig>>(payload?: Payload) => import("./public").BuilderEnableConfig<Payload>;
|
|
24
|
+
match: <const Payload extends import("./references").Paramable<import("./public").BuilderComponentConfig>, const MatchPath extends import("./references").Paramable<import("./public").BuilderPath>, const SelectMap extends import("./references").Paramable<import("./public").BuilderMatchSelectMap<import("./references").Paramable<import("./public").BuilderComponentConfig>>>>(matchPath: MatchPath, selectMap: SelectMap) => import("./public").BuilderMatchConfig<Payload, MatchPath, SelectMap>;
|
|
25
|
+
unless: <const UnlessPath extends import("./references").Paramable<import("./public").BuilderPath>, const Payload extends import("./references").Paramable<import("./public").BuilderComponentConfig>>(unlessPath: UnlessPath, disabledValues: import("./primitive").BuilderPrimitives, payload?: Payload) => import("./public").BuilderUnlessConfig<Payload, UnlessPath>;
|
|
26
|
+
};
|
|
27
|
+
export declare const has: {
|
|
28
|
+
collection: typeof collectionExpectation;
|
|
29
|
+
component: typeof componentExpectation;
|
|
30
|
+
option: typeof optionExpectation;
|
|
31
|
+
};
|
|
32
|
+
export declare const option: {
|
|
33
|
+
enable: <const Values extends import("./references").Paramable<import("./public").BuilderSelectConfig<readonly [string, ...string[]], import("valibot").GenericSchema<string | null>> | import("./public").BuilderToggleConfig<import("valibot").GenericSchema<string | number | boolean | null>>>>(values: Values) => import("./public").BuilderEnableConfig<Values>;
|
|
34
|
+
match: <const MatchPayload extends import("./references").Paramable<import("./public").BuilderSelectConfig<readonly [string, ...string[]], import("valibot").GenericSchema<string | null>> | import("./public").BuilderToggleConfig<import("valibot").GenericSchema<string | number | boolean | null>>>, const MatchPath extends import("./references").Paramable<import("./public").BuilderPath>, const SelectMap extends import("./references").Paramable<import("./public").BuilderMatchSelectMap<import("./references").Paramable<import("./public").BuilderSelectConfig<readonly [string, ...string[]], import("valibot").GenericSchema<string | null>> | import("./public").BuilderToggleConfig<import("valibot").GenericSchema<string | number | boolean | null>>>>>>(matchPath: MatchPath, selectMap: SelectMap) => import("./public").BuilderMatchConfig<MatchPayload, MatchPath, SelectMap>;
|
|
35
|
+
unless: <const Values extends import("./references").Paramable<import("./public").BuilderSelectConfig<readonly [string, ...string[]], import("valibot").GenericSchema<string | null>> | import("./public").BuilderToggleConfig<import("valibot").GenericSchema<string | number | boolean | null>>>, const UnlessPath extends import("./references").Paramable<import("./public").BuilderPath>>(unlessPath: UnlessPath, disabledValues: import("./primitive").BuilderPrimitives, values: Values) => import("./public").BuilderUnlessConfig<Values, UnlessPath>;
|
|
36
|
+
};
|
|
37
|
+
export declare const ui: typeof uis;
|
package/dist/public.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export { bb } from './bb.js';
|
|
2
|
+
export { builder, detailBoolean, detailNumber, detailString, input, model, pricing, select, serialise, toggleBoolean, toggleNumber, toggleString } from './entities/index.js';
|
|
3
|
+
export { BuilderException } from './errors/index.js';
|
|
4
|
+
export { ordinal } from './mappers/index.js';
|
|
5
|
+
export { parameter, ref } from './references.js';
|
|
6
|
+
import { collectionConfig, collectionExpectation, collectionWhen, componentConfig, componentExpectation, componentWhen, optionExpectation, optionWhen, uis } from './entities/index.js';
|
|
7
|
+
export const collection = Object.assign(collectionConfig, {
|
|
8
|
+
...collectionWhen
|
|
9
|
+
});
|
|
10
|
+
export const component = Object.assign(componentConfig, {
|
|
11
|
+
...componentWhen
|
|
12
|
+
});
|
|
13
|
+
export const has = {
|
|
14
|
+
collection: collectionExpectation,
|
|
15
|
+
component: componentExpectation,
|
|
16
|
+
option: optionExpectation
|
|
17
|
+
};
|
|
18
|
+
export const option = optionWhen;
|
|
19
|
+
export const ui = uis;
|
package/dist/validate/brand.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BuilderException
|
|
1
|
+
import { BuilderException } from '../errors/index.js';
|
|
2
2
|
const VALIDATED_ENTITIES = new WeakSet();
|
|
3
3
|
export function validate(value) {
|
|
4
4
|
VALIDATED_ENTITIES.add(value);
|
|
@@ -6,8 +6,6 @@ export function validate(value) {
|
|
|
6
6
|
}
|
|
7
7
|
export function assertValidated(value) {
|
|
8
8
|
if (typeof value !== 'object' || value === null || !VALIDATED_ENTITIES.has(value)) {
|
|
9
|
-
|
|
10
|
-
errors.unvalidated(value);
|
|
11
|
-
throw new BuilderException({ category: 'validation', errors: errors.errors });
|
|
9
|
+
throw new BuilderException({ category: 'invariant', value });
|
|
12
10
|
}
|
|
13
11
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { BuilderReferences, BuilderValidated, ValidationResult } from '../entities/index';
|
|
2
|
-
import {
|
|
2
|
+
import { BuilderErrorsScope } from '../errors/index.js';
|
|
3
3
|
export type BuilderValidationResult = ValidationResult<BuilderValidated>;
|
|
4
|
-
export declare function validateBuilder(input: unknown, references?: BuilderReferences, errors?:
|
|
4
|
+
export declare function validateBuilder(input: unknown, references?: BuilderReferences, errors?: BuilderErrorsScope): BuilderValidationResult;
|
package/dist/validate/builder.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { builder, BuilderSerialisedSchema, modelsMerge, serialise } from '../entities/index.js';
|
|
2
|
-
import {
|
|
2
|
+
import { BuilderErrorsScope, check } from '../errors/index.js';
|
|
3
3
|
import { validate } from './brand.js';
|
|
4
4
|
import { checkModelExpectations, validateModelStructure } from './model.js';
|
|
5
5
|
import { checkPricingExpectations, validatePricingStructure } from './pricing.js';
|
|
6
6
|
import { resolver } from './resolve.js';
|
|
7
7
|
import { checkUIExpectations, validateUIStructure } from './ui.js';
|
|
8
8
|
const EMPTY_BUILDER = validate(serialise.builder(builder()));
|
|
9
|
-
export function validateBuilder(input, references = [], errors = new
|
|
9
|
+
export function validateBuilder(input, references = [], errors = new BuilderErrorsScope(input)) {
|
|
10
10
|
if (!check.is(BuilderSerialisedSchema, input)) {
|
|
11
|
-
errors.
|
|
11
|
+
errors.entityInvalid('builder');
|
|
12
12
|
return [EMPTY_BUILDER, errors.errors];
|
|
13
13
|
}
|
|
14
14
|
const resolve = resolver(errors, references, input.bindings);
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { BuilderExpectationsSerialised, BuilderModelSerialised } from '../entities/index';
|
|
2
|
-
import type {
|
|
3
|
-
export declare function checkExpectations(model: BuilderModelSerialised, expectations: BuilderExpectationsSerialised, errors:
|
|
2
|
+
import type { BuilderErrorsScope } from '../errors/index';
|
|
3
|
+
export declare function checkExpectations(model: BuilderModelSerialised, expectations: BuilderExpectationsSerialised, errors: BuilderErrorsScope): void;
|
package/dist/validate/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export type { BuilderValidatedMap, ValidationResult } from '../entities/index';
|
|
2
|
-
export type { BuilderErrorKind, BuilderValidateErrors } from '../errors/index';
|
|
3
2
|
export type { BuilderValidatedBrand } from './brand';
|
|
4
3
|
export type { BuilderValidationResult } from './builder';
|
|
5
4
|
export type { BuilderInstanceValidationResult } from './instance';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BuilderInstanceValidated, BuilderModelValidated, ValidationResult } from '../entities/index';
|
|
2
2
|
import type { BuilderInstance } from '../instance';
|
|
3
|
-
import {
|
|
3
|
+
import { BuilderErrorsScope } from '../errors/index.js';
|
|
4
4
|
export type BuilderInstanceValidationResult = ValidationResult<BuilderInstanceValidated>;
|
|
5
|
-
export declare function validateInstance(model: BuilderModelValidated, instance: BuilderInstance, errors?:
|
|
5
|
+
export declare function validateInstance(model: BuilderModelValidated, instance: BuilderInstance, errors?: BuilderErrorsScope): BuilderInstanceValidationResult;
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { optionValueSchema } from '../entities/index.js';
|
|
2
|
-
import {
|
|
2
|
+
import { BuilderErrorsScope, check } from '../errors/index.js';
|
|
3
3
|
import { BuilderInstancesSchema } from '../instance.js';
|
|
4
4
|
import { resolveCollection, resolveOption } from '../mappers/index.js';
|
|
5
5
|
import { validate } from './brand.js';
|
|
6
|
-
export function validateInstance(model, instance, errors = new
|
|
6
|
+
export function validateInstance(model, instance, errors = new BuilderErrorsScope(instance)) {
|
|
7
7
|
errors.scope('instance', () => {
|
|
8
8
|
checkInstance(model, instance);
|
|
9
9
|
});
|
|
10
10
|
return [validate(instance), errors.errors];
|
|
11
|
-
function checkInstance(scopeModel, scopeInstance
|
|
11
|
+
function checkInstance(scopeModel, scopeInstance) {
|
|
12
12
|
scopeModel.options.forEach((option) => {
|
|
13
13
|
const { name } = option;
|
|
14
14
|
const payload = resolveOption(option, scopeModel, scopeInstance);
|
|
@@ -18,7 +18,7 @@ export function validateInstance(model, instance, errors = new BuilderValidateEr
|
|
|
18
18
|
const value = scopeInstance[name];
|
|
19
19
|
if (!check.is(optionValueSchema(payload), value)) {
|
|
20
20
|
errors.scope(name, () => {
|
|
21
|
-
errors.
|
|
21
|
+
errors.instanceInvalidOption();
|
|
22
22
|
});
|
|
23
23
|
}
|
|
24
24
|
});
|
|
@@ -31,14 +31,14 @@ export function validateInstance(model, instance, errors = new BuilderValidateEr
|
|
|
31
31
|
const existing = scopeInstance[name];
|
|
32
32
|
if (!check.is(BuilderInstancesSchema, existing)) {
|
|
33
33
|
errors.scope(name, () => {
|
|
34
|
-
errors.
|
|
34
|
+
errors.instanceInvalidCollection();
|
|
35
35
|
});
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
38
|
errors.scope(name, () => {
|
|
39
39
|
existing.forEach((itemInstance, index) => {
|
|
40
40
|
errors.scope(index, () => {
|
|
41
|
-
checkInstance(payload.model, itemInstance
|
|
41
|
+
checkInstance(payload.model, itemInstance);
|
|
42
42
|
});
|
|
43
43
|
});
|
|
44
44
|
});
|
package/dist/validate/model.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { BuilderModelSerialised, BuilderModelValidated, BuilderReferences, ValidationResult } from '../entities/index';
|
|
2
2
|
import type { ParamableSerialised } from '../references';
|
|
3
3
|
import type { BuilderResolve } from './resolve';
|
|
4
|
-
import {
|
|
4
|
+
import { BuilderErrorsScope } from '../errors/index.js';
|
|
5
5
|
export type BuilderModelValidationResult = ValidationResult<BuilderModelValidated>;
|
|
6
|
-
export declare function validateModel(input: unknown, references?: BuilderReferences, errors?:
|
|
7
|
-
export declare function checkModelExpectations(mergedModel: BuilderModelSerialised, rootModel: BuilderModelSerialised, errors:
|
|
8
|
-
export declare function validateModelStructure(input: ParamableSerialised<BuilderModelSerialised>, resolve: BuilderResolve, errors:
|
|
6
|
+
export declare function validateModel(input: unknown, references?: BuilderReferences, errors?: BuilderErrorsScope): BuilderModelValidationResult;
|
|
7
|
+
export declare function checkModelExpectations(mergedModel: BuilderModelSerialised, rootModel: BuilderModelSerialised, errors: BuilderErrorsScope): void;
|
|
8
|
+
export declare function validateModelStructure(input: ParamableSerialised<BuilderModelSerialised>, resolve: BuilderResolve, errors: BuilderErrorsScope): BuilderModelValidated;
|
package/dist/validate/model.js
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import { BuilderCollectionConfigSerialisedSchema, BuilderComponentConfigSerialisedSchema, BuilderModelSerialisedSchema, BuilderOptionConfigSerialisedSchema, BuilderWhenSerialisedSchema, whenBranches, model, modelsMerge, serialise, validateCollectionConfig, validateComponentConfig, validateSelect, validateToggle } from '../entities/index.js';
|
|
2
|
-
import {
|
|
2
|
+
import { BuilderErrorsScope, check } from '../errors/index.js';
|
|
3
3
|
import { isParamable } from '../references.js';
|
|
4
4
|
import { validate } from './brand.js';
|
|
5
5
|
import { checkExpectations } from './expectations.js';
|
|
6
6
|
import { checkPath } from './paths.js';
|
|
7
7
|
import { resolver } from './resolve.js';
|
|
8
8
|
const EMPTY_MODEL = validate(serialise.model(model()));
|
|
9
|
-
export function validateModel(input, references = [], errors = new
|
|
9
|
+
export function validateModel(input, references = [], errors = new BuilderErrorsScope(input)) {
|
|
10
10
|
if (!check.is(BuilderModelSerialisedSchema, input)) {
|
|
11
|
-
errors.
|
|
11
|
+
errors.entityInvalid('model');
|
|
12
12
|
return [EMPTY_MODEL, errors.errors];
|
|
13
13
|
}
|
|
14
14
|
const resolve = resolver(errors, references);
|
|
15
15
|
const structure = validateModelStructure(input, resolve, errors);
|
|
16
|
-
const
|
|
16
|
+
const merged = modelsMerge(structure);
|
|
17
|
+
const data = validate(merged);
|
|
17
18
|
checkModelExpectations(data, structure, errors);
|
|
18
19
|
return [data, errors.errors];
|
|
19
20
|
}
|
|
@@ -33,111 +34,127 @@ export function checkModelExpectations(mergedModel, rootModel, errors) {
|
|
|
33
34
|
}
|
|
34
35
|
}
|
|
35
36
|
export function validateModelStructure(input, resolve, errors) {
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const modelInput = resolved;
|
|
41
|
-
const skipPathValidation = modelInput.expectations.length > 0;
|
|
42
|
-
const childModels = errors.scope('models', () => modelInput.models.flatMap((part, partIndex) => errors.scope(partIndex, () => [validateModelStructure(part, resolve, errors)])));
|
|
43
|
-
const options = errors.scope('options', () => walkEntries(modelInput.options, (resolved) => {
|
|
44
|
-
whenBranches(resolved.payload, BuilderOptionConfigSerialisedSchema)
|
|
45
|
-
.filter((config) => !isParamable(config))
|
|
46
|
-
.forEach((config) => {
|
|
47
|
-
if (config.type === 'select') {
|
|
48
|
-
validateSelect(config, [], errors);
|
|
49
|
-
}
|
|
50
|
-
else if (config.type === 'toggle') {
|
|
51
|
-
validateToggle(config, [], errors);
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
}));
|
|
55
|
-
const components = errors.scope('components', () => walkEntries(modelInput.components, (resolved) => {
|
|
56
|
-
whenBranches(resolved.payload, BuilderComponentConfigSerialisedSchema)
|
|
57
|
-
.filter((config) => !isParamable(config))
|
|
58
|
-
.forEach((config) => {
|
|
59
|
-
validateComponentConfig(config, [], errors);
|
|
60
|
-
});
|
|
61
|
-
}));
|
|
62
|
-
const collections = errors.scope('collections', () => walkEntries(modelInput.collections, (resolved) => {
|
|
63
|
-
whenBranches(resolved.payload, BuilderCollectionConfigSerialisedSchema)
|
|
64
|
-
.filter((config) => !isParamable(config))
|
|
65
|
-
.forEach((config) => {
|
|
66
|
-
validateCollectionConfig(config, [], errors);
|
|
67
|
-
});
|
|
68
|
-
}));
|
|
69
|
-
return {
|
|
70
|
-
...modelInput,
|
|
71
|
-
models: childModels,
|
|
72
|
-
options,
|
|
73
|
-
components,
|
|
74
|
-
collections
|
|
37
|
+
const seenGlobal = {
|
|
38
|
+
option: new Set(),
|
|
39
|
+
component: new Set(),
|
|
40
|
+
collection: new Set()
|
|
75
41
|
};
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
42
|
+
return walkStructure(input);
|
|
43
|
+
function walkStructure(input) {
|
|
44
|
+
const resolved = resolve(input);
|
|
45
|
+
if (!check.is(BuilderModelSerialisedSchema, resolved)) {
|
|
46
|
+
return validate(serialise.model(model()));
|
|
47
|
+
}
|
|
48
|
+
const modelInput = resolved;
|
|
49
|
+
const skipPathValidation = modelInput.expectations.length > 0;
|
|
50
|
+
const childModels = errors.scope('models', () => modelInput.models.flatMap((part, partIndex) => errors.scope(partIndex, () => [walkStructure(part)])));
|
|
51
|
+
const options = errors.scope('options', () => walkEntries(modelInput.options, 'option', (resolved) => {
|
|
52
|
+
whenBranches(resolved.payload, BuilderOptionConfigSerialisedSchema)
|
|
53
|
+
.filter((config) => !isParamable(config))
|
|
54
|
+
.forEach((config) => {
|
|
55
|
+
if (config.type === 'select') {
|
|
56
|
+
validateSelect(config, [], errors);
|
|
57
|
+
}
|
|
58
|
+
else if (config.type === 'toggle') {
|
|
59
|
+
validateToggle(config, [], errors);
|
|
84
60
|
}
|
|
85
|
-
validateBranches(resolved);
|
|
86
|
-
items.push(resolved);
|
|
87
61
|
});
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const resolvedPaths = errors.scope('paths', () => resolve(entry.paths));
|
|
95
|
-
paths = resolvedPaths ?? entry.paths;
|
|
96
|
-
}
|
|
97
|
-
const payload = errors.scope('payload', () => resolve(entry.payload));
|
|
98
|
-
const resolvedEntry = { ...entry, paths, payload: payload ?? entry.payload };
|
|
99
|
-
if (seen.has(resolvedEntry.name)) {
|
|
100
|
-
errors.duplicateName(resolvedEntry.name);
|
|
101
|
-
return null;
|
|
102
|
-
}
|
|
103
|
-
seen.add(resolvedEntry.name);
|
|
104
|
-
checkPaths(resolvedEntry);
|
|
105
|
-
return resolvedEntry;
|
|
106
|
-
}
|
|
107
|
-
function checkPaths(entry) {
|
|
108
|
-
if (skipPathValidation) {
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
const { paths, payload } = entry;
|
|
112
|
-
if (Array.isArray(paths)) {
|
|
113
|
-
errors.scope('paths', () => {
|
|
114
|
-
paths.forEach((path, pathIndex) => {
|
|
115
|
-
errors.scope(pathIndex, () => {
|
|
116
|
-
checkPath(modelInput, path, errors);
|
|
117
|
-
});
|
|
118
|
-
});
|
|
62
|
+
}));
|
|
63
|
+
const components = errors.scope('components', () => walkEntries(modelInput.components, 'component', (resolved) => {
|
|
64
|
+
whenBranches(resolved.payload, BuilderComponentConfigSerialisedSchema)
|
|
65
|
+
.filter((config) => !isParamable(config))
|
|
66
|
+
.forEach((config) => {
|
|
67
|
+
validateComponentConfig(config, [], errors);
|
|
119
68
|
});
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
69
|
+
}));
|
|
70
|
+
const collections = errors.scope('collections', () => walkEntries(modelInput.collections, 'collection', (resolved) => {
|
|
71
|
+
whenBranches(resolved.payload, BuilderCollectionConfigSerialisedSchema)
|
|
72
|
+
.filter((config) => !isParamable(config))
|
|
73
|
+
.forEach((config) => {
|
|
74
|
+
validateCollectionConfig(config, [], errors);
|
|
75
|
+
});
|
|
76
|
+
}));
|
|
77
|
+
return {
|
|
78
|
+
...modelInput,
|
|
79
|
+
models: childModels,
|
|
80
|
+
options,
|
|
81
|
+
components,
|
|
82
|
+
collections
|
|
83
|
+
};
|
|
84
|
+
function walkEntries(entries, kind, validateBranches) {
|
|
85
|
+
const seenLocal = new Set();
|
|
86
|
+
const items = [];
|
|
87
|
+
entries.forEach((entry, entryIndex) => {
|
|
88
|
+
errors.scope(entryIndex, () => {
|
|
89
|
+
const resolved = resolveEntry(entry, seenLocal, kind);
|
|
90
|
+
if (resolved == null) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
validateBranches(resolved);
|
|
94
|
+
items.push(resolved);
|
|
131
95
|
});
|
|
132
96
|
});
|
|
133
|
-
return;
|
|
97
|
+
return items;
|
|
98
|
+
}
|
|
99
|
+
function resolveEntry(entry, seenLocal, kind) {
|
|
100
|
+
let paths = entry.paths;
|
|
101
|
+
if (entry.paths != null) {
|
|
102
|
+
const resolvedPaths = errors.scope('paths', () => resolve(entry.paths));
|
|
103
|
+
paths = resolvedPaths ?? entry.paths;
|
|
104
|
+
}
|
|
105
|
+
const payload = errors.scope('payload', () => resolve(entry.payload));
|
|
106
|
+
const resolvedEntry = { ...entry, paths, payload: payload ?? entry.payload };
|
|
107
|
+
if (seenLocal.has(resolvedEntry.name)) {
|
|
108
|
+
if (kind === 'option') {
|
|
109
|
+
errors.modelDuplicateOption();
|
|
110
|
+
}
|
|
111
|
+
else if (kind === 'component') {
|
|
112
|
+
errors.modelDuplicateComponent();
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
errors.modelDuplicateCollection();
|
|
116
|
+
}
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
if (seenGlobal[kind].has(resolvedEntry.name)) {
|
|
120
|
+
if (kind === 'option') {
|
|
121
|
+
errors.modelOverriddenOption();
|
|
122
|
+
}
|
|
123
|
+
else if (kind === 'component') {
|
|
124
|
+
errors.modelOverriddenComponent();
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
errors.modelOverriddenCollection();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
seenLocal.add(resolvedEntry.name);
|
|
131
|
+
seenGlobal[kind].add(resolvedEntry.name);
|
|
132
|
+
checkPaths(resolvedEntry);
|
|
133
|
+
return resolvedEntry;
|
|
134
134
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
135
|
+
function checkPaths(entry) {
|
|
136
|
+
if (skipPathValidation) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const { paths, payload } = entry;
|
|
140
|
+
if (Array.isArray(paths)) {
|
|
141
|
+
errors.scope('paths', () => {
|
|
142
|
+
paths.forEach((path, pathIndex) => {
|
|
143
|
+
errors.scope(pathIndex, () => {
|
|
144
|
+
checkPath(modelInput, path, errors);
|
|
145
|
+
});
|
|
146
|
+
});
|
|
139
147
|
});
|
|
140
|
-
}
|
|
148
|
+
}
|
|
149
|
+
if (!check.is(BuilderWhenSerialisedSchema, payload)) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
if (payload.type === 'match' && Array.isArray(payload.matchPath)) {
|
|
153
|
+
errors.scope('payload', () => errors.scope('matchPath', () => checkPath(modelInput, payload.matchPath, errors)));
|
|
154
|
+
}
|
|
155
|
+
if (payload.type === 'unless' && Array.isArray(payload.unlessPath)) {
|
|
156
|
+
errors.scope('payload', () => errors.scope('unlessPath', () => checkPath(modelInput, payload.unlessPath, errors)));
|
|
157
|
+
}
|
|
141
158
|
}
|
|
142
159
|
}
|
|
143
160
|
}
|
package/dist/validate/paths.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { BuilderModelSerialised, BuilderPath } from '../entities/index';
|
|
2
|
-
import type {
|
|
3
|
-
export declare function checkPath(model: BuilderModelSerialised, path: BuilderPath, errors:
|
|
2
|
+
import type { BuilderErrorsScope } from '../errors/index';
|
|
3
|
+
export declare function checkPath(model: BuilderModelSerialised, path: BuilderPath, errors: BuilderErrorsScope): void;
|