@builder-builder/builder 0.0.5 → 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 +20 -29
- package/dist/core/collection/collection.d.ts +3 -1
- package/dist/core/component/component.d.ts +0 -2
- package/dist/core/component/component.js +0 -7
- package/dist/core/component/graph.d.ts +0 -1
- package/dist/core/component/graph.js +5 -5
- package/dist/core/component/index.d.ts +1 -1
- package/dist/core/expectation.d.ts +22 -19
- package/dist/core/expectation.js +5 -9
- package/dist/core/index.d.ts +4 -2
- package/dist/core/index.js +2 -1
- package/dist/core/option/graph.d.ts +1 -2
- package/dist/core/option/graph.js +4 -6
- package/dist/core/option/index.d.ts +1 -0
- package/dist/core/option/option.js +5 -4
- 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 +7 -7
- package/dist/index.js +3 -3
- package/dist/paths.d.ts +3 -1
- 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 +13 -10
- 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 +153 -92
- package/dist/serialise/schemas.js +19 -10
- 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 +7 -6
- package/dist/ui.js +17 -15
- package/package.json +3 -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() {
|
|
@@ -35,17 +35,20 @@ export class Builder {
|
|
|
35
35
|
return this.#componentGraph;
|
|
36
36
|
}
|
|
37
37
|
get option() {
|
|
38
|
+
const existingNames = new Set(this.options.map((entry) => entry.name));
|
|
38
39
|
const addOption = (name, values) => {
|
|
40
|
+
check.falsy(existingNames.has(name), `Duplicate option name '${name}'! ❌`);
|
|
39
41
|
const entry = new BuilderOption(name, values);
|
|
40
|
-
return this.#next([...this.options, entry], this.
|
|
42
|
+
return this.#next([...this.options, entry], this.components, this.collections);
|
|
41
43
|
};
|
|
42
44
|
const addConditionalOption = (gatePaths, name, config) => {
|
|
45
|
+
check.falsy(existingNames.has(name), `Duplicate option name '${name}'! ❌`);
|
|
43
46
|
if (v.is(v.instance(BuilderParameter), config)) {
|
|
44
47
|
const entry = new BuilderOption(name, config, gatePaths, null);
|
|
45
|
-
return this.#next([...this.options, entry], this.
|
|
48
|
+
return this.#next([...this.options, entry], this.components, this.collections);
|
|
46
49
|
}
|
|
47
50
|
const entry = new BuilderOption(name, extractValues(config), gatePaths, config);
|
|
48
|
-
return this.#next([...this.options, entry], this.
|
|
51
|
+
return this.#next([...this.options, entry], this.components, this.collections);
|
|
49
52
|
};
|
|
50
53
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- bridges loose implementation to strict overloaded type
|
|
51
54
|
return Object.assign(addOption, { when: addConditionalOption });
|
|
@@ -55,12 +58,12 @@ export class Builder {
|
|
|
55
58
|
const addComponent = (name, paths) => {
|
|
56
59
|
check.falsy(existingNames.has(name), `Duplicate component name '${name}'! ❌`);
|
|
57
60
|
const entry = new BuilderComponent(name, paths);
|
|
58
|
-
return this.#next(this.options,
|
|
61
|
+
return this.#next(this.options, [...this.components, entry], this.collections);
|
|
59
62
|
};
|
|
60
63
|
const addConditionalComponent = (dependencies, name, paths) => {
|
|
61
64
|
check.falsy(existingNames.has(name), `Duplicate component name '${name}'! ❌`);
|
|
62
65
|
const entry = new BuilderComponent(name, paths, dependencies);
|
|
63
|
-
return this.#next(this.options,
|
|
66
|
+
return this.#next(this.options, [...this.components, entry], this.collections);
|
|
64
67
|
};
|
|
65
68
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- bridges loose implementation to strict overloaded type
|
|
66
69
|
return Object.assign(addComponent, { when: addConditionalComponent });
|
|
@@ -71,7 +74,7 @@ export class Builder {
|
|
|
71
74
|
check.falsy(existing.has(name), `Duplicate collection name '${name}'! ❌`);
|
|
72
75
|
check.assert(v.instance(Builder), collectionRecipe);
|
|
73
76
|
const entry = new BuilderCollection(name, collectionRecipe, min, max);
|
|
74
|
-
return this.#next(this.options, [...this.collections, entry]
|
|
77
|
+
return this.#next(this.options, this.components, [...this.collections, entry]);
|
|
75
78
|
};
|
|
76
79
|
const addConditionalCollection = (gatePaths, name, config) => {
|
|
77
80
|
const existing = resolveCollectionNames(this.collections);
|
|
@@ -80,13 +83,13 @@ export class Builder {
|
|
|
80
83
|
? Object.values(config.selectMap).find((value) => value !== null)
|
|
81
84
|
: config;
|
|
82
85
|
const entry = new BuilderCollection(name, defaultEntry.builder, defaultEntry.min, defaultEntry.max, gatePaths, config);
|
|
83
|
-
return this.#next(this.options, [...this.collections, entry]
|
|
86
|
+
return this.#next(this.options, this.components, [...this.collections, entry]);
|
|
84
87
|
};
|
|
85
88
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- bridges loose implementation to strict overloaded type
|
|
86
89
|
return Object.assign(addCollection, { when: addConditionalCollection });
|
|
87
90
|
}
|
|
88
91
|
expect(...expectations) {
|
|
89
|
-
return new Builder(this.options, this.
|
|
92
|
+
return new Builder(this.options, this.components, this.collections, [
|
|
90
93
|
...this.expectations,
|
|
91
94
|
...expectations
|
|
92
95
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- type narrowing cast, validated at merge time
|
|
@@ -94,25 +97,13 @@ export class Builder {
|
|
|
94
97
|
}
|
|
95
98
|
bind(bindings) {
|
|
96
99
|
const boundOptions = bindOptions(this.options, bindings);
|
|
97
|
-
return new Builder(boundOptions, this.
|
|
100
|
+
return new Builder(boundOptions, this.components, this.collections, this.expectations);
|
|
98
101
|
}
|
|
99
|
-
#next(options,
|
|
100
|
-
return new Builder(options,
|
|
102
|
+
#next(options, components, collections) {
|
|
103
|
+
return new Builder(options, components, collections, this.expectations);
|
|
101
104
|
}
|
|
102
105
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
buildersToMerge
|
|
106
|
-
.flatMap((builder) => builder.expectations)
|
|
107
|
-
.forEach((expectation) => {
|
|
108
|
-
if (v.is(v.instance(BuilderExpectation), expectation)) {
|
|
109
|
-
if (expectation.kind === 'option') {
|
|
110
|
-
expectation.validate(merged.options);
|
|
111
|
-
}
|
|
112
|
-
else if (expectation.kind === 'component') {
|
|
113
|
-
expectation.validate(merged.components);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
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));
|
|
118
108
|
}
|
|
109
|
+
export const builder = Object.assign(mergeBuilders, { validate: validateBuilder });
|
|
@@ -11,7 +11,9 @@ export type BuilderCollectionEntries = ReadonlyArray<BuilderCollection>;
|
|
|
11
11
|
export type TupleOf<Item, Length extends number, Result extends ReadonlyArray<Item> = []> = Result['length'] extends Length ? Result : TupleOf<Item, Length, [...Result, Item]>;
|
|
12
12
|
export type CollectionShape<Item, Min extends number, Max extends number> = number extends Min ? ReadonlyArray<Item> : number extends Max ? ReadonlyArray<Item> : Min extends Max ? TupleOf<Item, Min> : ReadonlyArray<Item>;
|
|
13
13
|
export type BuilderCollectionOf<Builder extends BuilderGeneric, Name extends string> = CollectionOf<BuilderStateOf<Builder>['collections'], Name>;
|
|
14
|
-
export type BuilderCollectionNamesOf<Builder extends BuilderGeneric> =
|
|
14
|
+
export type BuilderCollectionNamesOf<Builder extends BuilderGeneric | null> = [Builder] extends [
|
|
15
|
+
BuilderGeneric
|
|
16
|
+
] ? CollectionNamesOf<BuilderStateOf<Builder>['collections']> : never;
|
|
15
17
|
export type BuilderCollectionModelOf<CollectionRecipe extends BuilderGeneric, Min extends number, Max extends number> = CollectionShape<BuilderModelOf<CollectionRecipe>, Min, Max>;
|
|
16
18
|
export declare class BuilderCollection<const Name extends string = string, const CollectionRecipe = any, const Min extends number = number, const Max extends number = number> implements BuilderCollectionConfig<CollectionRecipe, Min, Max> {
|
|
17
19
|
readonly name: Name;
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import type { BuilderPaths } from '../../paths';
|
|
2
2
|
export type BuilderComponentEntries = ReadonlyArray<BuilderComponent>;
|
|
3
|
-
export type BuilderComponentMap = Record<string, BuilderComponent>;
|
|
4
3
|
export type BuilderComponentNamesOf<Components extends BuilderComponentEntries> = Components[number]['name'];
|
|
5
4
|
export declare class BuilderComponent<const Name extends string = string> {
|
|
6
5
|
readonly name: Name;
|
|
7
6
|
readonly paths: BuilderPaths;
|
|
8
7
|
readonly dependencies: ReadonlyArray<string>;
|
|
9
8
|
constructor(name: Name, paths: BuilderPaths, dependencies?: ReadonlyArray<string>);
|
|
10
|
-
resolve(resolved: BuilderComponentMap): BuilderComponent<Name> | null;
|
|
11
9
|
}
|
|
@@ -7,11 +7,4 @@ export class BuilderComponent {
|
|
|
7
7
|
this.paths = paths;
|
|
8
8
|
this.dependencies = dependencies;
|
|
9
9
|
}
|
|
10
|
-
resolve(resolved) {
|
|
11
|
-
if (this.dependencies.length === 0) {
|
|
12
|
-
return this;
|
|
13
|
-
}
|
|
14
|
-
const ready = this.dependencies.every((dependency) => !!resolved[dependency]);
|
|
15
|
-
return ready ? this : null;
|
|
16
|
-
}
|
|
17
10
|
}
|
|
@@ -6,16 +6,16 @@ export class BuilderComponentGraph {
|
|
|
6
6
|
constructor(paths = []) {
|
|
7
7
|
this.paths = paths;
|
|
8
8
|
}
|
|
9
|
-
has(name) {
|
|
10
|
-
return this.paths.some((graphPath) => graphPath.name === name);
|
|
11
|
-
}
|
|
12
9
|
add(component, options) {
|
|
13
|
-
check.falsy(this
|
|
14
|
-
const keys = new Set(component.paths.map((
|
|
10
|
+
check.falsy(this.#has(component.name), `Duplicate component name '${component.name}'! ❌`);
|
|
11
|
+
const keys = new Set(component.paths.map(([first]) => String(first)));
|
|
15
12
|
const models = this.#mergeModels(keys, options);
|
|
16
13
|
const newPath = { name: component.name, keys, models };
|
|
17
14
|
return new BuilderComponentGraph([...this.paths, newPath]);
|
|
18
15
|
}
|
|
16
|
+
#has(name) {
|
|
17
|
+
return this.paths.some((graphPath) => graphPath.name === name);
|
|
18
|
+
}
|
|
19
19
|
#mergeModels(keys, options) {
|
|
20
20
|
const graphPaths = Array.from(keys)
|
|
21
21
|
.map((key) => options.get(key))
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { BuilderComponentEntries,
|
|
1
|
+
export type { BuilderComponentEntries, BuilderComponentNamesOf } from './component';
|
|
2
2
|
export type { BuilderComponentMethod } from './method';
|
|
3
3
|
export { BuilderComponent } from './component.js';
|
|
4
4
|
export { BuilderComponentGraph } from './graph.js';
|
|
@@ -1,39 +1,42 @@
|
|
|
1
|
-
import type { BuilderGeneric, BuilderMerge, BuilderStateOf } from './builder';
|
|
2
1
|
import type { Prettify } from '../prettify';
|
|
2
|
+
import type { BuilderGeneric, BuilderMerge, BuilderStateOf } from './builder';
|
|
3
|
+
import { BuilderCollection } from './collection/index.js';
|
|
3
4
|
import { BuilderComponent } from './component/index.js';
|
|
4
|
-
export type BuilderExpectationKind = 'option' | 'component';
|
|
5
|
+
export type BuilderExpectationKind = 'option' | 'component' | 'collection';
|
|
5
6
|
export type BuilderExpectationEntries = ReadonlyArray<BuilderExpectation>;
|
|
6
7
|
export type BuilderExpectations = readonly [
|
|
7
8
|
BuilderExpectation,
|
|
8
9
|
...ReadonlyArray<BuilderExpectation>
|
|
9
10
|
];
|
|
10
|
-
export type BuilderModelAsserted<BuilderInput extends BuilderGeneric, Expectations extends BuilderExpectations> = BuilderMerge<BuilderStateOf<
|
|
11
|
-
model: ModelAssert<
|
|
12
|
-
components: ComponentAssert<
|
|
11
|
+
export type BuilderModelAsserted<BuilderInput extends BuilderGeneric | null, Expectations extends BuilderExpectations, Resolved extends BuilderGeneric = [BuilderInput] extends [BuilderGeneric] ? BuilderInput : BuilderGeneric> = BuilderMerge<BuilderStateOf<Resolved>, {
|
|
12
|
+
model: ModelAssert<Resolved, Expectations>;
|
|
13
|
+
components: ComponentAssert<Resolved, Expectations>;
|
|
14
|
+
collections: CollectionAssert<Resolved, Expectations>;
|
|
13
15
|
}>;
|
|
14
16
|
export type ModelAssert<BuilderInput extends BuilderGeneric, Items extends BuilderExpectations, Current extends BuilderStateOf<BuilderInput> = BuilderStateOf<BuilderInput>, Asserted extends ExpectedModel<Items> = ExpectedModel<Items>> = unknown extends Current['model'] ? Prettify<Asserted> : Prettify<Current['model'] & Asserted>;
|
|
15
17
|
export type ComponentAssert<BuilderInput extends BuilderGeneric, Items extends BuilderExpectations, Current extends BuilderStateOf<BuilderInput> = BuilderStateOf<BuilderInput>, Asserted extends ExpectedComponents<Items> = ExpectedComponents<Items>> = Current['components'] extends [] ? ExpectedComponents<Items> : number extends Asserted['length'] ? Asserted : [...Current['components'], ...Asserted];
|
|
16
|
-
export
|
|
18
|
+
export type CollectionAssert<BuilderInput extends BuilderGeneric, Items extends BuilderExpectations, Current extends BuilderStateOf<BuilderInput> = BuilderStateOf<BuilderInput>, Asserted extends ExpectedCollections<Items> = ExpectedCollections<Items>> = Current['collections'] extends [] ? ExpectedCollections<Items> : number extends Asserted['length'] ? Asserted : [...Current['collections'], ...Asserted];
|
|
19
|
+
export declare class BuilderExpectation<Name extends string = string, Value = unknown, Kind extends BuilderExpectationKind = BuilderExpectationKind> {
|
|
17
20
|
readonly name: Name;
|
|
18
|
-
readonly kind:
|
|
19
|
-
constructor(name: Name, kind:
|
|
20
|
-
optional(): BuilderExpectation<Name, Value | null>;
|
|
21
|
-
validate(entries: ReadonlyArray<{
|
|
22
|
-
readonly name: string;
|
|
23
|
-
}>): void;
|
|
21
|
+
readonly kind: Kind;
|
|
22
|
+
constructor(name: Name, kind: Kind);
|
|
23
|
+
optional(): BuilderExpectation<Name, Value | null, Kind>;
|
|
24
24
|
}
|
|
25
|
-
export declare const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
expect: <const Name extends string>(name: Name) => BuilderExpectation<Name, never>;
|
|
25
|
+
export declare const has: {
|
|
26
|
+
option: <const Name extends string>(name: Name) => BuilderExpectation<Name, string, "option">;
|
|
27
|
+
component: <const Name extends string>(name: Name) => BuilderExpectation<Name, never, "component">;
|
|
28
|
+
collection: <const Name extends string>(name: Name) => BuilderExpectation<Name, unknown, "collection">;
|
|
30
29
|
};
|
|
31
30
|
type ExpectedModel<Items extends ReadonlyArray<BuilderExpectation>> = Items extends readonly [
|
|
32
31
|
infer Head,
|
|
33
32
|
...infer Tail extends ReadonlyArray<BuilderExpectation>
|
|
34
|
-
] ? (Head extends BuilderExpectation<infer Name, infer Value> ?
|
|
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;
|
|
35
34
|
type ExpectedComponents<Items extends ReadonlyArray<BuilderExpectation>> = Items extends readonly [
|
|
36
35
|
infer Head,
|
|
37
36
|
...infer Tail extends ReadonlyArray<BuilderExpectation>
|
|
38
|
-
] ? Head extends BuilderExpectation<infer Name,
|
|
37
|
+
] ? Head extends BuilderExpectation<infer Name, any, 'component'> ? [BuilderComponent<Name>, ...ExpectedComponents<Tail>] : ExpectedComponents<Tail> : [];
|
|
38
|
+
type ExpectedCollections<Items extends ReadonlyArray<BuilderExpectation>> = Items extends readonly [
|
|
39
|
+
infer Head,
|
|
40
|
+
...infer Tail extends ReadonlyArray<BuilderExpectation>
|
|
41
|
+
] ? Head extends BuilderExpectation<infer Name, any, 'collection'> ? [BuilderCollection<Name>, ...ExpectedCollections<Tail>] : ExpectedCollections<Tail> : [];
|
|
39
42
|
export {};
|
package/dist/core/expectation.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { BuilderCollection } from './collection/index.js';
|
|
1
2
|
import { BuilderComponent } from './component/index.js';
|
|
2
|
-
import { check } from '../check.js';
|
|
3
3
|
export class BuilderExpectation {
|
|
4
4
|
name;
|
|
5
5
|
kind;
|
|
@@ -10,13 +10,9 @@ export class BuilderExpectation {
|
|
|
10
10
|
optional() {
|
|
11
11
|
return new BuilderExpectation(this.name, this.kind);
|
|
12
12
|
}
|
|
13
|
-
validate(entries) {
|
|
14
|
-
check.truthy(entries.some((entry) => entry.name === this.name), `assert: no \`${this.kind}\` named '${this.name}' exists in the builder config! ❌`);
|
|
15
|
-
}
|
|
16
13
|
}
|
|
17
|
-
export const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
expect: (name) => new BuilderExpectation(name, 'component')
|
|
14
|
+
export const has = {
|
|
15
|
+
option: (name) => new BuilderExpectation(name, 'option'),
|
|
16
|
+
component: (name) => new BuilderExpectation(name, 'component'),
|
|
17
|
+
collection: (name) => new BuilderExpectation(name, 'collection')
|
|
22
18
|
};
|
package/dist/core/index.d.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
export type { BuilderCollectionConfig, BuilderCollectionEnableConfig, BuilderCollectionEntries, BuilderCollectionMatchConfig, BuilderCollectionMethod, BuilderCollectionModelOf, BuilderCollectionNamesOf, BuilderCollectionOf, BuilderCollectionUnlessConfig, BuilderCollectionWhenConfig } from './collection/index';
|
|
2
|
-
export type { BuilderComponentEntries,
|
|
2
|
+
export type { BuilderComponentEntries, BuilderComponentMethod, BuilderComponentNamesOf } from './component/index';
|
|
3
3
|
export type { BuilderExpectationEntries, BuilderExpectations, BuilderModelAsserted } from './expectation';
|
|
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
|
-
export { BuilderExpectation,
|
|
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
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { Builder, builder } from './builder.js';
|
|
2
2
|
export { BuilderCollection, collection, resolveCollectionModels, resolveCollectionNames } from './collection/index.js';
|
|
3
3
|
export { BuilderComponent, BuilderComponentGraph } from './component/index.js';
|
|
4
|
-
export { BuilderExpectation,
|
|
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,10 +2,9 @@ import type { GraphPath, GraphPaths } from '../graph';
|
|
|
2
2
|
import { BuilderOption } from './option.js';
|
|
3
3
|
export type BuilderOptionGraphs = ReadonlyArray<BuilderOptionGraph>;
|
|
4
4
|
export declare class BuilderOptionGraph {
|
|
5
|
+
#private;
|
|
5
6
|
readonly paths: GraphPaths;
|
|
6
7
|
constructor(paths?: GraphPaths);
|
|
7
|
-
static merge(...graphs: BuilderOptionGraphs): BuilderOptionGraph;
|
|
8
|
-
has(name: string): boolean;
|
|
9
8
|
get(name: string): GraphPath;
|
|
10
9
|
add(option: BuilderOption): BuilderOptionGraph;
|
|
11
10
|
}
|
|
@@ -8,18 +8,13 @@ export class BuilderOptionGraph {
|
|
|
8
8
|
constructor(paths = []) {
|
|
9
9
|
this.paths = paths;
|
|
10
10
|
}
|
|
11
|
-
static merge(...graphs) {
|
|
12
|
-
return new BuilderOptionGraph(graphs.flatMap((graph) => graph.paths));
|
|
13
|
-
}
|
|
14
|
-
has(name) {
|
|
15
|
-
return this.paths.some((graphPath) => graphPath.name === name);
|
|
16
|
-
}
|
|
17
11
|
get(name) {
|
|
18
12
|
const graphPath = this.paths.find((graphPath) => graphPath.name === name);
|
|
19
13
|
check.truthy(graphPath, `Option '${name}' not found in graph! ❌`);
|
|
20
14
|
return graphPath;
|
|
21
15
|
}
|
|
22
16
|
add(option) {
|
|
17
|
+
check.falsy(this.#has(option.name), `Duplicate option name '${option.name}'! ❌`);
|
|
23
18
|
const dependencyKeys = option.dependencyKeys();
|
|
24
19
|
if (dependencyKeys.length === 0) {
|
|
25
20
|
const values = optionValues(option);
|
|
@@ -50,6 +45,9 @@ export class BuilderOptionGraph {
|
|
|
50
45
|
{ name: option.name, keys: merged.keys, models: finalModels }
|
|
51
46
|
]);
|
|
52
47
|
}
|
|
48
|
+
#has(name) {
|
|
49
|
+
return this.paths.some((graphPath) => graphPath.name === name);
|
|
50
|
+
}
|
|
53
51
|
}
|
|
54
52
|
function mergePaths(dependencyKeys, graphPaths) {
|
|
55
53
|
const dependencyPaths = Array.from(dependencyKeys).map((dependencyKey) => {
|
|
@@ -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';
|
|
@@ -28,13 +28,14 @@ export class BuilderOption {
|
|
|
28
28
|
});
|
|
29
29
|
}
|
|
30
30
|
dependencyKeys() {
|
|
31
|
-
const keys = new Set(this.gatePaths.map((
|
|
31
|
+
const keys = new Set(this.gatePaths.map(([first]) => String(first)));
|
|
32
32
|
if (this.config?.type === 'match') {
|
|
33
|
-
const
|
|
34
|
-
keys.add(String(
|
|
33
|
+
const [firstMatchSegment] = this.config.matchPath;
|
|
34
|
+
keys.add(String(firstMatchSegment));
|
|
35
35
|
}
|
|
36
36
|
else if (this.config?.type === 'unless') {
|
|
37
|
-
|
|
37
|
+
const [firstUnlessSegment] = this.config.unlessPath;
|
|
38
|
+
keys.add(String(firstUnlessSegment));
|
|
38
39
|
}
|
|
39
40
|
return Array.from(keys);
|
|
40
41
|
}
|
|
@@ -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
|
-
export type { BuilderUI,
|
|
8
|
-
export type { BuilderCollectionSerialised, BuilderCollectionWhenConfigSerialised, BuilderComponentSerialised, BuilderOptionSerialised, BuilderOptionWhenConfigSerialised, BuilderParameterSerialised, BuilderSelectTypeSerialised, BuilderSerialised, BuilderToggleTypeSerialised, BuilderUISerialised, BuilderValuesSerialised } from './serialise/index';
|
|
9
|
-
export { BuilderExpectation,
|
|
7
|
+
export type { BuilderUI, BuilderUIs } from './ui';
|
|
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,
|
|
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/paths.d.ts
CHANGED
|
@@ -5,7 +5,9 @@ export type BuilderValidPath<Model, Depth extends ReadonlyArray<never> = []> = D
|
|
|
5
5
|
[Key in keyof Model & string]: [Key] | (Model[Key] extends BuilderPrimitive | null ? never : [Key, ...BuilderValidPath<Model[Key], [...Depth, never]>]);
|
|
6
6
|
}[keyof Model & string];
|
|
7
7
|
export type BuilderValidPaths<Model> = ReadonlyArray<BuilderValidPath<Model>>;
|
|
8
|
-
export type BuilderModelPaths<Builder extends BuilderGeneric> =
|
|
8
|
+
export type BuilderModelPaths<Builder extends BuilderGeneric | null> = [Builder] extends [
|
|
9
|
+
BuilderGeneric
|
|
10
|
+
] ? BuilderValidPaths<BuilderModelOf<Builder>> : ReadonlyArray<never>;
|
|
9
11
|
export type BuilderResolvePath<Model, Path extends BuilderPath> = Path extends readonly [
|
|
10
12
|
infer Head extends keyof Model & string
|
|
11
13
|
] ? Model[Head] : Path extends readonly [
|
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';
|