@builder-builder/builder 0.0.6 → 0.0.7
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/core/builder.d.ts +6 -2
- package/dist/core/builder.js +17 -32
- package/dist/core/expectation.d.ts +2 -5
- package/dist/core/expectation.js +0 -4
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.js +1 -0
- package/dist/core/option/index.d.ts +1 -0
- package/dist/core/option/toggle.d.ts +3 -1
- package/dist/core/option/toggle.js +9 -7
- package/dist/core/validate.d.ts +26 -0
- package/dist/core/validate.js +43 -0
- package/dist/index.d.ts +6 -6
- package/dist/index.js +3 -3
- package/dist/resolve/index.d.ts +4 -3
- package/dist/resolve/index.js +2 -2
- package/dist/resolve/instance.d.ts +34 -2
- package/dist/resolve/instance.js +56 -2
- package/dist/resolve/models.d.ts +2 -2
- package/dist/resolve/models.js +11 -1
- package/dist/resolve/order.d.ts +4 -2
- package/dist/resolve/order.js +5 -2
- package/dist/resolve/render.d.ts +4 -2
- package/dist/resolve/validate.d.ts +20 -16
- package/dist/resolve/validate.js +18 -22
- package/dist/serialise/deserialise.d.ts +6 -1
- package/dist/serialise/deserialise.js +40 -34
- package/dist/serialise/index.d.ts +3 -1
- package/dist/serialise/index.js +2 -1
- package/dist/serialise/schemas.d.ts +146 -85
- package/dist/serialise/schemas.js +18 -9
- package/dist/serialise/serialise.d.ts +4 -1
- package/dist/serialise/serialise.js +16 -9
- package/dist/serialise/validate.d.ts +26 -0
- package/dist/serialise/validate.js +148 -0
- package/dist/ui.d.ts +2 -1
- package/dist/ui.js +3 -12
- package/package.json +2 -2
package/dist/core/builder.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { BuilderComponentEntries, BuilderComponentMethod } from './componen
|
|
|
4
4
|
import type { BuilderOptionEntries, BuilderOptionMethod } from './option/index';
|
|
5
5
|
import type { BuilderBindings, BuilderBoundState } from './parameter';
|
|
6
6
|
import type { BuilderExpectationEntries, BuilderExpectations, ComponentAssert, ModelAssert } from './expectation';
|
|
7
|
+
import { validateBuilder } from './validate.js';
|
|
7
8
|
import { BuilderComponentGraph } from './component/index.js';
|
|
8
9
|
import { BuilderOptionGraph } from './option/index.js';
|
|
9
10
|
export type BuilderState = {
|
|
@@ -42,7 +43,7 @@ export declare class Builder<State extends BuilderState = BuilderStateEmpty> {
|
|
|
42
43
|
readonly components: BuilderComponentEntries;
|
|
43
44
|
readonly collections: BuilderCollectionEntries;
|
|
44
45
|
readonly expectations: BuilderExpectationEntries;
|
|
45
|
-
constructor(options?: BuilderOptionEntries,
|
|
46
|
+
constructor(options?: BuilderOptionEntries, components?: BuilderComponentEntries, collections?: BuilderCollectionEntries, expectations?: BuilderExpectationEntries);
|
|
46
47
|
get optionGraph(): BuilderOptionGraph;
|
|
47
48
|
get componentGraph(): BuilderComponentGraph;
|
|
48
49
|
get option(): BuilderOptionMethod<State>;
|
|
@@ -55,7 +56,10 @@ export declare class Builder<State extends BuilderState = BuilderStateEmpty> {
|
|
|
55
56
|
}>;
|
|
56
57
|
bind<const Bindings extends BuilderBindings<State>>(bindings: Bindings): Builder<BuilderBoundState<State, Bindings>>;
|
|
57
58
|
}
|
|
58
|
-
|
|
59
|
+
declare function mergeBuilders<const BuildersToMerge extends Builders>(...buildersToMerge: BuildersToMerge): Builder<MergedPartsState<BuildersToMerge>>;
|
|
60
|
+
export declare const builder: typeof mergeBuilders & {
|
|
61
|
+
validate: typeof validateBuilder;
|
|
62
|
+
};
|
|
59
63
|
type MergedPartsState<Parts extends ReadonlyArray<BuilderGeneric>> = Parts extends readonly [
|
|
60
64
|
infer Head extends BuilderGeneric,
|
|
61
65
|
...infer Tail extends ReadonlyArray<BuilderGeneric>
|
package/dist/core/builder.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as v from 'valibot';
|
|
2
|
-
import { BuilderExpectation } from './expectation.js';
|
|
3
2
|
import { check } from '../check.js';
|
|
3
|
+
import { validateBuilder } from './validate.js';
|
|
4
4
|
import { BuilderCollection, resolveCollectionNames } from './collection/index.js';
|
|
5
5
|
import { BuilderComponent, BuilderComponentGraph } from './component/index.js';
|
|
6
6
|
import { BuilderOption, BuilderOptionGraph } from './option/index.js';
|
|
@@ -12,10 +12,10 @@ export class Builder {
|
|
|
12
12
|
expectations;
|
|
13
13
|
#optionGraph = null;
|
|
14
14
|
#componentGraph = null;
|
|
15
|
-
constructor(options = [],
|
|
15
|
+
constructor(options = [], components = [], collections = [], expectations = []) {
|
|
16
16
|
this.options = options;
|
|
17
|
-
this.collections = collections;
|
|
18
17
|
this.components = components;
|
|
18
|
+
this.collections = collections;
|
|
19
19
|
this.expectations = expectations;
|
|
20
20
|
}
|
|
21
21
|
get optionGraph() {
|
|
@@ -39,16 +39,16 @@ export class Builder {
|
|
|
39
39
|
const addOption = (name, values) => {
|
|
40
40
|
check.falsy(existingNames.has(name), `Duplicate option name '${name}'! ❌`);
|
|
41
41
|
const entry = new BuilderOption(name, values);
|
|
42
|
-
return this.#next([...this.options, entry], this.
|
|
42
|
+
return this.#next([...this.options, entry], this.components, this.collections);
|
|
43
43
|
};
|
|
44
44
|
const addConditionalOption = (gatePaths, name, config) => {
|
|
45
45
|
check.falsy(existingNames.has(name), `Duplicate option name '${name}'! ❌`);
|
|
46
46
|
if (v.is(v.instance(BuilderParameter), config)) {
|
|
47
47
|
const entry = new BuilderOption(name, config, gatePaths, null);
|
|
48
|
-
return this.#next([...this.options, entry], this.
|
|
48
|
+
return this.#next([...this.options, entry], this.components, this.collections);
|
|
49
49
|
}
|
|
50
50
|
const entry = new BuilderOption(name, extractValues(config), gatePaths, config);
|
|
51
|
-
return this.#next([...this.options, entry], this.
|
|
51
|
+
return this.#next([...this.options, entry], this.components, this.collections);
|
|
52
52
|
};
|
|
53
53
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- bridges loose implementation to strict overloaded type
|
|
54
54
|
return Object.assign(addOption, { when: addConditionalOption });
|
|
@@ -58,12 +58,12 @@ export class Builder {
|
|
|
58
58
|
const addComponent = (name, paths) => {
|
|
59
59
|
check.falsy(existingNames.has(name), `Duplicate component name '${name}'! ❌`);
|
|
60
60
|
const entry = new BuilderComponent(name, paths);
|
|
61
|
-
return this.#next(this.options,
|
|
61
|
+
return this.#next(this.options, [...this.components, entry], this.collections);
|
|
62
62
|
};
|
|
63
63
|
const addConditionalComponent = (dependencies, name, paths) => {
|
|
64
64
|
check.falsy(existingNames.has(name), `Duplicate component name '${name}'! ❌`);
|
|
65
65
|
const entry = new BuilderComponent(name, paths, dependencies);
|
|
66
|
-
return this.#next(this.options,
|
|
66
|
+
return this.#next(this.options, [...this.components, entry], this.collections);
|
|
67
67
|
};
|
|
68
68
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- bridges loose implementation to strict overloaded type
|
|
69
69
|
return Object.assign(addComponent, { when: addConditionalComponent });
|
|
@@ -74,7 +74,7 @@ export class Builder {
|
|
|
74
74
|
check.falsy(existing.has(name), `Duplicate collection name '${name}'! ❌`);
|
|
75
75
|
check.assert(v.instance(Builder), collectionRecipe);
|
|
76
76
|
const entry = new BuilderCollection(name, collectionRecipe, min, max);
|
|
77
|
-
return this.#next(this.options, [...this.collections, entry]
|
|
77
|
+
return this.#next(this.options, this.components, [...this.collections, entry]);
|
|
78
78
|
};
|
|
79
79
|
const addConditionalCollection = (gatePaths, name, config) => {
|
|
80
80
|
const existing = resolveCollectionNames(this.collections);
|
|
@@ -83,13 +83,13 @@ export class Builder {
|
|
|
83
83
|
? Object.values(config.selectMap).find((value) => value !== null)
|
|
84
84
|
: config;
|
|
85
85
|
const entry = new BuilderCollection(name, defaultEntry.builder, defaultEntry.min, defaultEntry.max, gatePaths, config);
|
|
86
|
-
return this.#next(this.options, [...this.collections, entry]
|
|
86
|
+
return this.#next(this.options, this.components, [...this.collections, entry]);
|
|
87
87
|
};
|
|
88
88
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- bridges loose implementation to strict overloaded type
|
|
89
89
|
return Object.assign(addCollection, { when: addConditionalCollection });
|
|
90
90
|
}
|
|
91
91
|
expect(...expectations) {
|
|
92
|
-
return new Builder(this.options, this.
|
|
92
|
+
return new Builder(this.options, this.components, this.collections, [
|
|
93
93
|
...this.expectations,
|
|
94
94
|
...expectations
|
|
95
95
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- type narrowing cast, validated at merge time
|
|
@@ -97,28 +97,13 @@ export class Builder {
|
|
|
97
97
|
}
|
|
98
98
|
bind(bindings) {
|
|
99
99
|
const boundOptions = bindOptions(this.options, bindings);
|
|
100
|
-
return new Builder(boundOptions, this.
|
|
100
|
+
return new Builder(boundOptions, this.components, this.collections, this.expectations);
|
|
101
101
|
}
|
|
102
|
-
#next(options,
|
|
103
|
-
return new Builder(options,
|
|
102
|
+
#next(options, components, collections) {
|
|
103
|
+
return new Builder(options, components, collections, this.expectations);
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
buildersToMerge
|
|
109
|
-
.flatMap((builder) => builder.expectations)
|
|
110
|
-
.forEach((expectation) => {
|
|
111
|
-
if (v.is(v.instance(BuilderExpectation), expectation)) {
|
|
112
|
-
if (expectation.kind === 'option') {
|
|
113
|
-
expectation.validate(merged.options);
|
|
114
|
-
}
|
|
115
|
-
else if (expectation.kind === 'component') {
|
|
116
|
-
expectation.validate(merged.components);
|
|
117
|
-
}
|
|
118
|
-
else if (expectation.kind === 'collection') {
|
|
119
|
-
expectation.validate(merged.collections);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
});
|
|
123
|
-
return merged;
|
|
106
|
+
function mergeBuilders(...buildersToMerge) {
|
|
107
|
+
return new Builder(buildersToMerge.flatMap((builder) => builder.options), buildersToMerge.flatMap((builder) => builder.components), buildersToMerge.flatMap((builder) => builder.collections), buildersToMerge.flatMap((builder) => builder.expectations));
|
|
124
108
|
}
|
|
109
|
+
export const builder = Object.assign(mergeBuilders, { validate: validateBuilder });
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { BuilderGeneric, BuilderMerge, BuilderStateOf } from './builder';
|
|
2
1
|
import type { Prettify } from '../prettify';
|
|
2
|
+
import type { BuilderGeneric, BuilderMerge, BuilderStateOf } from './builder';
|
|
3
3
|
import { BuilderCollection } from './collection/index.js';
|
|
4
4
|
import { BuilderComponent } from './component/index.js';
|
|
5
5
|
export type BuilderExpectationKind = 'option' | 'component' | 'collection';
|
|
@@ -21,9 +21,6 @@ export declare class BuilderExpectation<Name extends string = string, Value = un
|
|
|
21
21
|
readonly kind: Kind;
|
|
22
22
|
constructor(name: Name, kind: Kind);
|
|
23
23
|
optional(): BuilderExpectation<Name, Value | null, Kind>;
|
|
24
|
-
validate(entries: ReadonlyArray<{
|
|
25
|
-
readonly name: string;
|
|
26
|
-
}>): void;
|
|
27
24
|
}
|
|
28
25
|
export declare const has: {
|
|
29
26
|
option: <const Name extends string>(name: Name) => BuilderExpectation<Name, string, "option">;
|
|
@@ -33,7 +30,7 @@ export declare const has: {
|
|
|
33
30
|
type ExpectedModel<Items extends ReadonlyArray<BuilderExpectation>> = Items extends readonly [
|
|
34
31
|
infer Head,
|
|
35
32
|
...infer Tail extends ReadonlyArray<BuilderExpectation>
|
|
36
|
-
] ? (Head extends BuilderExpectation<infer Name, infer Value, 'option'> ? Record<Name, Value> : unknown) & ExpectedModel<Tail> : unknown;
|
|
33
|
+
] ? (Head extends BuilderExpectation<infer Name, infer Value, 'option'> ? Record<Name, Value> : Head extends BuilderExpectation<infer Name, any, 'collection'> ? Record<Name, ReadonlyArray<unknown>> : unknown) & ExpectedModel<Tail> : unknown;
|
|
37
34
|
type ExpectedComponents<Items extends ReadonlyArray<BuilderExpectation>> = Items extends readonly [
|
|
38
35
|
infer Head,
|
|
39
36
|
...infer Tail extends ReadonlyArray<BuilderExpectation>
|
package/dist/core/expectation.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { BuilderCollection } from './collection/index.js';
|
|
2
2
|
import { BuilderComponent } from './component/index.js';
|
|
3
|
-
import { check } from '../check.js';
|
|
4
3
|
export class BuilderExpectation {
|
|
5
4
|
name;
|
|
6
5
|
kind;
|
|
@@ -11,9 +10,6 @@ export class BuilderExpectation {
|
|
|
11
10
|
optional() {
|
|
12
11
|
return new BuilderExpectation(this.name, this.kind);
|
|
13
12
|
}
|
|
14
|
-
validate(entries) {
|
|
15
|
-
check.truthy(entries.some((entry) => entry.name === this.name), `assert: no \`${this.kind}\` named '${this.name}' exists in the builder config! ❌`);
|
|
16
|
-
}
|
|
17
13
|
}
|
|
18
14
|
export const has = {
|
|
19
15
|
option: (name) => new BuilderExpectation(name, 'option'),
|
package/dist/core/index.d.ts
CHANGED
|
@@ -4,9 +4,11 @@ export type { BuilderExpectationEntries, BuilderExpectations, BuilderModelAssert
|
|
|
4
4
|
export type { BuilderOptionEnableConfig, BuilderOptionEntries, BuilderOptionMatchConfig, BuilderOptionMethod, BuilderOptionUnlessConfig, BuilderOptionValues, BuilderOptionValuesMap, BuilderOptionWhenConfig, BuilderSelectTypeLabels, BuilderSelectTypeValues } from './option/index';
|
|
5
5
|
export type { BuilderWhenEnableConfig, BuilderWhenMatchConfig, BuilderWhenUnlessConfig } from './when/index';
|
|
6
6
|
export type { BuilderMerge, BuilderGeneric, BuilderModelOf, Builders, BuilderState, BuilderStateEmpty, BuilderStateOf } from './builder';
|
|
7
|
+
export type { BuilderValidated, BuilderValidateError, BuilderValidateErrors, BuilderValidateErrorUnboundParameter, BuilderValidateErrorUnmetExpectation, BuilderValidateOptions, BuilderValidateResult } from './validate';
|
|
7
8
|
export { Builder, builder } from './builder.js';
|
|
8
9
|
export { BuilderCollection, collection, resolveCollectionModels, resolveCollectionNames } from './collection/index.js';
|
|
9
10
|
export { BuilderComponent, BuilderComponentGraph } from './component/index.js';
|
|
10
11
|
export { BuilderExpectation, has } from './expectation.js';
|
|
11
12
|
export { BuilderOption, BuilderOptionGraph, select, BuilderSelectType, BuilderToggleType, toggleBoolean, toggleNumber, toggleString, enable, match, unless } from './option/index.js';
|
|
12
13
|
export { BuilderParameter, BuilderParameterSchema } from './parameter.js';
|
|
14
|
+
export { BuilderValidateException } from './validate.js';
|
package/dist/core/index.js
CHANGED
|
@@ -4,3 +4,4 @@ export { BuilderComponent, BuilderComponentGraph } from './component/index.js';
|
|
|
4
4
|
export { BuilderExpectation, has } from './expectation.js';
|
|
5
5
|
export { BuilderOption, BuilderOptionGraph, select, BuilderSelectType, BuilderToggleType, toggleBoolean, toggleNumber, toggleString, enable, match, unless } from './option/index.js';
|
|
6
6
|
export { BuilderParameter, BuilderParameterSchema } from './parameter.js';
|
|
7
|
+
export { BuilderValidateException } from './validate.js';
|
|
@@ -2,6 +2,7 @@ export type { BuilderOptionEnableConfig, BuilderOptionMatchConfig, BuilderOption
|
|
|
2
2
|
export type { BuilderOptionGraphs } from './graph';
|
|
3
3
|
export type { BuilderOptionEntries, BuilderOptionValues, BuilderOptionValuesMap, BuilderSelectTypeGeneric, BuilderToggleTypeGeneric, BuilderOptionValueSchema } from './option';
|
|
4
4
|
export type { BuilderSelectTypeLabels, BuilderSelectTypeValues } from './select';
|
|
5
|
+
export type { BuilderToggleValueType } from './toggle';
|
|
5
6
|
export { enable, match, unless } from './method.js';
|
|
6
7
|
export { BuilderOptionGraph } from './graph.js';
|
|
7
8
|
export { BuilderOption } from './option.js';
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type { BuilderOptionValueSchema } from './option';
|
|
2
2
|
import * as v from 'valibot';
|
|
3
|
+
export type BuilderToggleValueType = 'string' | 'boolean' | 'number';
|
|
3
4
|
export declare class BuilderToggleType<const ValueSchema extends BuilderOptionValueSchema = BuilderOptionValueSchema> {
|
|
4
5
|
readonly value: v.InferOutput<ValueSchema>;
|
|
6
|
+
readonly valueType: BuilderToggleValueType;
|
|
5
7
|
readonly valueSchema: ValueSchema;
|
|
6
8
|
readonly defaultValue: v.InferOutput<ValueSchema>;
|
|
7
9
|
readonly isOptional: boolean;
|
|
8
|
-
constructor(valueSchema: ValueSchema, defaultValue: v.InferOutput<ValueSchema>, optional?: boolean);
|
|
10
|
+
constructor(valueType: BuilderToggleValueType, valueSchema: ValueSchema, defaultValue: v.InferOutput<ValueSchema>, optional?: boolean);
|
|
9
11
|
default(newDefault: v.InferOutput<ValueSchema>): BuilderToggleType<ValueSchema>;
|
|
10
12
|
optional(): BuilderToggleType<v.NullableSchema<ValueSchema, undefined>>;
|
|
11
13
|
}
|
|
@@ -1,27 +1,29 @@
|
|
|
1
1
|
import * as v from 'valibot';
|
|
2
2
|
export class BuilderToggleType {
|
|
3
|
+
valueType;
|
|
3
4
|
valueSchema;
|
|
4
5
|
defaultValue;
|
|
5
6
|
isOptional;
|
|
6
|
-
constructor(valueSchema, defaultValue, optional) {
|
|
7
|
+
constructor(valueType, valueSchema, defaultValue, optional) {
|
|
8
|
+
this.valueType = valueType;
|
|
7
9
|
this.valueSchema = valueSchema;
|
|
8
10
|
this.defaultValue = defaultValue;
|
|
9
11
|
this.isOptional = optional || false;
|
|
10
12
|
}
|
|
11
13
|
default(newDefault) {
|
|
12
|
-
return new BuilderToggleType(this.valueSchema, newDefault, this.isOptional);
|
|
14
|
+
return new BuilderToggleType(this.valueType, this.valueSchema, newDefault, this.isOptional);
|
|
13
15
|
}
|
|
14
16
|
optional() {
|
|
15
|
-
const { valueSchema, defaultValue } = this;
|
|
16
|
-
return new BuilderToggleType(v.nullable(valueSchema), defaultValue, true);
|
|
17
|
+
const { valueType, valueSchema, defaultValue } = this;
|
|
18
|
+
return new BuilderToggleType(valueType, v.nullable(valueSchema), defaultValue, true);
|
|
17
19
|
}
|
|
18
20
|
}
|
|
19
21
|
export function toggleString() {
|
|
20
|
-
return new BuilderToggleType(v.string(), '');
|
|
22
|
+
return new BuilderToggleType('string', v.string(), '');
|
|
21
23
|
}
|
|
22
24
|
export function toggleBoolean() {
|
|
23
|
-
return new BuilderToggleType(v.boolean(), false);
|
|
25
|
+
return new BuilderToggleType('boolean', v.boolean(), false);
|
|
24
26
|
}
|
|
25
27
|
export function toggleNumber() {
|
|
26
|
-
return new BuilderToggleType(v.number(), 0);
|
|
28
|
+
return new BuilderToggleType('number', v.number(), 0);
|
|
27
29
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { BuilderGeneric } from './builder';
|
|
2
|
+
declare const validated: unique symbol;
|
|
3
|
+
export type BuilderValidated = BuilderGeneric & {
|
|
4
|
+
readonly [validated]: true;
|
|
5
|
+
};
|
|
6
|
+
export type BuilderValidateErrorUnmetExpectation = {
|
|
7
|
+
readonly kind: 'unmet-expectation';
|
|
8
|
+
readonly expectationKind: 'option' | 'component' | 'collection';
|
|
9
|
+
readonly name: string;
|
|
10
|
+
};
|
|
11
|
+
export type BuilderValidateErrorUnboundParameter = {
|
|
12
|
+
readonly kind: 'unbound-parameter';
|
|
13
|
+
readonly name: string;
|
|
14
|
+
};
|
|
15
|
+
export type BuilderValidateError = BuilderValidateErrorUnmetExpectation | BuilderValidateErrorUnboundParameter;
|
|
16
|
+
export type BuilderValidateErrors = ReadonlyArray<BuilderValidateError>;
|
|
17
|
+
export type BuilderValidateResult = readonly [BuilderValidated, BuilderValidateErrors];
|
|
18
|
+
export type BuilderValidateOptions = {
|
|
19
|
+
readonly strict: true;
|
|
20
|
+
};
|
|
21
|
+
export declare class BuilderValidateException extends Error {
|
|
22
|
+
readonly errors: BuilderValidateErrors;
|
|
23
|
+
constructor(errors: BuilderValidateErrors);
|
|
24
|
+
}
|
|
25
|
+
export declare function validateBuilder(builder: BuilderGeneric, options?: BuilderValidateOptions): BuilderValidateResult;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as v from 'valibot';
|
|
2
|
+
import { BuilderParameterSchema } from './parameter.js';
|
|
3
|
+
export class BuilderValidateException extends Error {
|
|
4
|
+
errors;
|
|
5
|
+
constructor(errors) {
|
|
6
|
+
super('builder validation failed');
|
|
7
|
+
this.errors = errors;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export function validateBuilder(builder, options) {
|
|
11
|
+
const expectationErrors = validateExpectations(builder.expectations, builder);
|
|
12
|
+
const parameterErrors = validateParameters(builder.options);
|
|
13
|
+
const errors = [...expectationErrors, ...parameterErrors];
|
|
14
|
+
if (options?.strict && errors.length > 0) {
|
|
15
|
+
throw new BuilderValidateException(errors);
|
|
16
|
+
}
|
|
17
|
+
return [builder, errors];
|
|
18
|
+
}
|
|
19
|
+
function validateExpectations(expectations, entries) {
|
|
20
|
+
return expectations.flatMap((expectation) => {
|
|
21
|
+
const lookup = expectation.kind === 'option'
|
|
22
|
+
? entries.options
|
|
23
|
+
: expectation.kind === 'component'
|
|
24
|
+
? entries.components
|
|
25
|
+
: entries.collections;
|
|
26
|
+
const exists = lookup.some((entry) => entry.name === expectation.name);
|
|
27
|
+
if (exists) {
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
return [
|
|
31
|
+
{
|
|
32
|
+
kind: 'unmet-expectation',
|
|
33
|
+
expectationKind: expectation.kind,
|
|
34
|
+
name: expectation.name
|
|
35
|
+
}
|
|
36
|
+
];
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
function validateParameters(options) {
|
|
40
|
+
return options
|
|
41
|
+
.filter((option) => v.is(BuilderParameterSchema, option.values))
|
|
42
|
+
.map((option) => ({ kind: 'unbound-parameter', name: option.name }));
|
|
43
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
export type { BuilderData, BuilderModel, BuilderModels, BuilderPrimitive, BuilderPrimitives, BuilderVariant, BuilderVariants } from './model';
|
|
2
|
-
export type { Builder, Builders, BuilderCollectionEntries, BuilderComponentEntries, BuilderGeneric, BuilderModelOf, BuilderOptionEntries } from './core/index';
|
|
2
|
+
export type { Builder, Builders, BuilderCollectionEntries, BuilderComponentEntries, BuilderGeneric, BuilderModelOf, BuilderOptionEntries, BuilderValidated, BuilderValidateError, BuilderValidateErrors, BuilderValidateErrorUnboundParameter, BuilderValidateErrorUnmetExpectation, BuilderValidateOptions, BuilderValidateResult } from './core/index';
|
|
3
3
|
export type { BuilderModelPaths, BuilderResolvePath, BuilderValidPath } from './paths';
|
|
4
4
|
export type { BuilderPath, BuilderPaths } from './schemas/index';
|
|
5
|
-
export type { BuilderDataValidated, BuilderDescription, BuilderDescriptionItem,
|
|
5
|
+
export type { BuilderDataValidated, BuilderDataError, BuilderDataErrors, BuilderDataErrorComponentMissing, BuilderDataErrorComponentUnexpected, BuilderDataErrorVariantInvalid, BuilderDataErrorVariantMissing, BuilderDataValidateResult, BuilderDescription, BuilderDescriptionItem, BuilderModelValidated, BuilderModelValidateError, BuilderModelValidateErrors, BuilderModelValidateErrorInvalidCollection, BuilderModelValidateErrorInvalidOption, BuilderModelValidateOptions, BuilderModelValidateResult, BuilderOrder, BuilderRenderOption, BuilderRenderOptions, BuilderRenderPage, BuilderRenderPages, BuilderRenderResult } from './resolve/index';
|
|
6
6
|
export type { BuilderUICollection, BuilderUIDescribe, BuilderUIItem, BuilderUIItems, BuilderUIPage } from './schemas/index';
|
|
7
7
|
export type { BuilderUI, BuilderUIs } from './ui';
|
|
8
|
-
export type { BuilderCollectionSerialised, BuilderCollectionWhenConfigSerialised, BuilderComponentSerialised, BuilderOptionSerialised, BuilderOptionWhenConfigSerialised, BuilderParameterSerialised, BuilderSelectTypeSerialised, BuilderSerialised, BuilderToggleTypeSerialised, BuilderUISerialised, BuilderValuesSerialised } from './serialise/index';
|
|
9
|
-
export { BuilderExpectation, has } from './core/index.js';
|
|
8
|
+
export type { BuilderCollectionSerialised, BuilderCollectionWhenConfigSerialised, BuilderComponentSerialised, BuilderOptionSerialised, BuilderOptionWhenConfigSerialised, BuilderParameterSerialised, BuilderSelectTypeSerialised, BuilderSerialised, BuilderSerialisedValidated, BuilderSerialisedError, BuilderSerialisedErrors, BuilderSerialisedValidateOptions, BuilderSerialisedValidateResult, BuilderToggleTypeSerialised, BuilderUISerialised, BuilderValuesSerialised } from './serialise/index';
|
|
9
|
+
export { BuilderExpectation, BuilderValidateException, has } from './core/index.js';
|
|
10
10
|
export { builder, BuilderCollection, BuilderComponent, BuilderOption, BuilderParameter, BuilderSelectType, BuilderToggleType, collection, enable, match, select, toggleBoolean, toggleNumber, toggleString, unless } from './core/index.js';
|
|
11
|
-
export { instance, models, order, ordinal, render, validate } from './resolve/index.js';
|
|
12
|
-
export { deserialise, serialise } from './serialise/index.js';
|
|
11
|
+
export { instance, BuilderModelValidateException, models, order, ordinal, render, validate, BuilderDataValidateError } from './resolve/index.js';
|
|
12
|
+
export { BuilderSerialisedValidateError, deserialise, serialise } from './serialise/index.js';
|
|
13
13
|
export { ui } from './ui.js';
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { BuilderExpectation, has } from './core/index.js';
|
|
1
|
+
export { BuilderExpectation, BuilderValidateException, has } from './core/index.js';
|
|
2
2
|
export { builder, BuilderCollection, BuilderComponent, BuilderOption, BuilderParameter, BuilderSelectType, BuilderToggleType, collection, enable, match, select, toggleBoolean, toggleNumber, toggleString, unless } from './core/index.js';
|
|
3
|
-
export { instance, models, order, ordinal, render, validate } from './resolve/index.js';
|
|
4
|
-
export { deserialise, serialise } from './serialise/index.js';
|
|
3
|
+
export { instance, BuilderModelValidateException, models, order, ordinal, render, validate, BuilderDataValidateError } from './resolve/index.js';
|
|
4
|
+
export { BuilderSerialisedValidateError, deserialise, serialise } from './serialise/index.js';
|
|
5
5
|
export { ui } from './ui.js';
|
package/dist/resolve/index.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export type { BuilderOrder } from './order';
|
|
2
2
|
export type { BuilderRenderOption, BuilderRenderOptions, BuilderRenderPage, BuilderRenderPages, BuilderRenderResult } from './render';
|
|
3
|
-
export type { BuilderDataValidated,
|
|
3
|
+
export type { BuilderDataValidated, BuilderDataError, BuilderDataErrors, BuilderDataErrorComponentMissing, BuilderDataErrorComponentUnexpected, BuilderDataErrorVariantInvalid, BuilderDataErrorVariantMissing, BuilderDataValidateResult } from './validate';
|
|
4
|
+
export type { BuilderModelValidated, BuilderModelValidateError, BuilderModelValidateErrors, BuilderModelValidateErrorInvalidCollection, BuilderModelValidateErrorInvalidOption, BuilderModelValidateOptions, BuilderModelValidateResult } from './instance';
|
|
4
5
|
export type { BuilderDescription, BuilderDescriptionItem } from '../schemas/index';
|
|
5
|
-
export { instance } from './instance.js';
|
|
6
|
+
export { instance, BuilderModelValidateException } from './instance.js';
|
|
6
7
|
export { models } from './models.js';
|
|
7
8
|
export { order } from './order.js';
|
|
8
9
|
export { ordinal, render } from './render.js';
|
|
9
|
-
export { validate } from './validate.js';
|
|
10
|
+
export { validate, BuilderDataValidateError } from './validate.js';
|
package/dist/resolve/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { instance } from './instance.js';
|
|
1
|
+
export { instance, BuilderModelValidateException } from './instance.js';
|
|
2
2
|
export { models } from './models.js';
|
|
3
3
|
export { order } from './order.js';
|
|
4
4
|
export { ordinal, render } from './render.js';
|
|
5
|
-
export { validate } from './validate.js';
|
|
5
|
+
export { validate, BuilderDataValidateError } from './validate.js';
|
|
@@ -1,3 +1,35 @@
|
|
|
1
1
|
import type { BuilderGeneric, BuilderModelOf } from '../core/index';
|
|
2
|
-
import type { BuilderModelInput } from '../model';
|
|
3
|
-
|
|
2
|
+
import type { BuilderModel, BuilderModelInput } from '../model';
|
|
3
|
+
declare const modelValidated: unique symbol;
|
|
4
|
+
export type BuilderModelValidated = BuilderModel & {
|
|
5
|
+
readonly [modelValidated]: true;
|
|
6
|
+
};
|
|
7
|
+
export type BuilderModelValidateErrorInvalidOption = {
|
|
8
|
+
readonly kind: 'invalid-option';
|
|
9
|
+
readonly name: string;
|
|
10
|
+
readonly value: unknown;
|
|
11
|
+
};
|
|
12
|
+
export type BuilderModelValidateErrorInvalidCollection = {
|
|
13
|
+
readonly kind: 'invalid-collection';
|
|
14
|
+
readonly name: string;
|
|
15
|
+
readonly detail: string;
|
|
16
|
+
};
|
|
17
|
+
export type BuilderModelValidateError = BuilderModelValidateErrorInvalidOption | BuilderModelValidateErrorInvalidCollection;
|
|
18
|
+
export type BuilderModelValidateErrors = ReadonlyArray<BuilderModelValidateError>;
|
|
19
|
+
export type BuilderModelValidateResult = readonly [
|
|
20
|
+
BuilderModelValidated,
|
|
21
|
+
BuilderModelValidateErrors
|
|
22
|
+
];
|
|
23
|
+
export type BuilderModelValidateOptions = {
|
|
24
|
+
readonly strict: true;
|
|
25
|
+
};
|
|
26
|
+
export declare class BuilderModelValidateException extends Error {
|
|
27
|
+
readonly errors: BuilderModelValidateErrors;
|
|
28
|
+
constructor(errors: BuilderModelValidateErrors);
|
|
29
|
+
}
|
|
30
|
+
export declare function validateInstance(builder: BuilderGeneric, model: BuilderModel, options?: BuilderModelValidateOptions): BuilderModelValidateResult;
|
|
31
|
+
export declare const instance: typeof createInstance & {
|
|
32
|
+
validate: typeof validateInstance;
|
|
33
|
+
};
|
|
34
|
+
declare function createInstance<const Builder extends BuilderGeneric>(builder: Builder, partial?: BuilderModelInput): BuilderModelOf<Builder> & BuilderModelValidated;
|
|
35
|
+
export {};
|
package/dist/resolve/instance.js
CHANGED
|
@@ -1,6 +1,60 @@
|
|
|
1
1
|
import * as v from 'valibot';
|
|
2
2
|
import { resolveCollectionModels } from '../core/index.js';
|
|
3
|
-
export
|
|
3
|
+
export class BuilderModelValidateException extends Error {
|
|
4
|
+
errors;
|
|
5
|
+
constructor(errors) {
|
|
6
|
+
super('model validation failed');
|
|
7
|
+
this.errors = errors;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export function validateInstance(builder, model, options) {
|
|
11
|
+
const errors = validateModel(builder, model);
|
|
12
|
+
if (options?.strict && errors.length > 0) {
|
|
13
|
+
throw new BuilderModelValidateException(errors);
|
|
14
|
+
}
|
|
15
|
+
return [model, errors];
|
|
16
|
+
}
|
|
17
|
+
export const instance = Object.assign(createInstance, { validate: validateInstance });
|
|
18
|
+
function validateModel(builder, model) {
|
|
19
|
+
let errors = [];
|
|
20
|
+
builder.options.forEach((entry) => {
|
|
21
|
+
const option = entry.resolve(model);
|
|
22
|
+
if (!option) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const value = model[option.name];
|
|
26
|
+
if (!v.is(option.values.valueSchema, value)) {
|
|
27
|
+
errors = [...errors, { kind: 'invalid-option', name: option.name, value }];
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
builder.collections.forEach((entry) => {
|
|
31
|
+
const collection = entry.resolve(model);
|
|
32
|
+
if (!collection) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const existing = model[collection.name];
|
|
36
|
+
if (!Array.isArray(existing)) {
|
|
37
|
+
errors = [
|
|
38
|
+
...errors,
|
|
39
|
+
{ kind: 'invalid-collection', name: collection.name, detail: 'expected an array' }
|
|
40
|
+
];
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const collectionModels = resolveCollectionModels(model, collection.name);
|
|
44
|
+
collectionModels.forEach((itemModel, index) => {
|
|
45
|
+
const nestedErrors = validateModel(collection.builder, itemModel);
|
|
46
|
+
errors = [
|
|
47
|
+
...errors,
|
|
48
|
+
...nestedErrors.map((error) => ({
|
|
49
|
+
...error,
|
|
50
|
+
name: `${collection.name}[${String(index)}].${error.name}`
|
|
51
|
+
}))
|
|
52
|
+
];
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
return errors;
|
|
56
|
+
}
|
|
57
|
+
function createInstance(builder, partial = {}) {
|
|
4
58
|
const model = partial;
|
|
5
59
|
builder.options.forEach((entry) => {
|
|
6
60
|
const option = entry.resolve(model);
|
|
@@ -20,7 +74,7 @@ export function instance(builder, partial = {}) {
|
|
|
20
74
|
const collectionModels = existing != null ? resolveCollectionModels(model, collection.name) : [];
|
|
21
75
|
model[collection.name] = Array.from({
|
|
22
76
|
length: Math.max(collectionModels.length, collection.min)
|
|
23
|
-
}).map((_, index) =>
|
|
77
|
+
}).map((_, index) => createInstance(collection.builder, collectionModels[index] || {}));
|
|
24
78
|
});
|
|
25
79
|
return model;
|
|
26
80
|
}
|
package/dist/resolve/models.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { BuilderData } from '../model';
|
|
2
|
-
import type {
|
|
3
|
-
export declare function models(builder:
|
|
2
|
+
import type { BuilderValidated } from '../core/validate';
|
|
3
|
+
export declare function models(builder: BuilderValidated): BuilderData;
|
package/dist/resolve/models.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
export function models(builder) {
|
|
2
|
+
return modelsRecursive(builder);
|
|
3
|
+
}
|
|
4
|
+
function modelsRecursive(builder) {
|
|
2
5
|
const collectionModels = builder.collections.flatMap((entry) => {
|
|
3
|
-
return
|
|
6
|
+
return collectionBuilders(entry).map((collectionBuilder) => modelsRecursive(collectionBuilder));
|
|
4
7
|
});
|
|
5
8
|
const wrapped = Object.fromEntries(builder.componentGraph.paths.map((path) => [path.name, path.models.map((model) => ({ model }))]));
|
|
6
9
|
return {
|
|
@@ -8,3 +11,10 @@ export function models(builder) {
|
|
|
8
11
|
...wrapped
|
|
9
12
|
};
|
|
10
13
|
}
|
|
14
|
+
function collectionBuilders(entry) {
|
|
15
|
+
if (entry.config?.type === 'match') {
|
|
16
|
+
const selectMap = entry.config.selectMap;
|
|
17
|
+
return Object.values(selectMap).flatMap((value) => (value ? [value.builder] : []));
|
|
18
|
+
}
|
|
19
|
+
return [entry.builder];
|
|
20
|
+
}
|
package/dist/resolve/order.d.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import type { Prettify } from '../prettify';
|
|
2
|
-
import type {
|
|
2
|
+
import type { BuilderVariant } from '../model';
|
|
3
3
|
import type { CollectionShape } from '../core/collection/index';
|
|
4
4
|
import type { BuilderCollection, BuilderCollectionEntries, BuilderComponentEntries, BuilderComponentNamesOf, BuilderGeneric } from '../core/index';
|
|
5
|
+
import type { BuilderValidated } from '../core/validate';
|
|
6
|
+
import type { BuilderModelValidated } from './instance';
|
|
5
7
|
import type { BuilderDataValidated } from './validate';
|
|
6
8
|
export type BuilderOrder<Builder extends BuilderGeneric> = Builder extends {
|
|
7
9
|
readonly _components: infer Components extends BuilderComponentEntries;
|
|
8
10
|
readonly _collections: infer Collections extends BuilderCollectionEntries;
|
|
9
11
|
} ? Prettify<ComponentsOrder<Components> & CollectionsOrder<Collections>> : Record<string, unknown>;
|
|
10
|
-
export declare function order<const Builder extends BuilderGeneric>(builder: Builder, model:
|
|
12
|
+
export declare function order<const Builder extends BuilderGeneric>(builder: Builder & BuilderValidated, model: BuilderModelValidated, componentModels: BuilderDataValidated): BuilderOrder<Builder>;
|
|
11
13
|
type ComponentsOrder<Components extends BuilderComponentEntries> = {
|
|
12
14
|
readonly [Name in BuilderComponentNamesOf<Components>]: BuilderVariant | null;
|
|
13
15
|
};
|
package/dist/resolve/order.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { resolveCollectionModels } from '../core/index.js';
|
|
2
2
|
import { check } from '../check.js';
|
|
3
|
-
|
|
3
|
+
function orderInternal(builder, model, componentModels) {
|
|
4
4
|
const result = {};
|
|
5
5
|
const resolved = new Set();
|
|
6
6
|
builder.components.forEach((component) => {
|
|
@@ -18,7 +18,10 @@ export function order(builder, model, componentModels) {
|
|
|
18
18
|
return;
|
|
19
19
|
}
|
|
20
20
|
const itemModels = resolveCollectionModels(model, collection.name);
|
|
21
|
-
result[collection.name] = itemModels.map((itemModel) =>
|
|
21
|
+
result[collection.name] = itemModels.map((itemModel) => orderInternal(collection.builder, itemModel, componentModels));
|
|
22
22
|
});
|
|
23
23
|
return result;
|
|
24
24
|
}
|
|
25
|
+
export function order(builder, model, componentModels) {
|
|
26
|
+
return orderInternal(builder, model, componentModels);
|
|
27
|
+
}
|
package/dist/resolve/render.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { BuilderOption } from '../core/index';
|
|
2
|
+
import type { BuilderValidated } from '../core/validate';
|
|
2
3
|
import type { BuilderModel } from '../model';
|
|
4
|
+
import type { BuilderModelValidated } from './instance';
|
|
3
5
|
import type { BuilderDescription, BuilderUIItems, BuilderPrimitive } from '../schemas/index';
|
|
4
6
|
import { BuilderUI } from '../ui.js';
|
|
5
7
|
export type BuilderRenderOption = {
|
|
@@ -17,5 +19,5 @@ export type BuilderRenderResult = {
|
|
|
17
19
|
readonly layout: BuilderRenderPages;
|
|
18
20
|
readonly description: BuilderDescription;
|
|
19
21
|
};
|
|
20
|
-
export declare function render(rootBuilder:
|
|
22
|
+
export declare function render(rootBuilder: BuilderValidated, rootModel: BuilderModelValidated, input: BuilderUI | BuilderUIItems): BuilderRenderResult;
|
|
21
23
|
export declare function ordinal(index: number): string;
|