@builder-builder/builder 0.0.26 → 0.0.28
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.js +4 -4
- package/dist/client/client.d.ts +2 -1
- package/dist/client/client.js +4 -1
- package/dist/client/public.d.ts +2 -2
- package/dist/client/public.js +1 -1
- package/dist/client/schema.d.ts +103 -17
- package/dist/client/schema.js +7 -0
- package/dist/components/Builder.svelte.d.ts +24 -0
- package/dist/components/BuilderCollectionButtons.svelte.d.ts +22 -0
- package/dist/components/BuilderCollections.svelte.d.ts +23 -0
- package/dist/components/BuilderDescription.svelte.d.ts +18 -0
- package/dist/components/BuilderLayout.svelte.d.ts +24 -0
- package/dist/components/BuilderOption.svelte.d.ts +31 -0
- package/dist/components/BuilderOptionSelect.svelte.d.ts +21 -0
- package/dist/components/BuilderOptionToggleBoolean.svelte.d.ts +20 -0
- package/dist/components/BuilderOptionToggleNumber.svelte.d.ts +21 -0
- package/dist/components/BuilderOptionToggleString.svelte.d.ts +21 -0
- package/dist/components/BuilderPrice.svelte.d.ts +21 -0
- package/dist/components/BuilderRender.svelte.d.ts +39 -0
- package/dist/components/config.d.ts +2 -0
- package/dist/components/config.js +1 -0
- package/dist/components/dispatch.d.ts +1 -0
- package/dist/components/dispatch.js +3 -0
- package/dist/components/id.d.ts +1 -0
- package/dist/components/id.js +3 -0
- package/dist/components/index.d.ts +25 -0
- package/dist/components/index.js +7515 -0
- package/dist/components/index.min.js +3 -0
- package/dist/entities/collection/collection.d.ts +66 -66
- package/dist/entities/collection/config.d.ts +17 -17
- package/dist/entities/collection/when.d.ts +1 -1
- package/dist/entities/component/component.d.ts +64 -64
- package/dist/entities/component/config.d.ts +33 -33
- package/dist/entities/component/config.js +18 -16
- package/dist/entities/component/detail.d.ts +61 -0
- package/dist/entities/component/detail.js +71 -0
- package/dist/entities/component/index.d.ts +2 -2
- package/dist/entities/component/index.js +1 -1
- package/dist/entities/component/when.d.ts +2 -2
- package/dist/entities/expectation.d.ts +1 -1
- package/dist/entities/index.d.ts +4 -4
- package/dist/entities/index.js +1 -1
- package/dist/entities/kind.d.ts +3 -3
- package/dist/entities/kind.js +20 -20
- package/dist/entities/model/methods.d.ts +1 -1
- package/dist/entities/option/config.d.ts +7 -7
- package/dist/entities/option/config.js +1 -1
- package/dist/entities/option/index.d.ts +4 -4
- package/dist/entities/option/index.js +2 -2
- package/dist/entities/option/option.d.ts +22 -22
- package/dist/entities/option/select.d.ts +1 -1
- package/dist/entities/option/toggle.d.ts +9 -9
- package/dist/entities/option/toggle.js +15 -10
- package/dist/entities/option/when.d.ts +1 -1
- package/dist/entities/paths.d.ts +2 -2
- package/dist/entities/pricing/expression.d.ts +16 -39
- package/dist/entities/pricing/expression.js +1 -16
- package/dist/entities/pricing/index.d.ts +1 -1
- package/dist/entities/pricing/rates.d.ts +1 -1
- package/dist/entities/references.d.ts +72 -24
- package/dist/entities/serialise.d.ts +148 -32
- package/dist/entities/serialise.js +7 -7
- package/dist/entities/ui/describe.d.ts +49 -1
- package/dist/entities/ui/input.d.ts +67 -2
- package/dist/entities/ui/input.js +8 -2
- package/dist/entities/ui/page.d.ts +49 -1
- package/dist/entities/ui/pages.d.ts +10 -2
- package/dist/entities/validated.d.ts +2 -2
- package/dist/entities/when.d.ts +5 -5
- package/dist/environment.d.ts +2 -2
- package/dist/errors/errors.d.ts +86 -55
- package/dist/errors/errors.js +36 -5
- package/dist/errors/exception.d.ts +3 -3
- package/dist/errors/index.d.ts +1 -1
- package/dist/errors/index.js +1 -1
- package/dist/errors/public.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/instance.d.ts +53 -9
- package/dist/instance.js +6 -2
- package/dist/mappers/dependencies.d.ts +3 -0
- package/dist/mappers/dependencies.js +44 -0
- package/dist/mappers/index.d.ts +2 -2
- package/dist/mappers/index.js +2 -1
- package/dist/mappers/instance.js +26 -21
- package/dist/mappers/order.js +4 -2
- package/dist/mappers/price.js +6 -4
- package/dist/mappers/render/option.d.ts +1 -0
- package/dist/mappers/render/option.js +1 -0
- package/dist/mappers/variants/index.d.ts +1 -2
- package/dist/mappers/variants/index.js +1 -2
- package/dist/mappers/variants/option-graph.d.ts +1 -2
- package/dist/mappers/variants/option-graph.js +3 -17
- package/dist/mappers/variants/variants.d.ts +3 -6
- package/dist/mappers/variants/variants.js +34 -11
- package/dist/primitive.d.ts +3 -0
- package/dist/primitive.js +2 -0
- package/dist/public.d.ts +8 -8
- package/dist/public.js +1 -1
- package/dist/validate/builder.d.ts +2 -2
- package/dist/validate/builder.js +15 -15
- package/dist/validate/expectations.d.ts +2 -2
- package/dist/validate/expectations.js +3 -3
- package/dist/validate/instance.d.ts +2 -2
- package/dist/validate/instance.js +31 -13
- package/dist/validate/model.d.ts +4 -4
- package/dist/validate/model.js +51 -42
- package/dist/validate/paths.d.ts +2 -2
- package/dist/validate/paths.js +19 -14
- package/dist/validate/pricing.d.ts +4 -4
- package/dist/validate/pricing.js +31 -31
- package/dist/validate/resolve.d.ts +2 -2
- package/dist/validate/resolve.js +18 -18
- package/dist/validate/ui.d.ts +4 -4
- package/dist/validate/ui.js +38 -38
- package/dist/validate/variants.d.ts +3 -3
- package/dist/validate/variants.js +32 -31
- package/package.json +9 -5
- package/dist/entities/component/field.d.ts +0 -59
- package/dist/entities/component/field.js +0 -52
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { BuilderPathSchema, BuilderPathsSchema, BuilderWhenMatchSchema, BuilderWhenUnlessSchema } from '../entities/index.js';
|
|
2
|
+
import { check } from '../errors/index.js';
|
|
3
|
+
export function dependencies(model) {
|
|
4
|
+
const entries = [...model.options, ...model.collections, ...model.components];
|
|
5
|
+
const names = new Set(entries.map((entry) => entry.name));
|
|
6
|
+
const ordered = [];
|
|
7
|
+
const visiting = new Set();
|
|
8
|
+
const visit = (name) => {
|
|
9
|
+
if (ordered.includes(name)) {
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
if (visiting.has(name)) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
const entry = entries.find((candidate) => candidate.name === name);
|
|
16
|
+
check.invariant(entry);
|
|
17
|
+
visiting.add(name);
|
|
18
|
+
const resolved = dependencyKeys(entry.payload, entry.paths)
|
|
19
|
+
.filter((dependency) => names.has(dependency))
|
|
20
|
+
.map((dependency) => visit(dependency))
|
|
21
|
+
.every(Boolean);
|
|
22
|
+
visiting.delete(name);
|
|
23
|
+
if (resolved) {
|
|
24
|
+
ordered.push(name);
|
|
25
|
+
}
|
|
26
|
+
return resolved;
|
|
27
|
+
};
|
|
28
|
+
names.forEach((name) => visit(name));
|
|
29
|
+
return ordered;
|
|
30
|
+
}
|
|
31
|
+
export function dependencyKeys(payload, paths = []) {
|
|
32
|
+
const conditionPaths = check.is(BuilderPathsSchema, paths) ? paths : [];
|
|
33
|
+
const keys = new Set(conditionPaths.map(([first]) => String(first)));
|
|
34
|
+
if (check.is(BuilderWhenMatchSchema, payload) && check.is(BuilderPathSchema, payload.matchPath)) {
|
|
35
|
+
const [firstMatchSegment] = payload.matchPath;
|
|
36
|
+
keys.add(String(firstMatchSegment));
|
|
37
|
+
}
|
|
38
|
+
else if (check.is(BuilderWhenUnlessSchema, payload) &&
|
|
39
|
+
check.is(BuilderPathSchema, payload.unlessPath)) {
|
|
40
|
+
const [firstUnlessSegment] = payload.unlessPath;
|
|
41
|
+
keys.add(String(firstUnlessSegment));
|
|
42
|
+
}
|
|
43
|
+
return Array.from(keys);
|
|
44
|
+
}
|
package/dist/mappers/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export type { BuilderOrder } from './order';
|
|
2
2
|
export type { BuilderRenderCollection, BuilderRenderCollectionAddRemove, BuilderRenderCollections, BuilderRenderMetadata, BuilderRenderOption, BuilderRenderOptions, BuilderRenderOptionUpdate, BuilderRenderPage, BuilderRenderPages, BuilderRenderResult } from './render/index';
|
|
3
|
-
export
|
|
3
|
+
export { dependencies, dependencyKeys } from './dependencies.js';
|
|
4
4
|
export { createInstance } from './instance.js';
|
|
5
5
|
export { order } from './order.js';
|
|
6
6
|
export { price } from './price.js';
|
|
7
7
|
export { ordinal, render } from './render/index.js';
|
|
8
8
|
export { resolveCollection, resolveCollections, resolveComponent, resolveComponents, resolveOption, resolveOptions } from './resolve.js';
|
|
9
|
-
export { createVariants
|
|
9
|
+
export { createVariants } from './variants/index.js';
|
package/dist/mappers/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
export { dependencies, dependencyKeys } from './dependencies.js';
|
|
1
2
|
export { createInstance } from './instance.js';
|
|
2
3
|
export { order } from './order.js';
|
|
3
4
|
export { price } from './price.js';
|
|
4
5
|
export { ordinal, render } from './render/index.js';
|
|
5
6
|
export { resolveCollection, resolveCollections, resolveComponent, resolveComponents, resolveOption, resolveOptions } from './resolve.js';
|
|
6
|
-
export { createVariants
|
|
7
|
+
export { createVariants } from './variants/index.js';
|
package/dist/mappers/instance.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { modelsMerge, optionValueSchema } from '../entities/index.js';
|
|
2
2
|
import { check } from '../errors/index.js';
|
|
3
3
|
import { BuilderInstanceSchema, BuilderInstancesSchema } from '../instance.js';
|
|
4
|
+
import { dependencies } from './dependencies.js';
|
|
4
5
|
import { resolveCollection, resolveOption } from './resolve.js';
|
|
5
6
|
export function createInstance(entity, partial = {}, references = []) {
|
|
6
7
|
const model = 'model' in entity ? entity.model : entity;
|
|
@@ -10,31 +11,35 @@ export function createInstance(entity, partial = {}, references = []) {
|
|
|
10
11
|
}
|
|
11
12
|
function buildInstance(model, partial, references) {
|
|
12
13
|
const merged = modelsMerge(model);
|
|
14
|
+
const names = dependencies(merged);
|
|
13
15
|
let instance = { ...partial };
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
names.forEach((name) => {
|
|
17
|
+
const option = merged.options.find((entry) => entry.name === name);
|
|
18
|
+
if (option != null) {
|
|
19
|
+
const payload = resolveOption(option, model, instance, references);
|
|
20
|
+
if (payload == null) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (check.is(optionValueSchema(payload), instance[name])) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
instance = { ...instance, [name]: payload.defaultValue };
|
|
18
27
|
return;
|
|
19
28
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
const collection = merged.collections.find((entry) => entry.name === name);
|
|
30
|
+
if (collection != null) {
|
|
31
|
+
const payload = resolveCollection(collection, model, instance, references);
|
|
32
|
+
if (payload == null) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const existing = instance[name];
|
|
36
|
+
const existingItems = check.is(BuilderInstancesSchema, existing)
|
|
37
|
+
? existing
|
|
38
|
+
: [];
|
|
39
|
+
const count = Math.min(Math.max(existingItems.length, payload.min), payload.max);
|
|
40
|
+
const items = Array.from({ length: count }, (_, index) => buildInstance(payload.model, existingItems[index] ?? {}, references));
|
|
41
|
+
instance = { ...instance, [name]: items };
|
|
30
42
|
}
|
|
31
|
-
const existing = instance[name];
|
|
32
|
-
const existingItems = check.is(BuilderInstancesSchema, existing)
|
|
33
|
-
? existing
|
|
34
|
-
: [];
|
|
35
|
-
const count = Math.max(existingItems.length, payload.min);
|
|
36
|
-
const items = Array.from({ length: count }, (_, index) => buildInstance(payload.model, existingItems[index] ?? {}, references));
|
|
37
|
-
instance = { ...instance, [name]: items };
|
|
38
43
|
});
|
|
39
44
|
return instance;
|
|
40
45
|
}
|
package/dist/mappers/order.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { modelsMerge } from '../entities/index.js';
|
|
1
2
|
import { check } from '../errors/index.js';
|
|
2
3
|
import { BuilderInstancesSchema } from '../instance.js';
|
|
3
4
|
import { resolveCollection, resolveComponent } from './resolve.js';
|
|
4
5
|
export function order(model, instance, variants, references = []) {
|
|
5
6
|
const result = {};
|
|
6
|
-
model
|
|
7
|
+
const merged = modelsMerge(model);
|
|
8
|
+
merged.components.forEach((component) => {
|
|
7
9
|
if (resolveComponent(component, model, instance, references) == null) {
|
|
8
10
|
return;
|
|
9
11
|
}
|
|
@@ -11,7 +13,7 @@ export function order(model, instance, variants, references = []) {
|
|
|
11
13
|
result[component.name] =
|
|
12
14
|
componentVariants.find((variant) => Object.entries(variant.instance).every(([key, value]) => instance[key] === value)) ?? null;
|
|
13
15
|
});
|
|
14
|
-
|
|
16
|
+
merged.collections.forEach((collection) => {
|
|
15
17
|
const { name } = collection;
|
|
16
18
|
const payload = resolveCollection(collection, model, instance, references);
|
|
17
19
|
if (payload == null) {
|
package/dist/mappers/price.js
CHANGED
|
@@ -16,8 +16,10 @@ export function price(pricingInput, order) {
|
|
|
16
16
|
}
|
|
17
17
|
switch (expression.kind) {
|
|
18
18
|
case 'variantPrice':
|
|
19
|
+
check.invariant(variant);
|
|
19
20
|
return variantPrice(variant);
|
|
20
21
|
case 'lookup':
|
|
22
|
+
check.invariant(variant);
|
|
21
23
|
return evaluateLookup(expression, variant);
|
|
22
24
|
case 'variants':
|
|
23
25
|
return evaluateVariants(expression);
|
|
@@ -50,8 +52,8 @@ export function price(pricingInput, order) {
|
|
|
50
52
|
return value;
|
|
51
53
|
}
|
|
52
54
|
function variantPrice(variant) {
|
|
53
|
-
const
|
|
54
|
-
return check.is(NumberSchema,
|
|
55
|
+
const price = Object.values(variant.details ?? {}).find((detail) => detail.kind === 'price');
|
|
56
|
+
return check.is(NumberSchema, price?.value) ? price?.value : null;
|
|
55
57
|
}
|
|
56
58
|
function evaluateLookup(expression, variant) {
|
|
57
59
|
const keys = resolveKey(expression.key, variant);
|
|
@@ -75,9 +77,9 @@ export function price(pricingInput, order) {
|
|
|
75
77
|
function resolveKey(key, variant) {
|
|
76
78
|
switch (key.kind) {
|
|
77
79
|
case 'variantTags':
|
|
78
|
-
return variant
|
|
80
|
+
return variant.tags ?? [];
|
|
79
81
|
case 'option': {
|
|
80
|
-
const value = variant
|
|
82
|
+
const value = variant.instance[key.name];
|
|
81
83
|
return value == null ? [] : [String(value)];
|
|
82
84
|
}
|
|
83
85
|
}
|
|
@@ -14,6 +14,7 @@ export type BuilderRenderOption = Readonly<{
|
|
|
14
14
|
option: BuilderOptionConfigSerialised;
|
|
15
15
|
displayName?: string;
|
|
16
16
|
kind?: string;
|
|
17
|
+
placeholderLabel?: string;
|
|
17
18
|
metadata?: BuilderRenderMetadata;
|
|
18
19
|
}>;
|
|
19
20
|
export type BuilderRenderOptions = ReadonlyArray<BuilderRenderOption>;
|
|
@@ -20,6 +20,7 @@ export function renderOption(input, path, builder, model, instance, references)
|
|
|
20
20
|
update: (updateInstance, updateValue) => createInstance(builder, writePath(updateInstance, fullPath, updateValue), references),
|
|
21
21
|
displayName: input.displayName && composeString(input.displayName, references),
|
|
22
22
|
kind: input.kind && composeString(input.kind, references),
|
|
23
|
+
placeholderLabel: input.placeholderLabel && composeString(input.placeholderLabel, references),
|
|
23
24
|
metadata: input.metadata && composeMetadata(input.metadata, references)
|
|
24
25
|
};
|
|
25
26
|
}
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export { createVariants, optionGraph, variantsFor } from './variants.js';
|
|
1
|
+
export { createVariants } from './variants.js';
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export { createVariants, optionGraph, variantsFor } from './variants.js';
|
|
1
|
+
export { createVariants } from './variants.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BuilderModelValidated, BuilderOptionValidated
|
|
1
|
+
import type { BuilderModelValidated, BuilderOptionValidated } from '../../entities/index';
|
|
2
2
|
import type { BuilderInstances } from '../../instance';
|
|
3
3
|
export type GraphKeys = ReadonlySet<string>;
|
|
4
4
|
export type GraphPath = {
|
|
@@ -8,7 +8,6 @@ export type GraphPath = {
|
|
|
8
8
|
};
|
|
9
9
|
export type GraphPaths = ReadonlyArray<GraphPath>;
|
|
10
10
|
export declare function crossProduct(left: BuilderInstances, right: BuilderInstances): BuilderInstances;
|
|
11
|
-
export declare function dependencyKeys(payload: unknown, paths?: BuilderPaths): ReadonlyArray<string>;
|
|
12
11
|
export declare class BuilderOptionGraph {
|
|
13
12
|
#private;
|
|
14
13
|
readonly paths: GraphPaths;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BuilderPathSchema, BuilderWhenMatchSchema, BuilderWhenUnlessSchema } from '../../entities/index.js';
|
|
2
1
|
import { check } from '../../errors/index.js';
|
|
2
|
+
import { dependencyKeys } from '../dependencies.js';
|
|
3
3
|
import { resolveOption } from '../resolve.js';
|
|
4
4
|
export function crossProduct(left, right) {
|
|
5
5
|
return left.flatMap((leftModel) => right.flatMap((rightModel) => {
|
|
@@ -11,20 +11,6 @@ export function crossProduct(left, right) {
|
|
|
11
11
|
return [{ ...leftModel, ...rightModel }];
|
|
12
12
|
}));
|
|
13
13
|
}
|
|
14
|
-
export function dependencyKeys(payload, paths = []) {
|
|
15
|
-
const keys = new Set(paths.map(([first]) => String(first)));
|
|
16
|
-
if (check.is(BuilderWhenMatchSchema, payload)) {
|
|
17
|
-
check.assert(BuilderPathSchema, payload.matchPath);
|
|
18
|
-
const [firstMatchSegment] = payload.matchPath;
|
|
19
|
-
keys.add(String(firstMatchSegment));
|
|
20
|
-
}
|
|
21
|
-
else if (check.is(BuilderWhenUnlessSchema, payload)) {
|
|
22
|
-
check.assert(BuilderPathSchema, payload.unlessPath);
|
|
23
|
-
const [firstUnlessSegment] = payload.unlessPath;
|
|
24
|
-
keys.add(String(firstUnlessSegment));
|
|
25
|
-
}
|
|
26
|
-
return Array.from(keys);
|
|
27
|
-
}
|
|
28
14
|
export class BuilderOptionGraph {
|
|
29
15
|
paths;
|
|
30
16
|
constructor(paths = []) {
|
|
@@ -86,10 +72,10 @@ export class BuilderOptionGraph {
|
|
|
86
72
|
if (values.type === 'select') {
|
|
87
73
|
return [...values.options];
|
|
88
74
|
}
|
|
89
|
-
if (values.
|
|
75
|
+
if (values.kind === 'boolean') {
|
|
90
76
|
return values.isOptional ? [true, false, null] : [true, false];
|
|
91
77
|
}
|
|
92
|
-
if (values.
|
|
78
|
+
if (values.kind === 'string') {
|
|
93
79
|
return values.isOptional ? [name, null] : [name];
|
|
94
80
|
}
|
|
95
81
|
return values.isOptional ? [1, null] : [1];
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { BuilderVariants
|
|
3
|
-
|
|
4
|
-
export declare function createVariants(entity: BuilderValidated | BuilderModelValidated): BuilderVariants;
|
|
5
|
-
export declare function optionGraph(model: BuilderModelValidated): BuilderOptionGraph;
|
|
6
|
-
export declare function variantsFor(entity: BuilderComponentValidated | BuilderCollectionValidated, options: BuilderOptionGraph): BuilderInstances;
|
|
1
|
+
import type { BuilderModelValidated, BuilderReferences, BuilderValidated } from '../../entities/index';
|
|
2
|
+
import type { BuilderVariants } from '../../instance';
|
|
3
|
+
export declare function createVariants(entity: BuilderValidated | BuilderModelValidated, references?: BuilderReferences): BuilderVariants;
|
|
@@ -1,34 +1,57 @@
|
|
|
1
1
|
import { BuilderModelSerialisedSchema, BuilderSerialisedSchema, modelsMerge } from '../../entities/index.js';
|
|
2
2
|
import { check } from '../../errors/index.js';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
3
|
+
import { dependencies, dependencyKeys } from '../dependencies.js';
|
|
4
|
+
import { resolveCollection, resolveComponent } from '../resolve.js';
|
|
5
|
+
import { BuilderOptionGraph, crossProduct } from './option-graph.js';
|
|
6
|
+
export function createVariants(entity, references = []) {
|
|
6
7
|
const model = check.is(BuilderSerialisedSchema, entity) ? entity.model : entity;
|
|
7
|
-
return buildVariants(model);
|
|
8
|
+
return buildVariants(model, references);
|
|
8
9
|
}
|
|
9
|
-
function buildVariants(model) {
|
|
10
|
+
function buildVariants(model, references) {
|
|
10
11
|
const merged = modelsMerge(model);
|
|
11
12
|
const options = optionGraph(merged);
|
|
12
13
|
const nestedVariants = merged.collections.flatMap((entry) => variantsFor(entry, options).flatMap((instance) => {
|
|
13
|
-
const resolved = resolveCollection(entry, merged, instance);
|
|
14
|
+
const resolved = resolveCollection(entry, merged, instance, references);
|
|
14
15
|
if (resolved == null) {
|
|
15
16
|
return [];
|
|
16
17
|
}
|
|
17
18
|
check.assert(BuilderModelSerialisedSchema, resolved.model);
|
|
18
|
-
return [buildVariants(resolved.model)];
|
|
19
|
+
return [buildVariants(resolved.model, references)];
|
|
19
20
|
}));
|
|
20
21
|
return {
|
|
21
22
|
...nestedVariants.reduce((accumulated, component) => ({ ...accumulated, ...component }), {}),
|
|
22
23
|
...Object.fromEntries(merged.components.map((component) => [
|
|
23
24
|
component.name,
|
|
24
|
-
|
|
25
|
+
componentVariants(component, merged, options, references)
|
|
25
26
|
]))
|
|
26
27
|
};
|
|
27
28
|
}
|
|
28
|
-
|
|
29
|
-
return
|
|
29
|
+
function componentVariants(component, model, options, references) {
|
|
30
|
+
return variantsFor(component, options).map((instance) => {
|
|
31
|
+
const resolved = resolveComponent(component, model, instance, references);
|
|
32
|
+
const declarations = resolved?.details ?? [];
|
|
33
|
+
const details = Object.fromEntries(declarations.map((declaration) => {
|
|
34
|
+
const { name, kind } = declaration;
|
|
35
|
+
return [name, { kind, value: null }];
|
|
36
|
+
}));
|
|
37
|
+
if (Object.keys(details).length === 0) {
|
|
38
|
+
return { instance };
|
|
39
|
+
}
|
|
40
|
+
return { instance, details };
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
function optionGraph(model) {
|
|
44
|
+
const names = dependencies(model);
|
|
45
|
+
let graph = new BuilderOptionGraph();
|
|
46
|
+
names.forEach((name) => {
|
|
47
|
+
const option = model.options.find((entry) => entry.name === name);
|
|
48
|
+
if (option != null) {
|
|
49
|
+
graph = graph.add(option, model);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
return graph;
|
|
30
53
|
}
|
|
31
|
-
|
|
54
|
+
function variantsFor(entity, options) {
|
|
32
55
|
const keys = new Set(dependencyKeys(entity.payload, entity.paths));
|
|
33
56
|
const graphPaths = Array.from(keys)
|
|
34
57
|
.map((key) => options.get(key))
|
package/dist/primitive.d.ts
CHANGED
|
@@ -4,7 +4,10 @@ export declare const NumberSchema: v.NumberSchema<undefined>;
|
|
|
4
4
|
export declare const BooleanSchema: v.BooleanSchema<undefined>;
|
|
5
5
|
export declare const NameSchema: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
|
|
6
6
|
export declare const IdSchema: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
|
|
7
|
+
export declare const UrlSchema: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.UrlAction<string, undefined>]>;
|
|
7
8
|
export declare const BuilderPrimitiveSchema: v.NullableSchema<v.UnionSchema<[v.StringSchema<undefined>, v.BooleanSchema<undefined>, v.NumberSchema<undefined>], undefined>, undefined>;
|
|
8
9
|
export type BuilderPrimitive = v.InferOutput<typeof BuilderPrimitiveSchema>;
|
|
9
10
|
export declare const BuilderPrimitivesSchema: v.SchemaWithPipe<readonly [v.ArraySchema<v.NullableSchema<v.UnionSchema<[v.StringSchema<undefined>, v.BooleanSchema<undefined>, v.NumberSchema<undefined>], undefined>, undefined>, undefined>, v.ReadonlyAction<(string | number | boolean | null)[]>]>;
|
|
10
11
|
export type BuilderPrimitives = v.InferOutput<typeof BuilderPrimitivesSchema>;
|
|
12
|
+
export declare const BuilderPrimitivesNonEmptySchema: v.SchemaWithPipe<readonly [v.TupleWithRestSchema<[v.NullableSchema<v.UnionSchema<[v.StringSchema<undefined>, v.BooleanSchema<undefined>, v.NumberSchema<undefined>], undefined>, undefined>], v.NullableSchema<v.UnionSchema<[v.StringSchema<undefined>, v.BooleanSchema<undefined>, v.NumberSchema<undefined>], undefined>, undefined>, undefined>, v.ReadonlyAction<[string | number | boolean | null, ...(string | number | boolean | null)[]]>]>;
|
|
13
|
+
export type BuilderPrimitivesNonEmpty = v.InferOutput<typeof BuilderPrimitivesNonEmptySchema>;
|
package/dist/primitive.js
CHANGED
|
@@ -4,5 +4,7 @@ export const NumberSchema = v.number();
|
|
|
4
4
|
export const BooleanSchema = v.boolean();
|
|
5
5
|
export const NameSchema = v.pipe(StringSchema, v.minLength(1));
|
|
6
6
|
export const IdSchema = v.pipe(StringSchema, v.minLength(1));
|
|
7
|
+
export const UrlSchema = v.pipe(StringSchema, v.url());
|
|
7
8
|
export const BuilderPrimitiveSchema = v.nullable(v.union([StringSchema, BooleanSchema, NumberSchema]));
|
|
8
9
|
export const BuilderPrimitivesSchema = v.pipe(v.array(BuilderPrimitiveSchema), v.readonly());
|
|
10
|
+
export const BuilderPrimitivesNonEmptySchema = v.pipe(v.tupleWithRest([BuilderPrimitiveSchema], BuilderPrimitiveSchema), v.readonly());
|
package/dist/public.d.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
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,
|
|
2
|
+
export type { Builder, BuilderBindings, BuilderBindingsSerialised, BuilderCollection, BuilderCollectionConfig, BuilderCollectionConfigSerialised, BuilderCollections, BuilderCollectionSerialised, BuilderCollectionsSerialised, BuilderCollectionWhen, BuilderCollectionWhenSerialised, BuilderComponent, BuilderComponentConfig, BuilderComponentConfigSerialised, BuilderComponentDetail, BuilderComponentDetailKind, BuilderComponentDetails, BuilderComponentDetailSerialised, BuilderComponentDetailsSerialised, 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, BuilderToggleKind, 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
3
|
export type { BuilderEnvironment } from './environment';
|
|
4
|
-
export type {
|
|
5
|
-
export type {
|
|
6
|
-
export type { BuilderComponentVariant, BuilderComponentVariants, BuilderInstance, BuilderInstanceInput, BuilderInstances, BuilderVariants } from './instance';
|
|
4
|
+
export type { BuilderIssue, BuilderIssueLocation, BuilderIssues } from './errors/index';
|
|
5
|
+
export type { BuilderIssueKind } from './errors/index.js';
|
|
6
|
+
export type { BuilderComponentVariant, BuilderComponentVariants, BuilderInstance, BuilderInstanceInput, BuilderInstances, BuilderVariantDetail, BuilderVariants } from './instance';
|
|
7
7
|
export type { BuilderOrder, BuilderRenderCollection, BuilderRenderCollectionAddRemove, BuilderRenderCollections, BuilderRenderMetadata, BuilderRenderOption, BuilderRenderOptions, BuilderRenderOptionUpdate, BuilderRenderPage, BuilderRenderPages, BuilderRenderResult } from './mappers/index';
|
|
8
8
|
export type { BuilderPrimitive, BuilderPrimitives } from './primitive';
|
|
9
9
|
export type { BuilderParameter, BuilderParameterSerialised, BuilderRef, Paramable, ParamableSerialised } from './references';
|
|
10
10
|
export type { BuilderInstanceValidationResult, BuilderModelValidationResult, BuilderPricingValidationResult, BuilderUIValidationResult, BuilderValidationResult, BuilderVariantsValidationOptions, BuilderVariantsValidationResult } from './validate/index';
|
|
11
11
|
export { bb } from './bb.js';
|
|
12
|
-
export { builder, detailBoolean, detailNumber, detailString, input, model, pricing, select, serialise, toggleBoolean, toggleNumber, toggleString } from './entities/index.js';
|
|
12
|
+
export { builder, detailBoolean, detailImage, detailNumber, detailPrice, detailString, input, model, pricing, select, serialise, toggleBoolean, toggleNumber, toggleString } from './entities/index.js';
|
|
13
13
|
export { BuilderException } from './errors/index.js';
|
|
14
14
|
export { ordinal } from './mappers/index.js';
|
|
15
15
|
export { parameter, ref } from './references.js';
|
|
@@ -17,12 +17,12 @@ import { collectionConfig, collectionExpectation, componentConfig, componentExpe
|
|
|
17
17
|
export declare const collection: typeof collectionConfig & {
|
|
18
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
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").
|
|
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").BuilderPrimitivesNonEmpty, values: Values) => import("./public").BuilderUnlessConfig<Values, UnlessPath>;
|
|
21
21
|
};
|
|
22
22
|
export declare const component: typeof componentConfig & {
|
|
23
23
|
enable: <const Payload extends import("./references").Paramable<import("./public").BuilderComponentConfig>>(payload?: Payload) => import("./public").BuilderEnableConfig<Payload>;
|
|
24
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").
|
|
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").BuilderPrimitivesNonEmpty, payload?: Payload) => import("./public").BuilderUnlessConfig<Payload, UnlessPath>;
|
|
26
26
|
};
|
|
27
27
|
export declare const has: {
|
|
28
28
|
collection: typeof collectionExpectation;
|
|
@@ -32,6 +32,6 @@ export declare const has: {
|
|
|
32
32
|
export declare const option: {
|
|
33
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
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").
|
|
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").BuilderPrimitivesNonEmpty, values: Values) => import("./public").BuilderUnlessConfig<Values, UnlessPath>;
|
|
36
36
|
};
|
|
37
37
|
export declare const ui: typeof uis;
|
package/dist/public.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { bb } from './bb.js';
|
|
2
|
-
export { builder, detailBoolean, detailNumber, detailString, input, model, pricing, select, serialise, toggleBoolean, toggleNumber, toggleString } from './entities/index.js';
|
|
2
|
+
export { builder, detailBoolean, detailImage, detailNumber, detailPrice, detailString, input, model, pricing, select, serialise, toggleBoolean, toggleNumber, toggleString } from './entities/index.js';
|
|
3
3
|
export { BuilderException } from './errors/index.js';
|
|
4
4
|
export { ordinal } from './mappers/index.js';
|
|
5
5
|
export { parameter, ref } from './references.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { BuilderReferences, BuilderValidated, ValidationResult } from '../entities/index';
|
|
2
|
-
import {
|
|
2
|
+
import { BuilderIssuesScope } from '../errors/index.js';
|
|
3
3
|
export type BuilderValidationResult = ValidationResult<BuilderValidated>;
|
|
4
|
-
export declare function validateBuilder(input: unknown, references?: BuilderReferences,
|
|
4
|
+
export declare function validateBuilder(input: unknown, references?: BuilderReferences, issues?: BuilderIssuesScope): BuilderValidationResult;
|
package/dist/validate/builder.js
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
import { builder, BuilderSerialisedSchema, modelsMerge, serialise } from '../entities/index.js';
|
|
2
|
-
import {
|
|
2
|
+
import { BuilderIssuesScope, 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 = [],
|
|
9
|
+
export function validateBuilder(input, references = [], issues = new BuilderIssuesScope(input)) {
|
|
10
10
|
if (!check.is(BuilderSerialisedSchema, input)) {
|
|
11
|
-
|
|
12
|
-
return [EMPTY_BUILDER, errors.
|
|
11
|
+
issues.entityInvalid('builder');
|
|
12
|
+
return [EMPTY_BUILDER, issues.errors, issues.warnings];
|
|
13
13
|
}
|
|
14
|
-
const resolve = resolver(
|
|
15
|
-
const validatedModel =
|
|
14
|
+
const resolve = resolver(issues, references, input.bindings);
|
|
15
|
+
const validatedModel = issues.scope('model', () => validateModelStructure(input.model, resolve, issues));
|
|
16
16
|
const mergedModel = modelsMerge(validatedModel);
|
|
17
|
-
|
|
18
|
-
checkModelExpectations(mergedModel, validatedModel,
|
|
17
|
+
issues.scope('model', () => {
|
|
18
|
+
checkModelExpectations(mergedModel, validatedModel, issues);
|
|
19
19
|
});
|
|
20
|
-
const validatedUI =
|
|
21
|
-
const validated = validateUIStructure(input.ui, resolve,
|
|
22
|
-
checkUIExpectations(mergedModel, validated,
|
|
20
|
+
const validatedUI = issues.scope('ui', () => {
|
|
21
|
+
const validated = validateUIStructure(input.ui, resolve, issues);
|
|
22
|
+
checkUIExpectations(mergedModel, validated, issues);
|
|
23
23
|
return validated;
|
|
24
24
|
});
|
|
25
|
-
const validatedPricing =
|
|
26
|
-
const validated = validatePricingStructure(input.pricing, resolve,
|
|
27
|
-
checkPricingExpectations(mergedModel, validated,
|
|
25
|
+
const validatedPricing = issues.scope('pricing', () => {
|
|
26
|
+
const validated = validatePricingStructure(input.pricing, resolve, issues);
|
|
27
|
+
checkPricingExpectations(mergedModel, validated, issues);
|
|
28
28
|
return validated;
|
|
29
29
|
});
|
|
30
30
|
const data = validate({
|
|
@@ -33,5 +33,5 @@ export function validateBuilder(input, references = [], errors = new BuilderErro
|
|
|
33
33
|
ui: validate(validatedUI),
|
|
34
34
|
pricing: validate(validatedPricing)
|
|
35
35
|
});
|
|
36
|
-
return [data, errors.
|
|
36
|
+
return [data, issues.errors, issues.warnings];
|
|
37
37
|
}
|
|
@@ -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,
|
|
2
|
+
import type { BuilderIssuesScope } from '../errors/index';
|
|
3
|
+
export declare function checkExpectations(model: BuilderModelSerialised, expectations: BuilderExpectationsSerialised, issues: BuilderIssuesScope): void;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
export function checkExpectations(model, expectations,
|
|
1
|
+
export function checkExpectations(model, expectations, issues) {
|
|
2
2
|
expectations.forEach(({ kind, name }, index) => {
|
|
3
|
-
|
|
3
|
+
issues.scope(index, () => {
|
|
4
4
|
if (model[`${kind}s`].some((entry) => entry.name === name)) {
|
|
5
5
|
return;
|
|
6
6
|
}
|
|
7
|
-
|
|
7
|
+
issues.modelUnmetExpectation();
|
|
8
8
|
});
|
|
9
9
|
});
|
|
10
10
|
}
|
|
@@ -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 { BuilderIssuesScope } from '../errors/index.js';
|
|
4
4
|
export type BuilderInstanceValidationResult = ValidationResult<BuilderInstanceValidated>;
|
|
5
|
-
export declare function validateInstance(model: BuilderModelValidated, instance: BuilderInstance,
|
|
5
|
+
export declare function validateInstance(model: BuilderModelValidated, instance: BuilderInstance, issues?: BuilderIssuesScope): BuilderInstanceValidationResult;
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { optionValueSchema } from '../entities/index.js';
|
|
2
|
-
import {
|
|
1
|
+
import { modelsMerge, optionValueSchema } from '../entities/index.js';
|
|
2
|
+
import { BuilderIssuesScope, 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,
|
|
7
|
-
|
|
6
|
+
export function validateInstance(model, instance, issues = new BuilderIssuesScope(instance)) {
|
|
7
|
+
issues.scope('instance', () => {
|
|
8
8
|
checkInstance(model, instance);
|
|
9
9
|
});
|
|
10
|
-
return [validate(instance), errors.
|
|
10
|
+
return [validate(instance), issues.errors, issues.warnings];
|
|
11
11
|
function checkInstance(scopeModel, scopeInstance) {
|
|
12
|
-
scopeModel
|
|
12
|
+
const merged = modelsMerge(scopeModel);
|
|
13
|
+
merged.options.forEach((option) => {
|
|
13
14
|
const { name } = option;
|
|
14
15
|
const payload = resolveOption(option, scopeModel, scopeInstance);
|
|
15
16
|
if (!payload) {
|
|
@@ -17,12 +18,12 @@ export function validateInstance(model, instance, errors = new BuilderErrorsScop
|
|
|
17
18
|
}
|
|
18
19
|
const value = scopeInstance[name];
|
|
19
20
|
if (!check.is(optionValueSchema(payload), value)) {
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
issues.scope(name, () => {
|
|
22
|
+
issues.instanceInvalidOption();
|
|
22
23
|
});
|
|
23
24
|
}
|
|
24
25
|
});
|
|
25
|
-
|
|
26
|
+
merged.collections.forEach((collection) => {
|
|
26
27
|
const { name } = collection;
|
|
27
28
|
const payload = resolveCollection(collection, scopeModel, scopeInstance);
|
|
28
29
|
if (!payload) {
|
|
@@ -30,18 +31,35 @@ export function validateInstance(model, instance, errors = new BuilderErrorsScop
|
|
|
30
31
|
}
|
|
31
32
|
const existing = scopeInstance[name];
|
|
32
33
|
if (!check.is(BuilderInstancesSchema, existing)) {
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
issues.scope(name, () => {
|
|
35
|
+
issues.instanceInvalidCollection();
|
|
35
36
|
});
|
|
36
37
|
return;
|
|
37
38
|
}
|
|
38
|
-
|
|
39
|
+
issues.scope(name, () => {
|
|
40
|
+
if (existing.length < payload.min) {
|
|
41
|
+
issues.instanceInvalidCollectionMin();
|
|
42
|
+
}
|
|
43
|
+
else if (existing.length > payload.max) {
|
|
44
|
+
issues.instanceInvalidCollectionMax();
|
|
45
|
+
}
|
|
39
46
|
existing.forEach((itemInstance, index) => {
|
|
40
|
-
|
|
47
|
+
issues.scope(index, () => {
|
|
41
48
|
checkInstance(payload.model, itemInstance);
|
|
42
49
|
});
|
|
43
50
|
});
|
|
44
51
|
});
|
|
45
52
|
});
|
|
53
|
+
const declaredNames = new Set([
|
|
54
|
+
...merged.options.map((option) => option.name),
|
|
55
|
+
...merged.collections.map((collection) => collection.name)
|
|
56
|
+
]);
|
|
57
|
+
Object.keys(scopeInstance).forEach((key) => {
|
|
58
|
+
if (!declaredNames.has(key)) {
|
|
59
|
+
issues.scope(key, () => {
|
|
60
|
+
issues.instanceUnexpectedKey();
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
});
|
|
46
64
|
}
|
|
47
65
|
}
|