@builder-builder/builder 0.0.3 → 0.0.5
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/check.d.ts +8 -0
- package/dist/check.js +18 -0
- package/dist/core/builder.d.ts +31 -22
- package/dist/core/builder.js +73 -27
- package/dist/core/collection/collection.d.ts +9 -12
- package/dist/core/collection/collection.js +9 -27
- package/dist/core/collection/index.d.ts +1 -1
- package/dist/core/collection/method.d.ts +22 -43
- package/dist/core/component/component.d.ts +1 -4
- package/dist/core/component/graph.d.ts +0 -3
- package/dist/core/component/graph.js +7 -9
- package/dist/core/component/method.d.ts +7 -9
- package/dist/core/expectation.d.ts +39 -0
- package/dist/{assert → core}/expectation.js +3 -2
- package/dist/core/graph.d.ts +2 -1
- package/dist/core/graph.js +3 -1
- package/dist/core/index.d.ts +8 -4
- package/dist/core/index.js +3 -1
- package/dist/core/option/graph.js +7 -5
- package/dist/core/option/method.d.ts +60 -42
- package/dist/core/option/method.js +7 -3
- package/dist/core/option/option.d.ts +14 -7
- package/dist/core/option/option.js +15 -23
- package/dist/core/option/select.d.ts +6 -1
- package/dist/core/option/select.js +5 -1
- package/dist/core/parameter.d.ts +48 -0
- package/dist/core/parameter.js +31 -0
- package/dist/core/when/config.d.ts +20 -0
- package/dist/core/when/config.js +4 -0
- package/dist/core/when/constrain.d.ts +14 -0
- package/dist/core/when/index.d.ts +5 -0
- package/dist/core/when/index.js +2 -0
- package/dist/core/when/nullability.d.ts +18 -0
- package/dist/core/when/nullability.js +1 -0
- package/dist/core/when/resolve.d.ts +18 -0
- package/dist/core/when/resolve.js +22 -0
- package/dist/index.d.ts +7 -10
- package/dist/index.js +2 -3
- package/dist/{config.d.ts → model.d.ts} +1 -1
- package/dist/model.js +1 -0
- package/dist/paths.d.ts +4 -3
- package/dist/resolve/index.d.ts +2 -2
- package/dist/resolve/instance.d.ts +2 -2
- package/dist/resolve/models.d.ts +1 -1
- package/dist/resolve/order.d.ts +7 -6
- package/dist/resolve/render.d.ts +4 -4
- package/dist/resolve/render.js +49 -60
- package/dist/resolve/validate.d.ts +6 -5
- package/dist/resolve/validate.js +5 -4
- package/dist/schemas/index.d.ts +2 -6
- package/dist/schemas/index.js +1 -3
- package/dist/serialise/deserialise.js +11 -6
- package/dist/serialise/index.d.ts +2 -2
- package/dist/serialise/index.js +1 -1
- package/dist/{schemas/serialise.d.ts → serialise/schemas.d.ts} +1050 -242
- package/dist/{schemas/serialise.js → serialise/schemas.js} +47 -47
- package/dist/serialise/serialise.d.ts +1 -1
- package/dist/serialise/serialise.js +19 -2
- package/dist/ui.d.ts +12 -12
- package/dist/ui.js +23 -16
- package/package.json +1 -1
- package/dist/assert/assert.d.ts +0 -28
- package/dist/assert/assert.js +0 -28
- package/dist/assert/expectation.d.ts +0 -20
- package/dist/assert/index.d.ts +0 -3
- package/dist/assert/index.js +0 -2
- package/dist/invariant.d.ts +0 -1
- package/dist/invariant.js +0 -6
- package/dist/schemas/layout.d.ts +0 -52
- package/dist/schemas/layout.js +0 -6
- /package/dist/{config.js → core/when/constrain.js} +0 -0
package/dist/check.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as v from 'valibot';
|
|
2
|
+
declare class Check {
|
|
3
|
+
truthy<Input>(input: Input, message?: `${string}! ❌`): asserts input is Exclude<Input, null | undefined | '' | 0 | false>;
|
|
4
|
+
falsy(input: unknown, message?: `${string}! ❌`): void;
|
|
5
|
+
assert<const TSchema extends v.BaseSchema<unknown, unknown, v.BaseIssue<unknown>>>(schema: TSchema, input: unknown): asserts input is v.InferOutput<TSchema>;
|
|
6
|
+
}
|
|
7
|
+
export declare const check: Check;
|
|
8
|
+
export {};
|
package/dist/check.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as v from 'valibot';
|
|
2
|
+
const DEFAULT_MESSAGE = 'Unexpected value! ❌';
|
|
3
|
+
class Check {
|
|
4
|
+
truthy(input, message = DEFAULT_MESSAGE) {
|
|
5
|
+
if (!input) {
|
|
6
|
+
throw new Error(message);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
falsy(input, message = DEFAULT_MESSAGE) {
|
|
10
|
+
if (input) {
|
|
11
|
+
throw new Error(message);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
assert(schema, input) {
|
|
15
|
+
v.assert(schema, input);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export const check = new Check();
|
package/dist/core/builder.d.ts
CHANGED
|
@@ -1,61 +1,70 @@
|
|
|
1
|
+
import type { Prettify } from '../prettify';
|
|
1
2
|
import type { BuilderCollectionEntries, BuilderCollectionMethod } from './collection/index';
|
|
2
3
|
import type { BuilderComponentEntries, BuilderComponentMethod } from './component/index';
|
|
3
|
-
import type { BuilderOptionEntries, BuilderOptionMethod
|
|
4
|
+
import type { BuilderOptionEntries, BuilderOptionMethod } from './option/index';
|
|
5
|
+
import type { BuilderBindings, BuilderBoundState } from './parameter';
|
|
6
|
+
import type { BuilderExpectationEntries, BuilderExpectations, ComponentAssert, ModelAssert } from './expectation';
|
|
4
7
|
import { BuilderComponentGraph } from './component/index.js';
|
|
5
8
|
import { BuilderOptionGraph } from './option/index.js';
|
|
6
|
-
export type BuilderSelectMap<Select extends BuilderSelectType = BuilderSelectType> = Record<Select['options'][number], BuilderOptionValues | null>;
|
|
7
|
-
export type BuilderSelectMapGeneric = BuilderSelectMap<any>;
|
|
8
9
|
export type BuilderState = {
|
|
9
10
|
readonly model: unknown;
|
|
10
11
|
readonly options: BuilderOptionEntries;
|
|
11
12
|
readonly components: BuilderComponentEntries;
|
|
12
13
|
readonly collections: BuilderCollectionEntries;
|
|
14
|
+
readonly expectations: BuilderExpectationEntries;
|
|
13
15
|
};
|
|
14
16
|
export type BuilderStateEmpty = {
|
|
15
17
|
readonly model: unknown;
|
|
16
18
|
readonly options: [];
|
|
17
19
|
readonly components: [];
|
|
18
20
|
readonly collections: [];
|
|
21
|
+
readonly expectations: [];
|
|
19
22
|
};
|
|
20
|
-
import type { Prettify } from '../prettify';
|
|
21
23
|
export type BuilderStateMerge<State extends BuilderState, Patch extends Partial<BuilderState>> = {
|
|
22
|
-
model: 'model' extends keyof Patch ? Patch['model'] : State['model']
|
|
23
|
-
options: 'options' extends keyof Patch ? Patch['options'] : State['options']
|
|
24
|
-
components: 'components' extends keyof Patch ? Patch['components'] : State['components']
|
|
25
|
-
collections: 'collections' extends keyof Patch ? Patch['collections'] : State['collections']
|
|
24
|
+
model: Prettify<'model' extends keyof Patch ? Patch['model'] : State['model']>;
|
|
25
|
+
options: Extract<'options' extends keyof Patch ? Patch['options'] : State['options'], BuilderOptionEntries>;
|
|
26
|
+
components: Extract<'components' extends keyof Patch ? Patch['components'] : State['components'], BuilderComponentEntries>;
|
|
27
|
+
collections: Extract<'collections' extends keyof Patch ? Patch['collections'] : State['collections'], BuilderCollectionEntries>;
|
|
28
|
+
expectations: Extract<'expectations' extends keyof Patch ? Patch['expectations'] : State['expectations'], BuilderExpectationEntries>;
|
|
26
29
|
};
|
|
30
|
+
export type BuilderMerge<State extends BuilderState, Patch extends Partial<BuilderState>> = Builder<BuilderStateMerge<State, Patch>>;
|
|
27
31
|
export type BuilderGeneric = Builder<any>;
|
|
28
|
-
export type
|
|
29
|
-
export type BuilderPart = BuilderGeneric | BuilderFactory;
|
|
30
|
-
export type BuilderParts = ReadonlyArray<BuilderPart>;
|
|
32
|
+
export type Builders = ReadonlyArray<BuilderGeneric>;
|
|
31
33
|
export type BuilderStateOf<Input extends BuilderGeneric> = Input extends Builder<infer State extends BuilderState> ? State : BuilderStateEmpty;
|
|
32
34
|
export type BuilderModelOf<Input extends BuilderGeneric> = Input extends Builder<infer State extends BuilderState> ? Prettify<State['model']> : never;
|
|
33
|
-
export type BuilderCollectionsOf<Input extends BuilderGeneric> = Input extends Builder<infer State extends BuilderState> ? State['collections'] : never;
|
|
34
35
|
export declare class Builder<State extends BuilderState = BuilderStateEmpty> {
|
|
35
36
|
#private;
|
|
36
37
|
readonly _options: State['options'];
|
|
37
38
|
readonly _components: State['components'];
|
|
38
39
|
readonly _collections: State['collections'];
|
|
40
|
+
readonly _expectations: State['expectations'];
|
|
39
41
|
readonly options: BuilderOptionEntries;
|
|
40
42
|
readonly components: BuilderComponentEntries;
|
|
41
43
|
readonly collections: BuilderCollectionEntries;
|
|
42
|
-
readonly
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
readonly expectations: BuilderExpectationEntries;
|
|
45
|
+
constructor(options?: BuilderOptionEntries, collections?: BuilderCollectionEntries, components?: BuilderComponentEntries, expectations?: BuilderExpectationEntries);
|
|
46
|
+
get optionGraph(): BuilderOptionGraph;
|
|
47
|
+
get componentGraph(): BuilderComponentGraph;
|
|
45
48
|
get option(): BuilderOptionMethod<State>;
|
|
46
49
|
get component(): BuilderComponentMethod<State>;
|
|
47
50
|
get collection(): BuilderCollectionMethod<State>;
|
|
51
|
+
expect<const Expectations extends BuilderExpectations>(...expectations: Expectations): BuilderMerge<State, {
|
|
52
|
+
model: ModelAssert<Builder<State>, Expectations>;
|
|
53
|
+
components: ComponentAssert<Builder<State>, Expectations>;
|
|
54
|
+
expectations: [...State['expectations'], ...Expectations];
|
|
55
|
+
}>;
|
|
56
|
+
bind<const Bindings extends BuilderBindings<State>>(bindings: Bindings): Builder<BuilderBoundState<State, Bindings>>;
|
|
48
57
|
}
|
|
49
|
-
export declare function builder<const
|
|
50
|
-
type
|
|
51
|
-
|
|
52
|
-
infer
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
type MergeStates<Left extends BuilderState, Right extends BuilderState> = {
|
|
58
|
+
export declare function builder<const BuildersToMerge extends Builders>(...buildersToMerge: BuildersToMerge): Builder<MergedPartsState<BuildersToMerge>>;
|
|
59
|
+
type MergedPartsState<Parts extends ReadonlyArray<BuilderGeneric>> = Parts extends readonly [
|
|
60
|
+
infer Head extends BuilderGeneric,
|
|
61
|
+
...infer Tail extends ReadonlyArray<BuilderGeneric>
|
|
62
|
+
] ? MergedStates<BuilderStateOf<Head>, MergedPartsState<Tail>> : BuilderStateEmpty;
|
|
63
|
+
type MergedStates<Left extends BuilderState, Right extends BuilderState> = {
|
|
56
64
|
model: Left['model'] & Right['model'];
|
|
57
65
|
options: [...Left['options'], ...Right['options']];
|
|
58
66
|
components: [...Left['components'], ...Right['components']];
|
|
59
67
|
collections: [...Left['collections'], ...Right['collections']];
|
|
68
|
+
expectations: [...Left['expectations'], ...Right['expectations']];
|
|
60
69
|
};
|
|
61
70
|
export {};
|
package/dist/core/builder.js
CHANGED
|
@@ -1,72 +1,118 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as v from 'valibot';
|
|
2
|
+
import { BuilderExpectation } from './expectation.js';
|
|
3
|
+
import { check } from '../check.js';
|
|
2
4
|
import { BuilderCollection, resolveCollectionNames } from './collection/index.js';
|
|
3
5
|
import { BuilderComponent, BuilderComponentGraph } from './component/index.js';
|
|
4
6
|
import { BuilderOption, BuilderOptionGraph } from './option/index.js';
|
|
7
|
+
import { BuilderParameter, bindOptions, extractValues } from './parameter.js';
|
|
5
8
|
export class Builder {
|
|
6
9
|
options;
|
|
7
10
|
components;
|
|
8
11
|
collections;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
+
expectations;
|
|
13
|
+
#optionGraph = null;
|
|
14
|
+
#componentGraph = null;
|
|
15
|
+
constructor(options = [], collections = [], components = [], expectations = []) {
|
|
12
16
|
this.options = options;
|
|
13
17
|
this.collections = collections;
|
|
14
18
|
this.components = components;
|
|
15
|
-
this.
|
|
16
|
-
|
|
19
|
+
this.expectations = expectations;
|
|
20
|
+
}
|
|
21
|
+
get optionGraph() {
|
|
22
|
+
if (this.#optionGraph === null) {
|
|
23
|
+
this.#optionGraph = this.options.reduce((graph, option) => graph.add(option), new BuilderOptionGraph());
|
|
24
|
+
}
|
|
25
|
+
return this.#optionGraph;
|
|
26
|
+
}
|
|
27
|
+
get componentGraph() {
|
|
28
|
+
if (this.#componentGraph === null) {
|
|
29
|
+
const graphs = [
|
|
30
|
+
this.components.reduce((graph, component) => graph.add(component, this.optionGraph), new BuilderComponentGraph()),
|
|
31
|
+
...this.collections.map((collection) => collection.builder.componentGraph)
|
|
32
|
+
];
|
|
33
|
+
this.#componentGraph = new BuilderComponentGraph(graphs.flatMap((graph) => graph.paths));
|
|
34
|
+
}
|
|
35
|
+
return this.#componentGraph;
|
|
17
36
|
}
|
|
18
37
|
get option() {
|
|
19
38
|
const addOption = (name, values) => {
|
|
20
39
|
const entry = new BuilderOption(name, values);
|
|
21
|
-
return this.#next([...this.options, entry], this.collections, this.components
|
|
40
|
+
return this.#next([...this.options, entry], this.collections, this.components);
|
|
22
41
|
};
|
|
23
42
|
const addConditionalOption = (gatePaths, name, config) => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
43
|
+
if (v.is(v.instance(BuilderParameter), config)) {
|
|
44
|
+
const entry = new BuilderOption(name, config, gatePaths, null);
|
|
45
|
+
return this.#next([...this.options, entry], this.collections, this.components);
|
|
46
|
+
}
|
|
47
|
+
const entry = new BuilderOption(name, extractValues(config), gatePaths, config);
|
|
48
|
+
return this.#next([...this.options, entry], this.collections, this.components);
|
|
29
49
|
};
|
|
50
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- bridges loose implementation to strict overloaded type
|
|
30
51
|
return Object.assign(addOption, { when: addConditionalOption });
|
|
31
52
|
}
|
|
32
53
|
get component() {
|
|
54
|
+
const existingNames = new Set(this.components.map((component) => component.name));
|
|
33
55
|
const addComponent = (name, paths) => {
|
|
56
|
+
check.falsy(existingNames.has(name), `Duplicate component name '${name}'! ❌`);
|
|
34
57
|
const entry = new BuilderComponent(name, paths);
|
|
35
|
-
return this.#next(this.options, this.collections, [...this.components, entry]
|
|
58
|
+
return this.#next(this.options, this.collections, [...this.components, entry]);
|
|
36
59
|
};
|
|
37
60
|
const addConditionalComponent = (dependencies, name, paths) => {
|
|
61
|
+
check.falsy(existingNames.has(name), `Duplicate component name '${name}'! ❌`);
|
|
38
62
|
const entry = new BuilderComponent(name, paths, dependencies);
|
|
39
|
-
return this.#next(this.options, this.collections, [...this.components, entry]
|
|
63
|
+
return this.#next(this.options, this.collections, [...this.components, entry]);
|
|
40
64
|
};
|
|
65
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- bridges loose implementation to strict overloaded type
|
|
41
66
|
return Object.assign(addComponent, { when: addConditionalComponent });
|
|
42
67
|
}
|
|
43
68
|
get collection() {
|
|
44
69
|
const addCollection = (name, collectionRecipe, min = 0, max = Infinity) => {
|
|
45
70
|
const existing = resolveCollectionNames(this.collections);
|
|
46
|
-
|
|
71
|
+
check.falsy(existing.has(name), `Duplicate collection name '${name}'! ❌`);
|
|
72
|
+
check.assert(v.instance(Builder), collectionRecipe);
|
|
47
73
|
const entry = new BuilderCollection(name, collectionRecipe, min, max);
|
|
48
|
-
return this.#next(this.options, [...this.collections, entry], this.components
|
|
74
|
+
return this.#next(this.options, [...this.collections, entry], this.components);
|
|
49
75
|
};
|
|
50
76
|
const addConditionalCollection = (gatePaths, name, config) => {
|
|
51
77
|
const existing = resolveCollectionNames(this.collections);
|
|
52
|
-
|
|
78
|
+
check.falsy(existing.has(name), `Duplicate collection name '${name}'! ❌`);
|
|
53
79
|
const defaultEntry = config.type === 'match'
|
|
54
80
|
? Object.values(config.selectMap).find((value) => value !== null)
|
|
55
81
|
: config;
|
|
56
82
|
const entry = new BuilderCollection(name, defaultEntry.builder, defaultEntry.min, defaultEntry.max, gatePaths, config);
|
|
57
|
-
return this.#next(this.options, [...this.collections, entry], this.components
|
|
83
|
+
return this.#next(this.options, [...this.collections, entry], this.components);
|
|
58
84
|
};
|
|
85
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- bridges loose implementation to strict overloaded type
|
|
59
86
|
return Object.assign(addCollection, { when: addConditionalCollection });
|
|
60
87
|
}
|
|
61
|
-
|
|
62
|
-
return new Builder(options, collections, components,
|
|
88
|
+
expect(...expectations) {
|
|
89
|
+
return new Builder(this.options, this.collections, this.components, [
|
|
90
|
+
...this.expectations,
|
|
91
|
+
...expectations
|
|
92
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- type narrowing cast, validated at merge time
|
|
93
|
+
]);
|
|
94
|
+
}
|
|
95
|
+
bind(bindings) {
|
|
96
|
+
const boundOptions = bindOptions(this.options, bindings);
|
|
97
|
+
return new Builder(boundOptions, this.collections, this.components, this.expectations);
|
|
98
|
+
}
|
|
99
|
+
#next(options, collections, components) {
|
|
100
|
+
return new Builder(options, collections, components, this.expectations);
|
|
63
101
|
}
|
|
64
102
|
}
|
|
65
|
-
export function builder(...
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
103
|
+
export function builder(...buildersToMerge) {
|
|
104
|
+
const merged = new Builder(buildersToMerge.flatMap((builder) => builder.options), buildersToMerge.flatMap((builder) => builder.collections), buildersToMerge.flatMap((builder) => builder.components));
|
|
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;
|
|
72
118
|
}
|
|
@@ -1,22 +1,18 @@
|
|
|
1
|
-
import type { BuilderModel, BuilderModels } from '../../
|
|
1
|
+
import type { BuilderModel, BuilderModels } from '../../model';
|
|
2
2
|
import type { BuilderPaths } from '../../paths';
|
|
3
|
+
import type { BuilderGeneric, BuilderModelOf, BuilderStateOf } from '../builder';
|
|
3
4
|
import type { BuilderCollectionWhenConfig } from './method';
|
|
4
|
-
import type { BuilderGeneric, BuilderStateOf } from '../builder';
|
|
5
5
|
export type BuilderCollectionConfig<CollectionRecipe = any, Min extends number = number, Max extends number = number> = {
|
|
6
6
|
readonly builder: CollectionRecipe;
|
|
7
7
|
readonly min: Min;
|
|
8
8
|
readonly max: Max;
|
|
9
9
|
};
|
|
10
10
|
export type BuilderCollectionEntries = ReadonlyArray<BuilderCollection>;
|
|
11
|
-
export type
|
|
12
|
-
export type
|
|
13
|
-
type
|
|
14
|
-
export type BuilderCollectionNamesOf<
|
|
15
|
-
type
|
|
16
|
-
infer Head extends BuilderCollection,
|
|
17
|
-
...infer Tail extends BuilderCollectionEntries
|
|
18
|
-
] ? Head['name'] | ExtractCollectionNames<Tail> : never;
|
|
19
|
-
export type BuilderCollectionModelOf<CollectionRecipe, Min extends number, Max extends number> = number extends Min ? ReadonlyArray<ExtractModel<CollectionRecipe>> : number extends Max ? ReadonlyArray<ExtractModel<CollectionRecipe>> : Min extends Max ? BuilderTupleOf<ExtractModel<CollectionRecipe>, Min> : ReadonlyArray<ExtractModel<CollectionRecipe>>;
|
|
11
|
+
export type TupleOf<Item, Length extends number, Result extends ReadonlyArray<Item> = []> = Result['length'] extends Length ? Result : TupleOf<Item, Length, [...Result, Item]>;
|
|
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
|
+
export type BuilderCollectionOf<Builder extends BuilderGeneric, Name extends string> = CollectionOf<BuilderStateOf<Builder>['collections'], Name>;
|
|
14
|
+
export type BuilderCollectionNamesOf<Builder extends BuilderGeneric> = CollectionNamesOf<BuilderStateOf<Builder>['collections']>;
|
|
15
|
+
export type BuilderCollectionModelOf<CollectionRecipe extends BuilderGeneric, Min extends number, Max extends number> = CollectionShape<BuilderModelOf<CollectionRecipe>, Min, Max>;
|
|
20
16
|
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> {
|
|
21
17
|
readonly name: Name;
|
|
22
18
|
readonly builder: CollectionRecipe;
|
|
@@ -29,5 +25,6 @@ export declare class BuilderCollection<const Name extends string = string, const
|
|
|
29
25
|
}
|
|
30
26
|
export declare function resolveCollectionNames(collections: BuilderCollectionEntries): Set<string>;
|
|
31
27
|
export declare function resolveCollectionModels(model: BuilderModel, collectionName: string): BuilderModels;
|
|
32
|
-
type
|
|
28
|
+
type CollectionOf<Config extends BuilderCollectionEntries, Name extends string> = Config extends readonly [infer Head, ...infer Tail extends BuilderCollectionEntries] ? Extract<Head, BuilderCollection<Name, any, any, any>> extends never ? CollectionOf<Tail, Name> : Extract<Head, BuilderCollection<Name, any, any, any>> : Extract<Config[number], BuilderCollection<Name, any, any, any>>;
|
|
29
|
+
type CollectionNamesOf<Entries extends BuilderCollectionEntries> = Entries[number]['name'];
|
|
33
30
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { check } from '../../check.js';
|
|
2
|
+
import { resolve } from '../when/index.js';
|
|
3
3
|
export class BuilderCollection {
|
|
4
4
|
name;
|
|
5
5
|
builder;
|
|
@@ -8,9 +8,9 @@ export class BuilderCollection {
|
|
|
8
8
|
gatePaths;
|
|
9
9
|
config;
|
|
10
10
|
constructor(name, builder, min = 0, max = Infinity, gatePaths = [], config = null) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
check.truthy(min >= 0, `Collection '${name}': min must be >= 0, got ${min}! ❌`);
|
|
12
|
+
check.truthy(max > 0, `Collection '${name}': max must be > 0, got ${max}! ❌`);
|
|
13
|
+
check.truthy(max >= min, `Collection '${name}': max must be >= min, got min=${min}, max=${max}! ❌`);
|
|
14
14
|
this.name = name;
|
|
15
15
|
this.builder = builder;
|
|
16
16
|
this.min = min;
|
|
@@ -19,28 +19,10 @@ export class BuilderCollection {
|
|
|
19
19
|
this.config = config;
|
|
20
20
|
}
|
|
21
21
|
resolve(model) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
return null;
|
|
27
|
-
}
|
|
28
|
-
switch (this.config.type) {
|
|
29
|
-
case 'enable': {
|
|
30
|
-
return this;
|
|
31
|
-
}
|
|
32
|
-
case 'match': {
|
|
33
|
-
const matchPath = this.config.matchPath;
|
|
34
|
-
const entry = this.config.selectMap[String(readPath(model, matchPath))];
|
|
35
|
-
return entry ? new BuilderCollection(this.name, entry.builder, entry.min, entry.max) : null;
|
|
36
|
-
}
|
|
37
|
-
case 'unless': {
|
|
38
|
-
const value = readPath(model, this.config.unlessPath);
|
|
39
|
-
return !this.config.disabledValues.includes(value)
|
|
40
|
-
? this
|
|
41
|
-
: null;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
22
|
+
return resolve(this, model, (selectMap, matchValue) => {
|
|
23
|
+
const entry = selectMap[matchValue];
|
|
24
|
+
return entry ? new BuilderCollection(this.name, entry.builder, entry.min, entry.max) : null;
|
|
25
|
+
});
|
|
44
26
|
}
|
|
45
27
|
}
|
|
46
28
|
export function resolveCollectionNames(collections) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { BuilderCollectionConfig, BuilderCollectionEntries, BuilderCollectionModelOf, BuilderCollectionNamesOf, BuilderCollectionOf,
|
|
1
|
+
export type { BuilderCollectionConfig, BuilderCollectionEntries, BuilderCollectionModelOf, BuilderCollectionNamesOf, BuilderCollectionOf, TupleOf, CollectionShape } from './collection';
|
|
2
2
|
export type { BuilderCollectionEnableConfig, BuilderCollectionMatchConfig, BuilderCollectionMethod, BuilderCollectionUnlessConfig, BuilderCollectionWhenConfig } from './method';
|
|
3
3
|
export { BuilderCollection, resolveCollectionModels, resolveCollectionNames } from './collection.js';
|
|
4
4
|
export { collection } from './method.js';
|
|
@@ -1,51 +1,30 @@
|
|
|
1
|
-
import type { BuilderPrimitive } from '../../
|
|
2
|
-
import type { BuilderPath,
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
1
|
+
import type { BuilderPrimitive } from '../../model';
|
|
2
|
+
import type { BuilderPath, BuilderValidPaths } from '../../paths';
|
|
3
|
+
import type { BuilderGeneric, BuilderMerge, BuilderState } from '../builder';
|
|
4
|
+
import type { BuilderWhenEnableConfig, BuilderWhenMatchConfig, BuilderWhenUnlessConfig, WhenConfigConstrained, WhenNullability } from '../when/index';
|
|
5
5
|
import type { BuilderCollection, BuilderCollectionConfig, BuilderCollectionModelOf } from './collection';
|
|
6
|
-
export type BuilderCollectionEnableConfig<CollectionRecipe = any, Min extends number = number, Max extends number = number> =
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
readonly min: Min;
|
|
10
|
-
readonly max: Max;
|
|
11
|
-
};
|
|
12
|
-
export type BuilderCollectionMatchConfig<SelectMap extends Record<string, BuilderCollectionConfig | null> = Record<string, BuilderCollectionConfig | null>, MatchPath extends BuilderPath = BuilderPath> = {
|
|
13
|
-
readonly type: 'match';
|
|
14
|
-
readonly matchPath: MatchPath;
|
|
15
|
-
readonly selectMap: SelectMap;
|
|
16
|
-
};
|
|
17
|
-
export type BuilderCollectionUnlessConfig<CollectionRecipe = any, Min extends number = number, Max extends number = number, UnlessPath extends BuilderPath = BuilderPath> = {
|
|
18
|
-
readonly type: 'unless';
|
|
19
|
-
readonly unlessPath: UnlessPath;
|
|
20
|
-
readonly disabledValues: ReadonlyArray<BuilderPrimitive>;
|
|
21
|
-
readonly builder: CollectionRecipe;
|
|
22
|
-
readonly min: Min;
|
|
23
|
-
readonly max: Max;
|
|
24
|
-
};
|
|
6
|
+
export type BuilderCollectionEnableConfig<CollectionRecipe = any, Min extends number = number, Max extends number = number> = BuilderWhenEnableConfig<BuilderCollectionConfig<CollectionRecipe, Min, Max>>;
|
|
7
|
+
export type BuilderCollectionMatchConfig<SelectMap extends Record<string, BuilderCollectionConfig | null> = Record<string, BuilderCollectionConfig | null>, MatchPath extends BuilderPath = BuilderPath> = BuilderWhenMatchConfig<SelectMap, MatchPath>;
|
|
8
|
+
export type BuilderCollectionUnlessConfig<CollectionRecipe = any, Min extends number = number, Max extends number = number, UnlessPath extends BuilderPath = BuilderPath> = BuilderWhenUnlessConfig<BuilderCollectionConfig<CollectionRecipe, Min, Max>, UnlessPath>;
|
|
25
9
|
export type BuilderCollectionWhenConfig = BuilderCollectionEnableConfig | BuilderCollectionMatchConfig | BuilderCollectionUnlessConfig;
|
|
26
|
-
export declare const collection: {
|
|
27
|
-
enable: <const CollectionRecipe extends BuilderGeneric, const Min extends number, const Max extends number>(builder: CollectionRecipe, min: Min, max: Max) => BuilderCollectionEnableConfig<CollectionRecipe, Min, Max>;
|
|
28
|
-
match: <const MatchPath extends BuilderPath, const SelectMap extends Record<string, BuilderCollectionConfig | null>>(matchPath: MatchPath, selectMap: SelectMap) => BuilderCollectionMatchConfig<SelectMap, MatchPath>;
|
|
29
|
-
unless: <const CollectionRecipe extends BuilderGeneric, const Min extends number, const Max extends number, const UnlessPath extends BuilderPath>(unlessPath: UnlessPath, disabledValues: ReadonlyArray<BuilderPrimitive>, builder: CollectionRecipe, min: Min, max: Max) => BuilderCollectionUnlessConfig<CollectionRecipe, Min, Max, UnlessPath>;
|
|
30
|
-
};
|
|
31
|
-
type CollectionWhenConfigModel<Config extends BuilderCollectionWhenConfig> = Config extends BuilderCollectionEnableConfig<infer BuilderInput, infer Min, infer Max> ? BuilderCollectionModelOf<BuilderInput, Min, Max> : Config extends BuilderCollectionUnlessConfig<infer BuilderInput, infer Min, infer Max> ? BuilderCollectionModelOf<BuilderInput, Min, Max> : Config extends BuilderCollectionMatchConfig<infer SelectMapType> ? BuilderCollectionModelOf<(NonNullable<SelectMapType[keyof SelectMapType]> & BuilderCollectionConfig)['builder'], (NonNullable<SelectMapType[keyof SelectMapType]> & BuilderCollectionConfig)['min'], (NonNullable<SelectMapType[keyof SelectMapType]> & BuilderCollectionConfig)['max']> : never;
|
|
32
|
-
type CollectionWhenConfigResolver<Name extends string, Config extends BuilderCollectionWhenConfig> = Config extends BuilderCollectionEnableConfig<infer BuilderInput, infer Min, infer Max> ? BuilderCollection<Name, BuilderInput, Min, Max> : Config extends BuilderCollectionUnlessConfig<infer BuilderInput, infer Min, infer Max> ? BuilderCollection<Name, BuilderInput, Min, Max> : Config extends BuilderCollectionMatchConfig<infer SelectMapType> ? BuilderCollection<Name, (NonNullable<SelectMapType[keyof SelectMapType]> & BuilderCollectionConfig)['builder'], (NonNullable<SelectMapType[keyof SelectMapType]> & BuilderCollectionConfig)['min'], (NonNullable<SelectMapType[keyof SelectMapType]> & BuilderCollectionConfig)['max']> : never;
|
|
33
|
-
type CollectionConfigNullable<Config extends BuilderCollectionWhenConfig> = Config extends BuilderCollectionUnlessConfig ? null : Config extends BuilderCollectionMatchConfig<infer SelectMapType> ? null extends SelectMapType[keyof SelectMapType] ? null : never : never;
|
|
34
|
-
type CollectionGatePathsNullable<Model, GatePaths extends BuilderPaths> = GatePaths extends readonly [infer Head extends BuilderPath, ...infer Tail extends BuilderPaths] ? null extends BuilderResolvePath<Model, Head> ? null : CollectionGatePathsNullable<Model, Tail> : never;
|
|
35
|
-
type CollectionWhenNullability<Model, GatePaths extends BuilderPaths, Config extends BuilderCollectionWhenConfig> = CollectionGatePathsNullable<Model, GatePaths> | CollectionConfigNullable<Config>;
|
|
36
|
-
type CollectionWhenConfigConstrained<Model, Config extends BuilderCollectionWhenConfig> = Config extends BuilderCollectionMatchConfig ? Config & {
|
|
37
|
-
readonly matchPath: Readonly<BuilderValidPath<Model>>;
|
|
38
|
-
} : Config extends BuilderCollectionUnlessConfig ? Config & {
|
|
39
|
-
readonly unlessPath: Readonly<BuilderValidPath<Model>>;
|
|
40
|
-
} : Config;
|
|
41
10
|
export type BuilderCollectionMethod<State extends BuilderState> = {
|
|
42
|
-
<const Name extends string, const CollectionRecipe extends BuilderGeneric, const Min extends number, const Max extends number>(name: Name, collectionRecipe: CollectionRecipe, min?: Min, max?: Max):
|
|
11
|
+
<const Name extends string, const CollectionRecipe extends BuilderGeneric, const Min extends number, const Max extends number>(name: Name, collectionRecipe: CollectionRecipe, min?: Min, max?: Max): BuilderMerge<State, {
|
|
43
12
|
model: State['model'] & Record<Name, BuilderCollectionModelOf<CollectionRecipe, Min, Max>>;
|
|
44
13
|
collections: [...State['collections'], BuilderCollection<Name, CollectionRecipe, Min, Max>];
|
|
45
|
-
}
|
|
46
|
-
when: <const GatePaths extends
|
|
47
|
-
model: State['model'] & Record<Name, CollectionWhenConfigModel<Config> |
|
|
14
|
+
}>;
|
|
15
|
+
when: <const GatePaths extends BuilderValidPaths<State['model']>, const Name extends string, const Config extends BuilderCollectionWhenConfig>(gatePaths: GatePaths, name: Name, config: Config & WhenConfigConstrained<State['model'], Config>) => BuilderMerge<State, {
|
|
16
|
+
model: State['model'] & Record<Name, CollectionWhenConfigModel<Config> | WhenNullability<State['model'], GatePaths, Config>>;
|
|
48
17
|
collections: [...State['collections'], CollectionWhenConfigResolver<Name, Config>];
|
|
49
|
-
}
|
|
18
|
+
}>;
|
|
19
|
+
};
|
|
20
|
+
export declare const collection: {
|
|
21
|
+
enable: <const CollectionRecipe extends BuilderGeneric, const Min extends number, const Max extends number>(builder: CollectionRecipe, min: Min, max: Max) => BuilderCollectionEnableConfig<CollectionRecipe, Min, Max>;
|
|
22
|
+
match: <const MatchPath extends BuilderPath, const SelectMap extends Record<string, BuilderCollectionConfig | null>>(matchPath: MatchPath, selectMap: SelectMap) => BuilderCollectionMatchConfig<SelectMap, MatchPath>;
|
|
23
|
+
unless: <const CollectionRecipe extends BuilderGeneric, const Min extends number, const Max extends number, const UnlessPath extends BuilderPath>(unlessPath: UnlessPath, disabledValues: ReadonlyArray<BuilderPrimitive>, builder: CollectionRecipe, min: Min, max: Max) => BuilderCollectionUnlessConfig<CollectionRecipe, Min, Max, UnlessPath>;
|
|
50
24
|
};
|
|
25
|
+
type SelectMapEntryOf<SelectMap> = NonNullable<SelectMap[keyof SelectMap]> & BuilderCollectionConfig;
|
|
26
|
+
type CollectionModelOfConfig<Config extends BuilderCollectionConfig> = BuilderCollectionModelOf<Config['builder'], Config['min'], Config['max']>;
|
|
27
|
+
type CollectionOfConfig<Name extends string, Config extends BuilderCollectionConfig> = BuilderCollection<Name, Config['builder'], Config['min'], Config['max']>;
|
|
28
|
+
type CollectionWhenConfigModel<Config extends BuilderCollectionWhenConfig> = Config extends BuilderCollectionEnableConfig<infer BuilderInput extends BuilderGeneric, infer Min extends number, infer Max extends number> ? BuilderCollectionModelOf<BuilderInput, Min, Max> : Config extends BuilderCollectionUnlessConfig<infer BuilderInput extends BuilderGeneric, infer Min extends number, infer Max extends number> ? BuilderCollectionModelOf<BuilderInput, Min, Max> : Config extends BuilderCollectionMatchConfig<infer SelectMapType> ? CollectionModelOfConfig<SelectMapEntryOf<SelectMapType>> : never;
|
|
29
|
+
type CollectionWhenConfigResolver<Name extends string, Config extends BuilderCollectionWhenConfig> = Config extends BuilderCollectionEnableConfig<infer BuilderInput, infer Min extends number, infer Max extends number> ? BuilderCollection<Name, BuilderInput, Min, Max> : Config extends BuilderCollectionUnlessConfig<infer BuilderInput, infer Min extends number, infer Max extends number> ? BuilderCollection<Name, BuilderInput, Min, Max> : Config extends BuilderCollectionMatchConfig<infer SelectMapType> ? CollectionOfConfig<Name, SelectMapEntryOf<SelectMapType>> : never;
|
|
51
30
|
export {};
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import type { BuilderPaths } from '../../paths';
|
|
2
2
|
export type BuilderComponentEntries = ReadonlyArray<BuilderComponent>;
|
|
3
3
|
export type BuilderComponentMap = Record<string, BuilderComponent>;
|
|
4
|
-
export type BuilderComponentNamesOf<Components extends BuilderComponentEntries> = Components
|
|
5
|
-
...infer Init extends BuilderComponentEntries,
|
|
6
|
-
BuilderComponent<infer Name>
|
|
7
|
-
] ? Name | BuilderComponentNamesOf<Init> : never;
|
|
4
|
+
export type BuilderComponentNamesOf<Components extends BuilderComponentEntries> = Components[number]['name'];
|
|
8
5
|
export declare class BuilderComponent<const Name extends string = string> {
|
|
9
6
|
readonly name: Name;
|
|
10
7
|
readonly paths: BuilderPaths;
|
|
@@ -5,9 +5,6 @@ export declare class BuilderComponentGraph {
|
|
|
5
5
|
#private;
|
|
6
6
|
readonly paths: GraphPaths;
|
|
7
7
|
constructor(paths?: GraphPaths);
|
|
8
|
-
static merge(...graphs: ComponentGraphs): BuilderComponentGraph;
|
|
9
8
|
has(name: string): boolean;
|
|
10
9
|
add(component: BuilderComponent, options: BuilderOptionGraph): BuilderComponentGraph;
|
|
11
10
|
}
|
|
12
|
-
type ComponentGraphs = ReadonlyArray<BuilderComponentGraph>;
|
|
13
|
-
export {};
|
|
@@ -1,19 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { check } from '../../check.js';
|
|
2
|
+
import { crossProduct } from '../graph.js';
|
|
2
3
|
import { BuilderComponent } from './component.js';
|
|
3
|
-
const EMPTY_MODEL = '{}';
|
|
4
4
|
export class BuilderComponentGraph {
|
|
5
5
|
paths;
|
|
6
6
|
constructor(paths = []) {
|
|
7
7
|
this.paths = paths;
|
|
8
8
|
}
|
|
9
|
-
static merge(...graphs) {
|
|
10
|
-
return new BuilderComponentGraph(graphs.flatMap((graph) => graph.paths));
|
|
11
|
-
}
|
|
12
9
|
has(name) {
|
|
13
10
|
return this.paths.some((graphPath) => graphPath.name === name);
|
|
14
11
|
}
|
|
15
12
|
add(component, options) {
|
|
16
|
-
|
|
13
|
+
check.falsy(this.has(component.name), `Duplicate component name '${component.name}'! ❌`);
|
|
17
14
|
const keys = new Set(component.paths.map((path) => String(path[0])));
|
|
18
15
|
const models = this.#mergeModels(keys, options);
|
|
19
16
|
const newPath = { name: component.name, keys, models };
|
|
@@ -30,7 +27,7 @@ export class BuilderComponentGraph {
|
|
|
30
27
|
Array.from(graphPath.keys).every((key) => handledKeys.has(key));
|
|
31
28
|
if (!isHandled) {
|
|
32
29
|
const componentModels = this.#createModels(graphPath, keys);
|
|
33
|
-
models = models
|
|
30
|
+
models = crossProduct(models, componentModels);
|
|
34
31
|
handledKeys.add(graphPath.name);
|
|
35
32
|
graphPath.keys.forEach((key) => handledKeys.add(key));
|
|
36
33
|
}
|
|
@@ -40,8 +37,8 @@ export class BuilderComponentGraph {
|
|
|
40
37
|
#createModels(graphPath, keys) {
|
|
41
38
|
const seen = new Set();
|
|
42
39
|
const models = [];
|
|
43
|
-
graphPath.models.forEach((
|
|
44
|
-
const picked = Object.fromEntries(Object.entries(
|
|
40
|
+
graphPath.models.forEach((model) => {
|
|
41
|
+
const picked = Object.fromEntries(Object.entries(model).filter(([key, value]) => keys.has(key) && value != null));
|
|
45
42
|
const identity = JSON.stringify(picked);
|
|
46
43
|
if (identity !== EMPTY_MODEL && !seen.has(identity)) {
|
|
47
44
|
seen.add(identity);
|
|
@@ -51,3 +48,4 @@ export class BuilderComponentGraph {
|
|
|
51
48
|
return models;
|
|
52
49
|
}
|
|
53
50
|
}
|
|
51
|
+
const EMPTY_MODEL = '{}';
|
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
4
|
-
import type { Builder } from '../builder';
|
|
5
|
-
import type { BuilderComponent } from './component';
|
|
1
|
+
import type { BuilderValidPaths } from '../../paths';
|
|
2
|
+
import type { BuilderMerge, BuilderState } from '../builder';
|
|
3
|
+
import type { BuilderComponent, BuilderComponentNamesOf } from './component';
|
|
6
4
|
export type BuilderComponentMethod<State extends BuilderState> = {
|
|
7
|
-
<const Name extends string>(name: Name, paths:
|
|
5
|
+
<const Name extends string>(name: Name, paths: BuilderValidPaths<State['model']>): BuilderMerge<State, {
|
|
8
6
|
components: [...State['components'], BuilderComponent<Name>];
|
|
9
|
-
}
|
|
10
|
-
when: <const Name extends string>(dependencies: ReadonlyArray<BuilderComponentNamesOf<State['components']>>, name: Name, paths:
|
|
7
|
+
}>;
|
|
8
|
+
when: <const Name extends string>(dependencies: ReadonlyArray<BuilderComponentNamesOf<State['components']>>, name: Name, paths: BuilderValidPaths<State['model']>) => BuilderMerge<State, {
|
|
11
9
|
components: [...State['components'], BuilderComponent<Name>];
|
|
12
|
-
}
|
|
10
|
+
}>;
|
|
13
11
|
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { BuilderGeneric, BuilderMerge, BuilderStateOf } from './builder';
|
|
2
|
+
import type { Prettify } from '../prettify';
|
|
3
|
+
import { BuilderComponent } from './component/index.js';
|
|
4
|
+
export type BuilderExpectationKind = 'option' | 'component';
|
|
5
|
+
export type BuilderExpectationEntries = ReadonlyArray<BuilderExpectation>;
|
|
6
|
+
export type BuilderExpectations = readonly [
|
|
7
|
+
BuilderExpectation,
|
|
8
|
+
...ReadonlyArray<BuilderExpectation>
|
|
9
|
+
];
|
|
10
|
+
export type BuilderModelAsserted<BuilderInput extends BuilderGeneric, Expectations extends BuilderExpectations> = BuilderMerge<BuilderStateOf<BuilderInput>, {
|
|
11
|
+
model: ModelAssert<BuilderInput, Expectations>;
|
|
12
|
+
components: ComponentAssert<BuilderInput, Expectations>;
|
|
13
|
+
}>;
|
|
14
|
+
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
|
+
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 declare class BuilderExpectation<Name extends string = string, Value = unknown> {
|
|
17
|
+
readonly name: Name;
|
|
18
|
+
readonly kind: BuilderExpectationKind;
|
|
19
|
+
constructor(name: Name, kind: BuilderExpectationKind);
|
|
20
|
+
optional(): BuilderExpectation<Name, Value | null>;
|
|
21
|
+
validate(entries: ReadonlyArray<{
|
|
22
|
+
readonly name: string;
|
|
23
|
+
}>): void;
|
|
24
|
+
}
|
|
25
|
+
export declare const option: {
|
|
26
|
+
expect: <const Name extends string>(name: Name) => BuilderExpectation<Name, string>;
|
|
27
|
+
};
|
|
28
|
+
export declare const component: {
|
|
29
|
+
expect: <const Name extends string>(name: Name) => BuilderExpectation<Name, never>;
|
|
30
|
+
};
|
|
31
|
+
type ExpectedModel<Items extends ReadonlyArray<BuilderExpectation>> = Items extends readonly [
|
|
32
|
+
infer Head,
|
|
33
|
+
...infer Tail extends ReadonlyArray<BuilderExpectation>
|
|
34
|
+
] ? (Head extends BuilderExpectation<infer Name, infer Value> ? [Value] extends [never] ? unknown : Record<Name, Value> : unknown) & ExpectedModel<Tail> : unknown;
|
|
35
|
+
type ExpectedComponents<Items extends ReadonlyArray<BuilderExpectation>> = Items extends readonly [
|
|
36
|
+
infer Head,
|
|
37
|
+
...infer Tail extends ReadonlyArray<BuilderExpectation>
|
|
38
|
+
] ? Head extends BuilderExpectation<infer Name, ReadonlyArray<any>> ? [BuilderComponent<Name>, ...ExpectedComponents<Tail>] : ExpectedComponents<Tail> : [];
|
|
39
|
+
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BuilderComponent } from './component/index.js';
|
|
2
|
+
import { check } from '../check.js';
|
|
2
3
|
export class BuilderExpectation {
|
|
3
4
|
name;
|
|
4
5
|
kind;
|
|
@@ -10,7 +11,7 @@ export class BuilderExpectation {
|
|
|
10
11
|
return new BuilderExpectation(this.name, this.kind);
|
|
11
12
|
}
|
|
12
13
|
validate(entries) {
|
|
13
|
-
|
|
14
|
+
check.truthy(entries.some((entry) => entry.name === this.name), `assert: no \`${this.kind}\` named '${this.name}' exists in the builder config! ❌`);
|
|
14
15
|
}
|
|
15
16
|
}
|
|
16
17
|
export const option = {
|