@builder-builder/builder 0.0.27 → 0.0.29
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 +9 -10
- 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 +126 -45
- package/dist/client/schema.js +6 -1
- package/dist/components/BuilderOption.svelte.d.ts +12 -12
- package/dist/components/BuilderOptionValueBoolean.svelte.d.ts +20 -0
- package/dist/components/BuilderOptionValueNumber.svelte.d.ts +21 -0
- package/dist/components/BuilderOptionValueSelect.svelte.d.ts +21 -0
- package/dist/components/BuilderOptionValueString.svelte.d.ts +21 -0
- package/dist/components/BuilderRender.svelte.d.ts +2 -2
- package/dist/components/index.d.ts +8 -8
- package/dist/components/index.js +4376 -4258
- package/dist/components/index.min.js +3 -0
- package/dist/entities/collection/collection.d.ts +191 -401
- package/dist/entities/collection/collection.js +7 -4
- package/dist/entities/collection/{when.d.ts → condition.d.ts} +4 -5
- package/dist/entities/collection/condition.js +2 -0
- package/dist/entities/collection/config.d.ts +62 -80
- package/dist/entities/collection/index.d.ts +4 -4
- package/dist/entities/collection/index.js +2 -2
- package/dist/entities/component/component.d.ts +71 -83
- package/dist/entities/component/component.js +4 -4
- package/dist/entities/component/condition.d.ts +10 -0
- package/dist/entities/component/{when.js → condition.js} +3 -9
- 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 +6 -6
- package/dist/entities/component/index.js +3 -3
- package/dist/entities/{when.d.ts → condition.d.ts} +23 -36
- package/dist/entities/{when.js → condition.js} +20 -25
- package/dist/entities/expectation.d.ts +135 -3
- package/dist/entities/expectation.js +6 -2
- package/dist/entities/index.d.ts +9 -9
- package/dist/entities/index.js +4 -4
- package/dist/entities/kind.d.ts +4 -4
- package/dist/entities/kind.js +24 -25
- package/dist/entities/model/bind.d.ts +5 -5
- package/dist/entities/model/methods.d.ts +18 -27
- package/dist/entities/model/methods.js +4 -22
- package/dist/entities/model/model.d.ts +3 -1
- package/dist/entities/model/model.js +25 -27
- package/dist/entities/option/condition.d.ts +9 -0
- package/dist/entities/option/condition.js +2 -0
- package/dist/entities/option/config.d.ts +47 -72
- package/dist/entities/option/config.js +6 -6
- package/dist/entities/option/expectation.d.ts +6 -1
- package/dist/entities/option/expectation.js +2 -2
- package/dist/entities/option/index.d.ts +8 -8
- package/dist/entities/option/index.js +4 -4
- package/dist/entities/option/option.d.ts +179 -210
- package/dist/entities/option/option.js +4 -4
- package/dist/entities/option/select.d.ts +16 -43
- package/dist/entities/option/select.js +8 -31
- package/dist/entities/option/value.d.ts +73 -0
- package/dist/entities/option/value.js +99 -0
- 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 +124 -84
- package/dist/entities/serialise.d.ts +175 -109
- package/dist/entities/serialise.js +32 -27
- package/dist/entities/ui/describe.d.ts +1 -1
- package/dist/entities/ui/input.d.ts +2 -2
- package/dist/entities/ui/page.d.ts +1 -1
- package/dist/entities/ui/pages.d.ts +2 -2
- package/dist/entities/validated.d.ts +3 -3
- package/dist/environment.d.ts +2 -2
- package/dist/errors/errors.d.ts +94 -58
- package/dist/errors/errors.js +41 -7
- 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 +45 -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/price.js +6 -4
- package/dist/mappers/resolve.js +23 -22
- 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 +4 -18
- 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 +20 -20
- package/dist/public.js +17 -9
- 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 +23 -5
- 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 +57 -51
- 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 +27 -31
- 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 +4 -2
- package/dist/components/BuilderOptionSelect.svelte.d.ts +0 -21
- package/dist/components/BuilderOptionToggleBoolean.svelte.d.ts +0 -20
- package/dist/components/BuilderOptionToggleNumber.svelte.d.ts +0 -21
- package/dist/components/BuilderOptionToggleString.svelte.d.ts +0 -21
- package/dist/entities/collection/when.js +0 -2
- package/dist/entities/component/field.d.ts +0 -59
- package/dist/entities/component/field.js +0 -52
- package/dist/entities/component/when.d.ts +0 -11
- package/dist/entities/option/toggle.d.ts +0 -45
- package/dist/entities/option/toggle.js +0 -66
- package/dist/entities/option/when.d.ts +0 -10
- package/dist/entities/option/when.js +0 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { BuilderModelSerialised, BuilderPricingSerialised, BuilderPricingValidated, BuilderReferences, ValidationResult } from '../entities/index';
|
|
2
2
|
import type { BuilderResolve } from './resolve';
|
|
3
|
-
import {
|
|
3
|
+
import { BuilderIssuesScope } from '../errors/index.js';
|
|
4
4
|
export type BuilderPricingValidationResult = ValidationResult<BuilderPricingValidated>;
|
|
5
|
-
export declare function validatePricing(input: unknown, references?: BuilderReferences,
|
|
6
|
-
export declare function validatePricingStructure(input: BuilderPricingSerialised, resolve: BuilderResolve,
|
|
7
|
-
export declare function checkPricingExpectations(model: BuilderModelSerialised, pricing: BuilderPricingSerialised,
|
|
5
|
+
export declare function validatePricing(input: unknown, references?: BuilderReferences, issues?: BuilderIssuesScope): BuilderPricingValidationResult;
|
|
6
|
+
export declare function validatePricingStructure(input: BuilderPricingSerialised, resolve: BuilderResolve, issues: BuilderIssuesScope): BuilderPricingSerialised;
|
|
7
|
+
export declare function checkPricingExpectations(model: BuilderModelSerialised, pricing: BuilderPricingSerialised, issues: BuilderIssuesScope): void;
|
package/dist/validate/pricing.js
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
import { BuilderPricingExpressionSchema, BuilderPricingSerialisedSchema, BuilderRatesSchema, pricing, serialise } from '../entities/index.js';
|
|
2
|
-
import {
|
|
2
|
+
import { BuilderIssuesScope, check } from '../errors/index.js';
|
|
3
3
|
import { NumberSchema } from '../primitive.js';
|
|
4
4
|
import { validate } from './brand.js';
|
|
5
5
|
import { resolver } from './resolve.js';
|
|
6
6
|
const EMPTY_PRICING = validate(serialise.pricing(pricing()));
|
|
7
|
-
export function validatePricing(input, references = [],
|
|
7
|
+
export function validatePricing(input, references = [], issues = new BuilderIssuesScope(input)) {
|
|
8
8
|
if (!check.is(BuilderPricingSerialisedSchema, input)) {
|
|
9
|
-
|
|
10
|
-
return [EMPTY_PRICING, errors.
|
|
9
|
+
issues.entityInvalid('pricing');
|
|
10
|
+
return [EMPTY_PRICING, issues.errors, issues.warnings];
|
|
11
11
|
}
|
|
12
|
-
const resolve = resolver(
|
|
13
|
-
const structure = validatePricingStructure(input, resolve,
|
|
14
|
-
return [validate(structure), errors.
|
|
12
|
+
const resolve = resolver(issues, references);
|
|
13
|
+
const structure = validatePricingStructure(input, resolve, issues);
|
|
14
|
+
return [validate(structure), issues.errors, issues.warnings];
|
|
15
15
|
}
|
|
16
|
-
export function validatePricingStructure(input, resolve,
|
|
17
|
-
const rates =
|
|
16
|
+
export function validatePricingStructure(input, resolve, issues) {
|
|
17
|
+
const rates = issues.scope('rates', () => input.rates.flatMap((entry, index) => {
|
|
18
18
|
const resolved = resolve(entry, BuilderRatesSchema);
|
|
19
19
|
if (resolved != null) {
|
|
20
20
|
return [resolved];
|
|
21
21
|
}
|
|
22
|
-
|
|
22
|
+
issues.scope(index, () => issues.pricingInvalidRateValue());
|
|
23
23
|
return [];
|
|
24
24
|
}));
|
|
25
25
|
const formula = input.formula == null ? null : resolveExpression(input.formula);
|
|
@@ -30,7 +30,7 @@ export function validatePricingStructure(input, resolve, errors) {
|
|
|
30
30
|
function resolveExpression(input) {
|
|
31
31
|
const resolved = resolve(input, BuilderPricingExpressionSchema);
|
|
32
32
|
if (resolved == null) {
|
|
33
|
-
|
|
33
|
+
issues.pricingMalformedExpression();
|
|
34
34
|
return null;
|
|
35
35
|
}
|
|
36
36
|
if (check.is(NumberSchema, resolved)) {
|
|
@@ -40,11 +40,11 @@ export function validatePricingStructure(input, resolve, errors) {
|
|
|
40
40
|
return resolved;
|
|
41
41
|
}
|
|
42
42
|
if (resolved.kind === 'variants') {
|
|
43
|
-
const inner =
|
|
43
|
+
const inner = issues.scope('expression', () => resolveExpression(resolved.expression));
|
|
44
44
|
return { ...resolved, expression: inner ?? resolved.expression };
|
|
45
45
|
}
|
|
46
|
-
const left =
|
|
47
|
-
const right =
|
|
46
|
+
const left = issues.scope('left', () => resolveExpression(resolved.left));
|
|
47
|
+
const right = issues.scope('right', () => resolveExpression(resolved.right));
|
|
48
48
|
return { ...resolved, left: left ?? resolved.left, right: right ?? resolved.right };
|
|
49
49
|
}
|
|
50
50
|
function walkExpression(expression, insideVariants) {
|
|
@@ -54,33 +54,33 @@ export function validatePricingStructure(input, resolve, errors) {
|
|
|
54
54
|
switch (expression.kind) {
|
|
55
55
|
case 'variantPrice':
|
|
56
56
|
if (!insideVariants) {
|
|
57
|
-
|
|
57
|
+
issues.pricingInvalidScope();
|
|
58
58
|
}
|
|
59
59
|
return;
|
|
60
60
|
case 'lookup':
|
|
61
|
-
|
|
61
|
+
issues.scope('lookup', () => {
|
|
62
62
|
if (rates.length === 0) {
|
|
63
|
-
|
|
63
|
+
issues.pricingEmptyRates();
|
|
64
64
|
}
|
|
65
65
|
else {
|
|
66
66
|
const exists = rates.some((entry) => entry[expression.rate] != null);
|
|
67
67
|
if (!exists) {
|
|
68
|
-
|
|
68
|
+
issues.pricingMissingRate();
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
if (!insideVariants) {
|
|
72
|
-
|
|
72
|
+
issues.pricingInvalidScope();
|
|
73
73
|
}
|
|
74
74
|
});
|
|
75
75
|
return;
|
|
76
76
|
case 'variants':
|
|
77
|
-
|
|
77
|
+
issues.scope('variants', () => {
|
|
78
78
|
if (insideVariants) {
|
|
79
|
-
|
|
79
|
+
issues.pricingNestedVariants();
|
|
80
80
|
}
|
|
81
81
|
const inner = expression.expression;
|
|
82
82
|
check.assert(BuilderPricingExpressionSchema, inner);
|
|
83
|
-
|
|
83
|
+
issues.scope('expression', () => walkExpression(inner, true));
|
|
84
84
|
});
|
|
85
85
|
return;
|
|
86
86
|
case 'add':
|
|
@@ -91,16 +91,16 @@ export function validatePricingStructure(input, resolve, errors) {
|
|
|
91
91
|
check.assert(BuilderPricingExpressionSchema, left);
|
|
92
92
|
check.assert(BuilderPricingExpressionSchema, right);
|
|
93
93
|
if (expression.kind === 'div' && check.is(NumberSchema, right) && right === 0) {
|
|
94
|
-
|
|
94
|
+
issues.pricingDivideByZero();
|
|
95
95
|
}
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
issues.scope('left', () => walkExpression(left, insideVariants));
|
|
97
|
+
issues.scope('right', () => walkExpression(right, insideVariants));
|
|
98
98
|
return;
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
|
-
export function checkPricingExpectations(model, pricing,
|
|
103
|
+
export function checkPricingExpectations(model, pricing, issues) {
|
|
104
104
|
if (pricing.formula == null) {
|
|
105
105
|
return;
|
|
106
106
|
}
|
|
@@ -115,21 +115,21 @@ export function checkPricingExpectations(model, pricing, errors) {
|
|
|
115
115
|
}
|
|
116
116
|
switch (expression.kind) {
|
|
117
117
|
case 'lookup':
|
|
118
|
-
|
|
118
|
+
issues.scope('lookup', () => {
|
|
119
119
|
if (expression.key.kind === 'option' && !optionNames.has(expression.key.name)) {
|
|
120
|
-
|
|
120
|
+
issues.pricingMissingOption();
|
|
121
121
|
}
|
|
122
122
|
});
|
|
123
123
|
return;
|
|
124
124
|
case 'variants':
|
|
125
|
-
|
|
125
|
+
issues.scope('variants', () => issues.scope('expression', () => walkExpression(expression.expression)));
|
|
126
126
|
return;
|
|
127
127
|
case 'add':
|
|
128
128
|
case 'sub':
|
|
129
129
|
case 'mul':
|
|
130
130
|
case 'div':
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
issues.scope('left', () => walkExpression(expression.left));
|
|
132
|
+
issues.scope('right', () => walkExpression(expression.right));
|
|
133
133
|
return;
|
|
134
134
|
default:
|
|
135
135
|
return;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BuilderBindings, BuilderReferences } from '../entities/index';
|
|
2
|
-
import type {
|
|
2
|
+
import type { BuilderIssuesScope } from '../errors/index';
|
|
3
3
|
import * as v from 'valibot';
|
|
4
4
|
export type BuilderResolve = <S extends v.GenericSchema = v.GenericSchema<unknown>>(value: unknown, schema?: S) => v.InferOutput<S> | null;
|
|
5
|
-
export declare function resolver(
|
|
5
|
+
export declare function resolver(issues: BuilderIssuesScope, references?: BuilderReferences, bindings?: BuilderBindings): BuilderResolve;
|
package/dist/validate/resolve.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import * as v from 'valibot';
|
|
2
|
-
import { BuilderCollectionConfigSerialisedSchema, BuilderModelSerialisedSchema, BuilderPathSchema,
|
|
2
|
+
import { BuilderCollectionConfigSerialisedSchema, BuilderModelSerialisedSchema, BuilderPathSchema, BuilderConditionSerialisedSchema } from '../entities/index.js';
|
|
3
3
|
import { check } from '../errors/index.js';
|
|
4
4
|
import { NumberSchema, StringSchema } from '../primitive.js';
|
|
5
5
|
import { BuilderParameterSerialisedSchema, BuilderRefSerialisedSchema } from '../references.js';
|
|
6
6
|
import { validateModelStructure } from './model.js';
|
|
7
|
-
export function resolver(
|
|
7
|
+
export function resolver(issues, references = [], bindings = {}) {
|
|
8
8
|
const resolving = new Set();
|
|
9
9
|
function resolve(value, schema = v.unknown()) {
|
|
10
|
-
const errorsBefore =
|
|
10
|
+
const errorsBefore = issues.errors.length;
|
|
11
11
|
const resolved = dispatch(value, schema);
|
|
12
12
|
if (check.is(schema, resolved)) {
|
|
13
13
|
return resolved;
|
|
14
14
|
}
|
|
15
|
-
if (
|
|
16
|
-
|
|
15
|
+
if (issues.errors.length === errorsBefore) {
|
|
16
|
+
issues.referenceInvalid();
|
|
17
17
|
}
|
|
18
18
|
return null;
|
|
19
19
|
}
|
|
@@ -24,8 +24,8 @@ export function resolver(errors, references = [], bindings = {}) {
|
|
|
24
24
|
if (check.is(BuilderRefSerialisedSchema, value)) {
|
|
25
25
|
return resolveReference(value, schema);
|
|
26
26
|
}
|
|
27
|
-
if (check.is(
|
|
28
|
-
return
|
|
27
|
+
if (check.is(BuilderConditionSerialisedSchema, value)) {
|
|
28
|
+
return resolveCondition(value, schema);
|
|
29
29
|
}
|
|
30
30
|
if (check.is(BuilderCollectionConfigSerialisedSchema, value)) {
|
|
31
31
|
return resolveCollectionConfig(value);
|
|
@@ -34,12 +34,12 @@ export function resolver(errors, references = [], bindings = {}) {
|
|
|
34
34
|
}
|
|
35
35
|
function resolveReference(reference, schema) {
|
|
36
36
|
if (resolving.has(reference.id)) {
|
|
37
|
-
|
|
37
|
+
issues.referenceCircular();
|
|
38
38
|
return reference;
|
|
39
39
|
}
|
|
40
40
|
const found = references.find((entry) => entry.id === reference.id);
|
|
41
41
|
if (found == null) {
|
|
42
|
-
|
|
42
|
+
issues.referenceMissing();
|
|
43
43
|
return reference;
|
|
44
44
|
}
|
|
45
45
|
resolving.add(reference.id);
|
|
@@ -52,7 +52,7 @@ export function resolver(errors, references = [], bindings = {}) {
|
|
|
52
52
|
}
|
|
53
53
|
function resolveParameter(parameter, schema) {
|
|
54
54
|
if (!(parameter.name in bindings)) {
|
|
55
|
-
|
|
55
|
+
issues.referenceUnboundParameter();
|
|
56
56
|
return null;
|
|
57
57
|
}
|
|
58
58
|
const binding = bindings[parameter.name];
|
|
@@ -61,45 +61,41 @@ export function resolver(errors, references = [], bindings = {}) {
|
|
|
61
61
|
}
|
|
62
62
|
return resolveReference(binding, schema);
|
|
63
63
|
}
|
|
64
|
-
function
|
|
65
|
-
if (
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
if (when.type === 'unless') {
|
|
70
|
-
const unlessPath = errors.scope('unlessPath', () => resolve(when.unlessPath, BuilderPathSchema));
|
|
71
|
-
const payload = errors.scope('payload', () => resolve(when.payload, payloadSchema));
|
|
64
|
+
function resolveCondition(condition, payloadSchema) {
|
|
65
|
+
if (condition.type === 'unless') {
|
|
66
|
+
const unlessPath = issues.scope('unlessPath', () => resolve(condition.unlessPath, BuilderPathSchema));
|
|
67
|
+
const payload = issues.scope('payload', () => resolve(condition.payload, payloadSchema));
|
|
72
68
|
return {
|
|
73
|
-
...
|
|
74
|
-
unlessPath: unlessPath ??
|
|
75
|
-
payload: payload ??
|
|
69
|
+
...condition,
|
|
70
|
+
unlessPath: unlessPath ?? condition.unlessPath,
|
|
71
|
+
payload: payload ?? condition.payload
|
|
76
72
|
};
|
|
77
73
|
}
|
|
78
|
-
const matchPath =
|
|
74
|
+
const matchPath = issues.scope('matchPath', () => resolve(condition.matchPath, BuilderPathSchema));
|
|
79
75
|
const selectMapSchema = v.record(StringSchema, v.nullable(v.unknown()));
|
|
80
|
-
const map =
|
|
76
|
+
const map = issues.scope('selectMap', () => resolve(condition.selectMap, selectMapSchema));
|
|
81
77
|
if (map == null) {
|
|
82
|
-
return { ...
|
|
78
|
+
return { ...condition, matchPath: matchPath ?? condition.matchPath };
|
|
83
79
|
}
|
|
84
|
-
const selectMap =
|
|
80
|
+
const selectMap = issues.scope('selectMap', () => Object.entries(map).reduce((values, [key, entryValue]) => {
|
|
85
81
|
if (entryValue == null) {
|
|
86
82
|
return { ...values, [key]: null };
|
|
87
83
|
}
|
|
88
|
-
const resolved =
|
|
84
|
+
const resolved = issues.scope(key, () => resolve(entryValue, payloadSchema));
|
|
89
85
|
return { ...values, [key]: resolved ?? entryValue };
|
|
90
86
|
}, {}));
|
|
91
|
-
return { ...
|
|
87
|
+
return { ...condition, matchPath: matchPath ?? condition.matchPath, selectMap };
|
|
92
88
|
}
|
|
93
89
|
function resolveCollectionConfig(config) {
|
|
94
|
-
const model =
|
|
90
|
+
const model = issues.scope('model', () => {
|
|
95
91
|
const resolved = resolve(config.model, BuilderModelSerialisedSchema);
|
|
96
92
|
if (resolved == null) {
|
|
97
93
|
return null;
|
|
98
94
|
}
|
|
99
|
-
return validateModelStructure(resolved, resolve,
|
|
95
|
+
return validateModelStructure(resolved, resolve, issues);
|
|
100
96
|
});
|
|
101
|
-
const min =
|
|
102
|
-
const max =
|
|
97
|
+
const min = issues.scope('min', () => resolve(config.min, NumberSchema));
|
|
98
|
+
const max = issues.scope('max', () => resolve(config.max, NumberSchema));
|
|
103
99
|
return {
|
|
104
100
|
...config,
|
|
105
101
|
model: model ?? config.model,
|
package/dist/validate/ui.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { BuilderModelSerialised, BuilderReferences, BuilderUISerialised, BuilderUIValidated, ValidationResult } from '../entities/index';
|
|
2
2
|
import type { BuilderResolve } from './resolve';
|
|
3
|
-
import {
|
|
3
|
+
import { BuilderIssuesScope } from '../errors/index.js';
|
|
4
4
|
export type BuilderUIValidationResult = ValidationResult<BuilderUIValidated>;
|
|
5
|
-
export declare function validateUI(input: unknown, references?: BuilderReferences,
|
|
6
|
-
export declare function validateUIStructure(ui: BuilderUISerialised, resolve: BuilderResolve,
|
|
7
|
-
export declare function checkUIExpectations(mergedModel: BuilderModelSerialised, ui: BuilderUIValidated,
|
|
5
|
+
export declare function validateUI(input: unknown, references?: BuilderReferences, issues?: BuilderIssuesScope): BuilderUIValidationResult;
|
|
6
|
+
export declare function validateUIStructure(ui: BuilderUISerialised, resolve: BuilderResolve, issues: BuilderIssuesScope): BuilderUIValidated;
|
|
7
|
+
export declare function checkUIExpectations(mergedModel: BuilderModelSerialised, ui: BuilderUIValidated, issues: BuilderIssuesScope): void;
|
package/dist/validate/ui.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import { BuilderModelSerialisedSchema, BuilderPathSchema, BuilderUIInputMetadataSchema, BuilderUIInputSerialisedSchema, BuilderUIInputsSerialisedSchema, BuilderUIItemSerialisedSchema, BuilderUIItemsSerialisedSchema, BuilderUISerialisedSchema, modelsMerge, serialise, uis, validateUIDescribe, validateUIInput, validateUIPage, validateUIPages } from '../entities/index.js';
|
|
2
|
-
import {
|
|
2
|
+
import { BuilderIssuesScope, check } from '../errors/index.js';
|
|
3
3
|
import { resolveCollections } from '../mappers/index.js';
|
|
4
4
|
import { StringSchema } from '../primitive.js';
|
|
5
5
|
import { validate } from './brand.js';
|
|
6
6
|
import { checkExpectations } from './expectations.js';
|
|
7
7
|
import { checkPath } from './paths.js';
|
|
8
8
|
import { resolver } from './resolve.js';
|
|
9
|
-
export function validateUI(input, references = [],
|
|
9
|
+
export function validateUI(input, references = [], issues = new BuilderIssuesScope(input)) {
|
|
10
10
|
if (!check.is(BuilderUISerialisedSchema, input)) {
|
|
11
|
-
|
|
12
|
-
return [validate(serialise.ui(uis())), errors.
|
|
11
|
+
issues.entityInvalid('ui');
|
|
12
|
+
return [validate(serialise.ui(uis())), issues.errors, issues.warnings];
|
|
13
13
|
}
|
|
14
|
-
const resolve = resolver(
|
|
15
|
-
const structure = validateUIStructure(input, resolve,
|
|
16
|
-
return [validate(structure), errors.
|
|
14
|
+
const resolve = resolver(issues, references);
|
|
15
|
+
const structure = validateUIStructure(input, resolve, issues);
|
|
16
|
+
return [validate(structure), issues.errors, issues.warnings];
|
|
17
17
|
}
|
|
18
|
-
export function validateUIStructure(ui, resolve,
|
|
18
|
+
export function validateUIStructure(ui, resolve, issues) {
|
|
19
19
|
const childUIs = walkChildUIs();
|
|
20
|
-
const items =
|
|
20
|
+
const items = issues.scope('items', () => walkItems(ui.items));
|
|
21
21
|
const data = {
|
|
22
22
|
...ui,
|
|
23
23
|
uis: childUIs,
|
|
@@ -25,40 +25,40 @@ export function validateUIStructure(ui, resolve, errors) {
|
|
|
25
25
|
};
|
|
26
26
|
return data;
|
|
27
27
|
function walkChildUIs() {
|
|
28
|
-
return
|
|
28
|
+
return issues.scope('uis', () => ui.uis.flatMap((part, partIndex) => issues.scope(partIndex, () => {
|
|
29
29
|
const resolved = resolve(part, BuilderUISerialisedSchema);
|
|
30
30
|
if (resolved == null) {
|
|
31
31
|
return [];
|
|
32
32
|
}
|
|
33
|
-
return [validateUIStructure(resolved, resolve,
|
|
33
|
+
return [validateUIStructure(resolved, resolve, issues)];
|
|
34
34
|
})));
|
|
35
35
|
}
|
|
36
36
|
function walkItems(parts) {
|
|
37
|
-
return parts.map((item, itemIndex) =>
|
|
37
|
+
return parts.map((item, itemIndex) => issues.scope(itemIndex, () => {
|
|
38
38
|
const resolved = resolve(item, BuilderUIItemSerialisedSchema);
|
|
39
39
|
return walkUIItem((resolved ?? item));
|
|
40
40
|
}));
|
|
41
41
|
}
|
|
42
42
|
function walkUIItem(item) {
|
|
43
43
|
if (item.type === 'page') {
|
|
44
|
-
validateUIPage(item, [],
|
|
44
|
+
validateUIPage(item, [], issues);
|
|
45
45
|
}
|
|
46
46
|
else if (item.type === 'pages') {
|
|
47
|
-
validateUIPages(item, [],
|
|
47
|
+
validateUIPages(item, [], issues);
|
|
48
48
|
}
|
|
49
49
|
else if (item.type === 'describe') {
|
|
50
|
-
validateUIDescribe(item, [],
|
|
50
|
+
validateUIDescribe(item, [], issues);
|
|
51
51
|
}
|
|
52
|
-
const label =
|
|
52
|
+
const label = issues.scope('label', () => resolve(item.label, StringSchema) ?? item.label);
|
|
53
53
|
if (item.type === 'pages') {
|
|
54
|
-
const innerItems =
|
|
54
|
+
const innerItems = issues.scope('items', () => {
|
|
55
55
|
const resolved = resolve(item.items, BuilderUIItemsSerialisedSchema);
|
|
56
56
|
const resolvedItems = (Array.isArray(resolved) ? resolved : item.items);
|
|
57
57
|
return walkItems(resolvedItems);
|
|
58
58
|
});
|
|
59
59
|
return { ...item, label, items: innerItems };
|
|
60
60
|
}
|
|
61
|
-
const inputs =
|
|
61
|
+
const inputs = issues.scope('inputs', () => {
|
|
62
62
|
const resolved = resolve(item.inputs, BuilderUIInputsSerialisedSchema);
|
|
63
63
|
if (!Array.isArray(resolved)) {
|
|
64
64
|
return resolved ?? item.inputs;
|
|
@@ -68,18 +68,18 @@ export function validateUIStructure(ui, resolve, errors) {
|
|
|
68
68
|
return { ...item, label, inputs };
|
|
69
69
|
}
|
|
70
70
|
function walkInputs(inputs) {
|
|
71
|
-
return inputs.map((entry, entryIndex) =>
|
|
71
|
+
return inputs.map((entry, entryIndex) => issues.scope(entryIndex, () => {
|
|
72
72
|
const resolvedEntry = resolve(entry, BuilderUIInputSerialisedSchema);
|
|
73
73
|
return walkInput((resolvedEntry ?? entry));
|
|
74
74
|
}));
|
|
75
75
|
}
|
|
76
76
|
function walkInput(value) {
|
|
77
|
-
validateUIInput(value, [],
|
|
78
|
-
const path =
|
|
77
|
+
validateUIInput(value, [], issues);
|
|
78
|
+
const path = issues.scope('path', () => resolve(value.path, BuilderPathSchema) ?? value.path);
|
|
79
79
|
const displayName = value.displayName &&
|
|
80
|
-
|
|
81
|
-
const kind = value.kind &&
|
|
82
|
-
const metadata = value.metadata &&
|
|
80
|
+
issues.scope('displayName', () => resolve(value.displayName, StringSchema) ?? value.displayName);
|
|
81
|
+
const kind = value.kind && issues.scope('kind', () => resolve(value.kind, StringSchema) ?? value.kind);
|
|
82
|
+
const metadata = value.metadata && issues.scope('metadata', () => walkMetadata(value.metadata));
|
|
83
83
|
return { ...value, path, displayName, kind, metadata };
|
|
84
84
|
}
|
|
85
85
|
function walkMetadata(rawMetadata) {
|
|
@@ -88,28 +88,28 @@ export function validateUIStructure(ui, resolve, errors) {
|
|
|
88
88
|
return rawMetadata;
|
|
89
89
|
}
|
|
90
90
|
return Object.entries(resolved).reduce((entries, [key, entryValue]) => {
|
|
91
|
-
const resolvedValue =
|
|
91
|
+
const resolvedValue = issues.scope(key, () => resolve(entryValue));
|
|
92
92
|
return { ...entries, [key]: resolvedValue ?? entryValue };
|
|
93
93
|
}, {});
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
|
-
export function checkUIExpectations(mergedModel, ui,
|
|
96
|
+
export function checkUIExpectations(mergedModel, ui, issues) {
|
|
97
97
|
const expectedOptionNames = collectExpectedOptionNames(ui);
|
|
98
|
-
|
|
99
|
-
checkExpectations(mergedModel, ui.expectations,
|
|
98
|
+
issues.scope('expectations', () => {
|
|
99
|
+
checkExpectations(mergedModel, ui.expectations, issues);
|
|
100
100
|
});
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
issues.scope('items', () => walkItems(mergedModel, ui.items));
|
|
102
|
+
issues.scope('uis', () => {
|
|
103
103
|
ui.uis.forEach((nested, nestedIndex) => {
|
|
104
|
-
|
|
105
|
-
checkUIExpectations(mergedModel, nested,
|
|
104
|
+
issues.scope(nestedIndex, () => {
|
|
105
|
+
checkUIExpectations(mergedModel, nested, issues);
|
|
106
106
|
});
|
|
107
107
|
});
|
|
108
108
|
});
|
|
109
109
|
function walkItems(model, items) {
|
|
110
110
|
items.forEach((entry, itemIndex) => {
|
|
111
111
|
const item = entry;
|
|
112
|
-
|
|
112
|
+
issues.scope(itemIndex, () => {
|
|
113
113
|
if (item.type === 'pages') {
|
|
114
114
|
walkPages(model, item);
|
|
115
115
|
return;
|
|
@@ -118,8 +118,8 @@ export function checkUIExpectations(mergedModel, ui, errors) {
|
|
|
118
118
|
if (!Array.isArray(inputs)) {
|
|
119
119
|
return;
|
|
120
120
|
}
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
issues.scope('inputs', () => inputs.forEach((input, entryIndex) => {
|
|
122
|
+
issues.scope(entryIndex, () => walkInput(model, input));
|
|
123
123
|
}));
|
|
124
124
|
});
|
|
125
125
|
});
|
|
@@ -132,7 +132,7 @@ export function checkUIExpectations(mergedModel, ui, errors) {
|
|
|
132
132
|
const innerModels = resolveCollections(collection).flatMap(({ model: configModel }) => check.is(BuilderModelSerialisedSchema, configModel) ? [configModel] : []);
|
|
133
133
|
innerModels.forEach((innerModel) => {
|
|
134
134
|
const mergedInnerModel = modelsMerge(innerModel);
|
|
135
|
-
|
|
135
|
+
issues.scope('items', () => walkItems(mergedInnerModel, pages.items));
|
|
136
136
|
});
|
|
137
137
|
}
|
|
138
138
|
function walkInput(model, input) {
|
|
@@ -144,8 +144,8 @@ export function checkUIExpectations(mergedModel, ui, errors) {
|
|
|
144
144
|
if (typeof leaf === 'string' && expectedOptionNames.has(leaf)) {
|
|
145
145
|
return;
|
|
146
146
|
}
|
|
147
|
-
|
|
148
|
-
checkPath(model, path,
|
|
147
|
+
issues.scope('path', () => {
|
|
148
|
+
checkPath(model, path, issues);
|
|
149
149
|
});
|
|
150
150
|
}
|
|
151
151
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { BuilderModelValidated, BuilderVariantsValidated, ValidationResult } from '../entities/index';
|
|
2
|
-
import {
|
|
1
|
+
import type { BuilderModelValidated, BuilderReferences, BuilderVariantsValidated, ValidationResult } from '../entities/index';
|
|
2
|
+
import { BuilderIssuesScope } from '../errors/index.js';
|
|
3
3
|
export type BuilderVariantsValidationOptions = {
|
|
4
4
|
readonly partial?: boolean;
|
|
5
5
|
};
|
|
6
6
|
export type BuilderVariantsValidationResult = ValidationResult<BuilderVariantsValidated>;
|
|
7
|
-
export declare function validateVariants(model: BuilderModelValidated, input: unknown, options?: BuilderVariantsValidationOptions,
|
|
7
|
+
export declare function validateVariants(model: BuilderModelValidated, input: unknown, options?: BuilderVariantsValidationOptions, references?: BuilderReferences, issues?: BuilderIssuesScope): BuilderVariantsValidationResult;
|
|
@@ -1,46 +1,46 @@
|
|
|
1
1
|
import { BuilderComponentConfigSerialisedSchema, detailValueSchema } from '../entities/index.js';
|
|
2
|
-
import {
|
|
2
|
+
import { BuilderIssuesScope, check } from '../errors/index.js';
|
|
3
3
|
import { BuilderVariantsSchema } from '../instance.js';
|
|
4
4
|
import { createVariants } from '../mappers/index.js';
|
|
5
5
|
import { validate } from './brand.js';
|
|
6
|
-
export function validateVariants(model, input, options = {},
|
|
6
|
+
export function validateVariants(model, input, options = {}, references = [], issues = new BuilderIssuesScope(input)) {
|
|
7
7
|
if (!check.is(BuilderVariantsSchema, input)) {
|
|
8
|
-
|
|
9
|
-
return [validate({}), errors.
|
|
8
|
+
issues.variantsInvalid();
|
|
9
|
+
return [validate({}), issues.errors, issues.warnings];
|
|
10
10
|
}
|
|
11
11
|
const variants = input;
|
|
12
|
-
const expected = createVariants(model);
|
|
12
|
+
const expected = createVariants(model, references);
|
|
13
13
|
if (Object.keys(expected).length === 0) {
|
|
14
|
-
|
|
15
|
-
return [validate({}), errors.
|
|
14
|
+
issues.modelEmptyComponents();
|
|
15
|
+
return [validate({}), issues.errors, issues.warnings];
|
|
16
16
|
}
|
|
17
|
-
|
|
17
|
+
issues.scope('variants', () => {
|
|
18
18
|
checkVariants();
|
|
19
19
|
checkComponents();
|
|
20
20
|
checkDetails();
|
|
21
21
|
function checkVariants() {
|
|
22
22
|
Object.entries(expected).forEach(([component, expectedVariants]) => {
|
|
23
23
|
const componentVariants = variants[component];
|
|
24
|
-
|
|
24
|
+
issues.scope(component, () => {
|
|
25
25
|
if (componentVariants == null) {
|
|
26
26
|
if (options.partial !== false) {
|
|
27
|
-
|
|
27
|
+
issues.variantsMissingComponent();
|
|
28
28
|
}
|
|
29
29
|
return;
|
|
30
30
|
}
|
|
31
31
|
const expectedKeys = new Map(expectedVariants.map(({ instance }) => [sortedKey(instance), instance]));
|
|
32
32
|
const actualKeys = new Set(componentVariants.map(({ instance }) => sortedKey(instance)));
|
|
33
33
|
componentVariants.forEach((variant, index) => {
|
|
34
|
-
|
|
34
|
+
issues.scope(index, () => {
|
|
35
35
|
const { instance } = variant;
|
|
36
36
|
if (!expectedKeys.has(sortedKey(instance))) {
|
|
37
|
-
|
|
37
|
+
issues.variantsInvalidVariant();
|
|
38
38
|
}
|
|
39
39
|
});
|
|
40
40
|
});
|
|
41
41
|
Array.from(expectedKeys).forEach(([key, instance]) => {
|
|
42
42
|
if (!actualKeys.has(key)) {
|
|
43
|
-
|
|
43
|
+
issues.variantsMissingVariant(instance);
|
|
44
44
|
}
|
|
45
45
|
});
|
|
46
46
|
});
|
|
@@ -48,9 +48,9 @@ export function validateVariants(model, input, options = {}, errors = new Builde
|
|
|
48
48
|
}
|
|
49
49
|
function checkComponents() {
|
|
50
50
|
Object.keys(variants).forEach((component) => {
|
|
51
|
-
|
|
51
|
+
issues.scope(component, () => {
|
|
52
52
|
if (expected[component] == null) {
|
|
53
|
-
|
|
53
|
+
issues.variantsUnexpectedComponent();
|
|
54
54
|
}
|
|
55
55
|
});
|
|
56
56
|
});
|
|
@@ -58,32 +58,33 @@ export function validateVariants(model, input, options = {}, errors = new Builde
|
|
|
58
58
|
function checkDetails() {
|
|
59
59
|
const componentByName = new Map(model.components.map((entry) => [entry.name, entry]));
|
|
60
60
|
Object.entries(variants).forEach(([component, componentVariants]) => {
|
|
61
|
-
|
|
61
|
+
issues.scope(component, () => {
|
|
62
62
|
const entry = componentByName.get(component);
|
|
63
63
|
if (entry == null) {
|
|
64
64
|
return;
|
|
65
65
|
}
|
|
66
66
|
componentVariants.forEach(({ instance, details = {} }, index) => {
|
|
67
|
-
|
|
67
|
+
issues.scope(index, () => {
|
|
68
68
|
const resolved = variantDetails(entry, instance);
|
|
69
|
-
const
|
|
70
|
-
const expectedNames = new Set(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
69
|
+
const expected = resolved?.details ?? [];
|
|
70
|
+
const expectedNames = new Set(expected.map(({ name }) => name));
|
|
71
|
+
issues.scope('details', () => {
|
|
72
|
+
expected.forEach(({ name, kind, isOptional }) => {
|
|
73
|
+
issues.scope(name, () => {
|
|
74
|
+
const detail = details[name];
|
|
75
|
+
if (detail == null) {
|
|
76
|
+
issues.variantsMissingDetail();
|
|
76
77
|
return;
|
|
77
78
|
}
|
|
78
|
-
if (!check.is(detailValueSchema(
|
|
79
|
-
|
|
79
|
+
if (!check.is(detailValueSchema(kind, isOptional), detail.value)) {
|
|
80
|
+
issues.variantsInvalidDetail();
|
|
80
81
|
}
|
|
81
82
|
});
|
|
82
83
|
});
|
|
83
|
-
Object.keys(details).forEach((
|
|
84
|
-
if (!expectedNames.has(
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
Object.keys(details).forEach((name) => {
|
|
85
|
+
if (!expectedNames.has(name)) {
|
|
86
|
+
issues.scope(name, () => {
|
|
87
|
+
issues.variantsUnexpectedDetail();
|
|
87
88
|
});
|
|
88
89
|
}
|
|
89
90
|
});
|
|
@@ -94,7 +95,7 @@ export function validateVariants(model, input, options = {}, errors = new Builde
|
|
|
94
95
|
});
|
|
95
96
|
}
|
|
96
97
|
});
|
|
97
|
-
return [validate(variants), errors.
|
|
98
|
+
return [validate(variants), issues.errors, issues.warnings];
|
|
98
99
|
}
|
|
99
100
|
function variantDetails(component, variantInstance) {
|
|
100
101
|
const { payload } = component;
|