@builder-builder/builder 0.0.10 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bb.d.ts +28 -0
- package/dist/bb.js +49 -0
- package/dist/check.d.ts +1 -1
- package/dist/check.js +4 -2
- package/dist/entities/builder/bind.d.ts +4 -85
- package/dist/entities/builder/bind.js +1 -9
- package/dist/entities/builder/builder.d.ts +17 -509
- package/dist/entities/builder/builder.js +19 -79
- package/dist/entities/builder/factory.d.ts +7 -0
- package/dist/entities/builder/factory.js +4 -0
- package/dist/entities/builder/index.d.ts +3 -6
- package/dist/entities/builder/index.js +1 -2
- package/dist/entities/collection/collection.d.ts +69 -19
- package/dist/entities/collection/collection.js +7 -25
- package/dist/entities/collection/config.d.ts +38 -1095
- package/dist/entities/collection/config.js +8 -8
- package/dist/entities/collection/expectation.d.ts +8 -4
- package/dist/entities/collection/index.d.ts +2 -2
- package/dist/entities/collection/when.d.ts +5 -4
- package/dist/entities/component/component.d.ts +264 -293
- package/dist/entities/component/component.js +5 -5
- package/dist/entities/component/details.d.ts +32 -57
- package/dist/entities/component/details.js +8 -8
- package/dist/entities/component/expectation.d.ts +7 -4
- package/dist/entities/component/expectation.js +0 -3
- package/dist/entities/component/field.d.ts +50 -0
- package/dist/entities/component/field.js +41 -0
- package/dist/entities/component/index.d.ts +4 -2
- package/dist/entities/component/index.js +2 -1
- package/dist/entities/component/when.d.ts +1 -1
- package/dist/entities/component/when.js +2 -2
- package/dist/entities/entry.d.ts +4 -0
- package/dist/entities/expectation.d.ts +10 -22
- package/dist/entities/expectation.js +2 -7
- package/dist/entities/index.d.ts +20 -17
- package/dist/entities/index.js +9 -8
- package/dist/entities/kind.d.ts +8 -5
- package/dist/entities/kind.js +3 -4
- package/dist/entities/model/bind.d.ts +83 -0
- package/dist/entities/model/expectation.d.ts +16 -0
- package/dist/entities/model/index.d.ts +7 -0
- package/dist/entities/model/index.js +2 -0
- package/dist/entities/model/methods.d.ts +57 -0
- package/dist/entities/{builder → model}/methods.js +8 -8
- package/dist/entities/model/model.d.ts +39 -0
- package/dist/entities/model/model.js +73 -0
- package/dist/entities/model/models.d.ts +39 -0
- package/dist/entities/model/models.js +14 -0
- package/dist/entities/{builder → model}/state.d.ts +10 -10
- package/dist/entities/option/index.d.ts +1 -1
- package/dist/entities/option/index.js +1 -1
- package/dist/entities/option/option.d.ts +210 -209
- package/dist/entities/option/option.js +5 -5
- package/dist/entities/option/select.d.ts +2 -12
- package/dist/entities/option/select.js +6 -3
- package/dist/entities/option/toggle.d.ts +2 -9
- package/dist/entities/option/toggle.js +3 -3
- package/dist/entities/option/values.d.ts +3 -21
- package/dist/entities/option/values.js +8 -2
- package/dist/entities/option/when.d.ts +5 -4
- package/dist/entities/refs.d.ts +6 -0
- package/dist/entities/refs.js +1 -0
- package/dist/entities/serialise.d.ts +388 -2919
- package/dist/entities/serialise.js +116 -17
- package/dist/entities/ui/describe.d.ts +22 -31
- package/dist/entities/ui/describe.js +1 -1
- package/dist/entities/ui/index.d.ts +2 -5
- package/dist/entities/ui/index.js +1 -2
- package/dist/entities/ui/page.d.ts +22 -31
- package/dist/entities/ui/page.js +1 -1
- package/dist/entities/ui/pages.d.ts +11 -8
- package/dist/entities/ui/pages.js +1 -1
- package/dist/entities/ui/ui.d.ts +22 -1194
- package/dist/entities/ui/ui.js +16 -28
- package/dist/entities/ui/uis.d.ts +5 -15
- package/dist/entities/ui/uis.js +12 -18
- package/dist/entities/validated.d.ts +35 -0
- package/dist/entities/validated.js +1 -0
- package/dist/entities/when.d.ts +64 -56
- package/dist/entities/when.js +1 -0
- package/dist/environment.d.ts +5 -0
- package/dist/environment.js +2 -0
- package/dist/exception.d.ts +8 -3
- package/dist/exception.js +3 -0
- package/dist/index.d.ts +21 -28
- package/dist/index.js +5 -13
- package/dist/instance.d.ts +56 -0
- package/dist/instance.js +10 -0
- package/dist/mappers/index.d.ts +7 -7
- package/dist/mappers/index.js +5 -4
- package/dist/mappers/instance.d.ts +3 -0
- package/dist/mappers/instance.js +35 -0
- package/dist/mappers/order.d.ts +6 -0
- package/dist/mappers/order.js +22 -0
- package/dist/mappers/render/pages.d.ts +4 -4
- package/dist/mappers/render/render.d.ts +2 -3
- package/dist/mappers/render/render.js +83 -78
- package/dist/mappers/resolve.d.ts +5 -9
- package/dist/mappers/resolve.js +25 -33
- package/dist/mappers/variants/index.d.ts +1 -0
- package/dist/mappers/variants/index.js +1 -0
- package/dist/mappers/variants/option-graph.d.ts +19 -0
- package/dist/mappers/{models → variants}/option-graph.js +33 -22
- package/dist/mappers/variants/variants.d.ts +3 -0
- package/dist/mappers/variants/variants.js +57 -0
- package/dist/private.d.ts +4 -0
- package/dist/private.js +4 -0
- package/dist/references.d.ts +13 -48
- package/dist/references.js +6 -14
- package/dist/serialisable.d.ts +1 -9
- package/dist/serialisable.js +2 -3
- package/dist/validate/brand.d.ts +14 -0
- package/dist/validate/brand.js +17 -0
- package/dist/validate/builder.d.ts +4 -0
- package/dist/validate/builder.js +27 -0
- package/dist/validate/expectations.d.ts +10 -0
- package/dist/validate/expectations.js +12 -0
- package/dist/validate/index.d.ts +18 -0
- package/dist/validate/index.js +9 -0
- package/dist/validate/instance.d.ts +19 -0
- package/dist/validate/instance.js +46 -0
- package/dist/validate/model.d.ts +36 -0
- package/dist/validate/model.js +196 -0
- package/dist/validate/resolve.d.ts +16 -0
- package/dist/validate/resolve.js +91 -0
- package/dist/validate/result.d.ts +8 -0
- package/dist/validate/result.js +4 -0
- package/dist/validate/ui.d.ts +8 -0
- package/dist/validate/ui.js +77 -0
- package/dist/validate/variants.d.ts +59 -0
- package/dist/validate/variants.js +102 -0
- package/package.json +5 -4
- package/dist/entities/bind.d.ts +0 -4
- package/dist/entities/bind.js +0 -44
- package/dist/entities/builder/builders.d.ts +0 -35
- package/dist/entities/builder/builders.js +0 -19
- package/dist/entities/builder/expectation.d.ts +0 -12
- package/dist/entities/builder/methods.d.ts +0 -58
- package/dist/entities/builder/validate.d.ts +0 -3
- package/dist/entities/builder/validate.js +0 -108
- package/dist/entities/errors.d.ts +0 -21
- package/dist/entities/ui/bind.d.ts +0 -10
- package/dist/entities/ui/bind.js +0 -9
- package/dist/entities/ui/validate.d.ts +0 -8
- package/dist/entities/ui/validate.js +0 -21
- package/dist/entities/validate.d.ts +0 -28
- package/dist/mappers/assert/builder.d.ts +0 -2
- package/dist/mappers/assert/builder.js +0 -46
- package/dist/mappers/assert/expectation.d.ts +0 -2
- package/dist/mappers/assert/expectation.js +0 -23
- package/dist/mappers/assert/index.d.ts +0 -6
- package/dist/mappers/assert/index.js +0 -4
- package/dist/mappers/assert/model.d.ts +0 -13
- package/dist/mappers/assert/model.js +0 -47
- package/dist/mappers/assert/models.d.ts +0 -33
- package/dist/mappers/assert/models.js +0 -74
- package/dist/mappers/assert/ui.d.ts +0 -2
- package/dist/mappers/assert/ui.js +0 -22
- package/dist/mappers/instance/index.d.ts +0 -1
- package/dist/mappers/instance/index.js +0 -1
- package/dist/mappers/instance/instance.d.ts +0 -4
- package/dist/mappers/instance/instance.js +0 -33
- package/dist/mappers/models/component-graph.d.ts +0 -9
- package/dist/mappers/models/component-graph.js +0 -51
- package/dist/mappers/models/graph.d.ts +0 -12
- package/dist/mappers/models/graph.js +0 -17
- package/dist/mappers/models/index.d.ts +0 -1
- package/dist/mappers/models/index.js +0 -1
- package/dist/mappers/models/models.d.ts +0 -3
- package/dist/mappers/models/models.js +0 -37
- package/dist/mappers/models/option-graph.d.ts +0 -9
- package/dist/mappers/order/index.d.ts +0 -2
- package/dist/mappers/order/index.js +0 -1
- package/dist/mappers/order/order.d.ts +0 -14
- package/dist/mappers/order/order.js +0 -31
- package/dist/mappers/refs.d.ts +0 -12
- package/dist/mappers/refs.js +0 -36
- package/dist/model.d.ts +0 -35
- package/dist/model.js +0 -9
- package/dist/walker/index.d.ts +0 -2
- package/dist/walker/index.js +0 -1
- package/dist/walker/walkable.d.ts +0 -4
- package/dist/walker/walkable.js +0 -4
- package/dist/walker/walker.d.ts +0 -26
- package/dist/walker/walker.js +0 -115
- package/dist/walker/walkers.d.ts +0 -9
- package/dist/walker/walkers.js +0 -55
- /package/dist/entities/{builder/expectation.js → entry.js} +0 -0
- /package/dist/entities/{builder/state.js → model/bind.js} +0 -0
- /package/dist/entities/{errors.js → model/expectation.js} +0 -0
- /package/dist/entities/{validate.js → model/state.js} +0 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import * as v from 'valibot';
|
|
2
|
+
import { type BuilderPrimitive } from './primitive.js';
|
|
3
|
+
export type BuilderInstance = {
|
|
4
|
+
readonly [key: string]: BuilderPrimitive | BuilderInstances;
|
|
5
|
+
};
|
|
6
|
+
export declare const BuilderInstanceSchema: v.GenericSchema<BuilderInstance>;
|
|
7
|
+
export declare const BuilderInstancesSchema: v.SchemaWithPipe<readonly [v.ArraySchema<v.GenericSchema<BuilderInstance>, undefined>, v.ReadonlyAction<BuilderInstance[]>]>;
|
|
8
|
+
export type BuilderInstances = v.InferOutput<typeof BuilderInstancesSchema>;
|
|
9
|
+
export type BuilderInstanceInput = Readonly<Record<string, unknown>>;
|
|
10
|
+
export declare const BuilderVariantSchema: v.SchemaWithPipe<readonly [v.ObjectSchema<{
|
|
11
|
+
readonly instance: v.GenericSchema<BuilderInstance>;
|
|
12
|
+
readonly details: v.OptionalSchema<v.RecordSchema<v.StringSchema<undefined>, v.NullableSchema<v.UnionSchema<[v.StringSchema<undefined>, v.BooleanSchema<undefined>, v.NumberSchema<undefined>], undefined>, undefined>, undefined>, undefined>;
|
|
13
|
+
}, undefined>, v.ReadonlyAction<{
|
|
14
|
+
instance: BuilderInstance;
|
|
15
|
+
details?: {
|
|
16
|
+
[x: string]: string | number | boolean | null;
|
|
17
|
+
} | undefined;
|
|
18
|
+
}>]>;
|
|
19
|
+
export type BuilderVariant = v.InferOutput<typeof BuilderVariantSchema>;
|
|
20
|
+
export declare const BuilderVariantsSchema: v.SchemaWithPipe<readonly [v.ArraySchema<v.SchemaWithPipe<readonly [v.ObjectSchema<{
|
|
21
|
+
readonly instance: v.GenericSchema<BuilderInstance>;
|
|
22
|
+
readonly details: v.OptionalSchema<v.RecordSchema<v.StringSchema<undefined>, v.NullableSchema<v.UnionSchema<[v.StringSchema<undefined>, v.BooleanSchema<undefined>, v.NumberSchema<undefined>], undefined>, undefined>, undefined>, undefined>;
|
|
23
|
+
}, undefined>, v.ReadonlyAction<{
|
|
24
|
+
instance: BuilderInstance;
|
|
25
|
+
details?: {
|
|
26
|
+
[x: string]: string | number | boolean | null;
|
|
27
|
+
} | undefined;
|
|
28
|
+
}>]>, undefined>, v.ReadonlyAction<Readonly<{
|
|
29
|
+
instance: BuilderInstance;
|
|
30
|
+
details?: {
|
|
31
|
+
[x: string]: string | number | boolean | null;
|
|
32
|
+
} | undefined;
|
|
33
|
+
}>[]>]>;
|
|
34
|
+
export type BuilderVariants = v.InferOutput<typeof BuilderVariantsSchema>;
|
|
35
|
+
export declare const BuilderComponentVariantsSchema: v.SchemaWithPipe<readonly [v.RecordSchema<v.StringSchema<undefined>, v.SchemaWithPipe<readonly [v.ArraySchema<v.SchemaWithPipe<readonly [v.ObjectSchema<{
|
|
36
|
+
readonly instance: v.GenericSchema<BuilderInstance>;
|
|
37
|
+
readonly details: v.OptionalSchema<v.RecordSchema<v.StringSchema<undefined>, v.NullableSchema<v.UnionSchema<[v.StringSchema<undefined>, v.BooleanSchema<undefined>, v.NumberSchema<undefined>], undefined>, undefined>, undefined>, undefined>;
|
|
38
|
+
}, undefined>, v.ReadonlyAction<{
|
|
39
|
+
instance: BuilderInstance;
|
|
40
|
+
details?: {
|
|
41
|
+
[x: string]: string | number | boolean | null;
|
|
42
|
+
} | undefined;
|
|
43
|
+
}>]>, undefined>, v.ReadonlyAction<Readonly<{
|
|
44
|
+
instance: BuilderInstance;
|
|
45
|
+
details?: {
|
|
46
|
+
[x: string]: string | number | boolean | null;
|
|
47
|
+
} | undefined;
|
|
48
|
+
}>[]>]>, undefined>, v.ReadonlyAction<{
|
|
49
|
+
readonly [x: string]: readonly Readonly<{
|
|
50
|
+
instance: BuilderInstance;
|
|
51
|
+
details?: {
|
|
52
|
+
[x: string]: string | number | boolean | null;
|
|
53
|
+
} | undefined;
|
|
54
|
+
}>[];
|
|
55
|
+
}>]>;
|
|
56
|
+
export type BuilderComponentVariants = v.InferOutput<typeof BuilderComponentVariantsSchema>;
|
package/dist/instance.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as v from 'valibot';
|
|
2
|
+
import { BuilderPrimitiveSchema } from './primitive.js';
|
|
3
|
+
export const BuilderInstanceSchema = v.pipe(v.record(v.string(), v.union([BuilderPrimitiveSchema, v.lazy(() => BuilderInstancesSchema)])), v.readonly());
|
|
4
|
+
export const BuilderInstancesSchema = v.pipe(v.array(BuilderInstanceSchema), v.readonly());
|
|
5
|
+
export const BuilderVariantSchema = v.pipe(v.object({
|
|
6
|
+
instance: BuilderInstanceSchema,
|
|
7
|
+
details: v.optional(v.record(v.string(), BuilderPrimitiveSchema))
|
|
8
|
+
}), v.readonly());
|
|
9
|
+
export const BuilderVariantsSchema = v.pipe(v.array(BuilderVariantSchema), v.readonly());
|
|
10
|
+
export const BuilderComponentVariantsSchema = v.pipe(v.record(v.string(), BuilderVariantsSchema), v.readonly());
|
package/dist/mappers/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export type { BuilderErrorInvalidCollection, BuilderErrorInvalidOption, BuilderErrorInvalidVariant, BuilderErrorMissingComponent, BuilderErrorMissingDetail, BuilderErrorMissingVariant, BuilderErrorUnexpectedComponent, BuilderErrorUnexpectedDetail } from '
|
|
2
|
-
export type { BuilderOrder } from './order
|
|
3
|
-
export type { BuilderRefEntities, BuilderRefEntity } from './refs';
|
|
1
|
+
export type { BuilderComponentVariantsValidationResult, BuilderErrorDuplicateName, BuilderErrorInvalidCollection, BuilderErrorInvalidCollectionBounds, BuilderErrorInvalidDetail, BuilderErrorInvalidInput, BuilderErrorInvalidOption, BuilderErrorInvalidPath, BuilderErrorInvalidPathReason, BuilderErrorInvalidSelectMapKey, BuilderErrorInvalidVariant, BuilderErrorMissingComponent, BuilderErrorMissingDetail, BuilderErrorMissingReference, BuilderErrorMissingVariant, BuilderErrorUnboundParameter, BuilderErrorUnexpectedComponent, BuilderErrorUnexpectedDetail, BuilderErrorUnmetExpectation, BuilderErrorUnvalidated, BuilderInstanceValidationResult, BuilderModelValidationResult, BuilderUIValidationResult, BuilderValidationResult, BuilderVariantsValidationOptions } from '../validate/index';
|
|
2
|
+
export type { BuilderOrder } from './order';
|
|
4
3
|
export type { BuilderRenderOption, BuilderRenderOptions, BuilderRenderPage, BuilderRenderPages, BuilderRenderResult, BuilderRenderUpdate } from './render/index';
|
|
5
|
-
export {
|
|
6
|
-
export {
|
|
7
|
-
export {
|
|
8
|
-
export {
|
|
4
|
+
export { assertValidated, validateBuilder, validateInstance, validateModel, validateUI, validateVariants } from '../validate/index.js';
|
|
5
|
+
export { createInstance } from './instance.js';
|
|
6
|
+
export { createVariants } from './variants/index.js';
|
|
7
|
+
export { order } from './order.js';
|
|
9
8
|
export { ordinal, render } from './render/index.js';
|
|
9
|
+
export { resolveCollection, resolveComponent, resolveOption } from './resolve.js';
|
package/dist/mappers/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
1
|
+
export { assertValidated, validateBuilder, validateInstance, validateModel, validateUI, validateVariants } from '../validate/index.js';
|
|
2
|
+
export { createInstance } from './instance.js';
|
|
3
|
+
export { createVariants } from './variants/index.js';
|
|
4
|
+
export { order } from './order.js';
|
|
5
5
|
export { ordinal, render } from './render/index.js';
|
|
6
|
+
export { resolveCollection, resolveComponent, resolveOption } from './resolve.js';
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { BuilderModelValidated, BuilderRefEntities, BuilderValidated } from '../entities/index';
|
|
2
|
+
import type { BuilderInstance, BuilderInstanceInput } from '../instance';
|
|
3
|
+
export declare function createInstance(entity: BuilderValidated | BuilderModelValidated, partial?: BuilderInstanceInput, refs?: BuilderRefEntities): BuilderInstance;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { check } from '../check.js';
|
|
2
|
+
import { optionValueSchema } from '../entities/index.js';
|
|
3
|
+
import { resolveCollection, resolveOption } from './resolve.js';
|
|
4
|
+
export function createInstance(entity, partial = {}, refs = []) {
|
|
5
|
+
const model = 'model' in entity ? entity.model : entity;
|
|
6
|
+
return buildInstance(model, partial, refs);
|
|
7
|
+
}
|
|
8
|
+
function buildInstance(model, partial, refs) {
|
|
9
|
+
let instance = { ...partial };
|
|
10
|
+
model.options.forEach((option) => {
|
|
11
|
+
const { name } = option;
|
|
12
|
+
const payload = resolveOption(option, instance, refs);
|
|
13
|
+
if (payload == null) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const existing = instance[name];
|
|
17
|
+
if (check.is(optionValueSchema(payload), existing)) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
instance = { ...instance, [name]: payload.defaultValue };
|
|
21
|
+
});
|
|
22
|
+
model.collections.forEach((collection) => {
|
|
23
|
+
const { name } = collection;
|
|
24
|
+
const payload = resolveCollection(collection, instance, refs);
|
|
25
|
+
if (payload == null) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const existing = instance[name];
|
|
29
|
+
const existingItems = Array.isArray(existing) ? existing : [];
|
|
30
|
+
const count = Math.max(existingItems.length, payload.min);
|
|
31
|
+
const items = Array.from({ length: count }, (_, index) => buildInstance(payload.model, existingItems[index] ?? {}, refs));
|
|
32
|
+
instance = { ...instance, [name]: items };
|
|
33
|
+
});
|
|
34
|
+
return instance;
|
|
35
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { BuilderComponentVariantsValidated, BuilderInstanceValidated, BuilderModelValidated, BuilderRefEntities } from '../entities/index';
|
|
2
|
+
import type { BuilderVariant } from '../instance';
|
|
3
|
+
export interface BuilderOrder {
|
|
4
|
+
readonly [key: string]: BuilderVariant | BuilderOrder | ReadonlyArray<BuilderOrder> | null;
|
|
5
|
+
}
|
|
6
|
+
export declare function order(model: BuilderModelValidated, instance: BuilderInstanceValidated, variants: BuilderComponentVariantsValidated, refs?: BuilderRefEntities): BuilderOrder;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { resolveCollection, resolveComponent } from './resolve.js';
|
|
2
|
+
export function order(model, instance, variants, refs = []) {
|
|
3
|
+
const result = {};
|
|
4
|
+
model.components.forEach((component) => {
|
|
5
|
+
if (resolveComponent(component, instance, refs) == null) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
const componentVariants = variants[component.name] ?? [];
|
|
9
|
+
result[component.name] =
|
|
10
|
+
componentVariants.find((variant) => Object.entries(variant.instance).every(([key, value]) => instance[key] === value)) ?? null;
|
|
11
|
+
});
|
|
12
|
+
model.collections.forEach((collection) => {
|
|
13
|
+
const { name } = collection;
|
|
14
|
+
const payload = resolveCollection(collection, instance, refs);
|
|
15
|
+
if (payload == null) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const itemInstances = instance[name];
|
|
19
|
+
result[name] = itemInstances.map((itemInstance) => order(payload.model, itemInstance, variants, refs));
|
|
20
|
+
});
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { BuilderOptionValuesSerialised } from '../../entities/index';
|
|
2
2
|
import type { BuilderPrimitive } from '../../primitive';
|
|
3
|
-
import type {
|
|
4
|
-
export type BuilderRenderUpdate = (model:
|
|
3
|
+
import type { BuilderInstance } from '../../instance';
|
|
4
|
+
export type BuilderRenderUpdate = (model: BuilderInstance, primitive: BuilderPrimitive) => BuilderInstance;
|
|
5
5
|
export type BuilderRenderOption = Readonly<{
|
|
6
6
|
value: BuilderPrimitive;
|
|
7
7
|
update: BuilderRenderUpdate;
|
|
8
|
-
option:
|
|
8
|
+
option: BuilderOptionValuesSerialised;
|
|
9
9
|
}>;
|
|
10
10
|
export type BuilderRenderOptions = ReadonlyArray<BuilderRenderOption>;
|
|
11
11
|
export type BuilderRenderPage = Readonly<{
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import type { BuilderDescription,
|
|
2
|
-
import type { BuilderModel } from '../../model';
|
|
1
|
+
import type { BuilderDescription, BuilderInstanceValidated, BuilderRefEntities, BuilderValidated } from '../../entities/index';
|
|
3
2
|
import type { BuilderRenderPages } from './pages';
|
|
4
3
|
export type BuilderRenderResult = Readonly<{
|
|
5
4
|
layout: BuilderRenderPages;
|
|
6
5
|
description: BuilderDescription;
|
|
7
6
|
}>;
|
|
8
|
-
export declare function render(
|
|
7
|
+
export declare function render(builder: BuilderValidated, instance: BuilderInstanceValidated, refs?: BuilderRefEntities): BuilderRenderResult;
|
|
@@ -1,112 +1,117 @@
|
|
|
1
1
|
import * as v from 'valibot';
|
|
2
|
-
import { assertModel, assertUI } from '../assert/index.js';
|
|
3
2
|
import { check } from '../../check.js';
|
|
3
|
+
import { BuilderInstancesSchema } from '../../instance.js';
|
|
4
4
|
import { readPath } from '../../paths.js';
|
|
5
|
-
import { resolveCollection, resolveOption } from '../resolve.js';
|
|
5
|
+
import { resolveCollection, resolveOption, resolveRef } from '../resolve.js';
|
|
6
6
|
import { ordinal } from './ordinal.js';
|
|
7
|
-
export function render(
|
|
8
|
-
assertUI(ui);
|
|
9
|
-
const rootBuilder = ui.builder;
|
|
10
|
-
assertModel(rootBuilder, rootModel);
|
|
7
|
+
export function render(builder, instance, refs = []) {
|
|
11
8
|
const layout = [];
|
|
12
9
|
const description = [];
|
|
13
|
-
|
|
10
|
+
walkTree(builder.ui);
|
|
14
11
|
return { layout, description };
|
|
15
|
-
function
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return `${labelContext.join(', ')}, ${label}`;
|
|
21
|
-
}
|
|
12
|
+
function walkTree(ui) {
|
|
13
|
+
ui.uis.forEach((nested) => walkTree(nested));
|
|
14
|
+
walkItems(ui.items, builder.model, [], [], instance);
|
|
15
|
+
}
|
|
16
|
+
function walkItems(items, model, collectionPath, labelContext, currentInstance) {
|
|
22
17
|
items.forEach((item) => {
|
|
23
|
-
if (item.type === 'pages') {
|
|
24
|
-
const collection = findCollection(builder, model, item.name);
|
|
25
|
-
if (!collection) {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
const models = model[collection.name];
|
|
29
|
-
models.forEach((collectionModel, itemIndex) => {
|
|
30
|
-
const labelSegment = `${ordinal(itemIndex)} ${item.label}`;
|
|
31
|
-
walk(collection.payload.builder, collectionModel, [...collectionPath, item.name, itemIndex], [...labelContext, labelSegment], item.items);
|
|
32
|
-
});
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
18
|
if (item.type === 'page') {
|
|
36
|
-
|
|
37
|
-
const option = findResolvedOption(builder, model, path);
|
|
38
|
-
if (!option) {
|
|
39
|
-
return [];
|
|
40
|
-
}
|
|
41
|
-
const fullPath = [...collectionPath, ...path];
|
|
42
|
-
return [
|
|
43
|
-
{
|
|
44
|
-
option: option.payload,
|
|
45
|
-
value: readPath(model, fullPath),
|
|
46
|
-
update: (updateModel, updateValue) => setPath(updateModel, fullPath, updateValue)
|
|
47
|
-
}
|
|
48
|
-
];
|
|
49
|
-
});
|
|
50
|
-
if (options.length === 0) {
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
layout.push({ label: composeLabel(item.label), options });
|
|
19
|
+
emitPage(item, model, collectionPath, labelContext, currentInstance);
|
|
54
20
|
return;
|
|
55
21
|
}
|
|
56
22
|
if (item.type === 'describe') {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
23
|
+
emitDescribe(item, model, labelContext, currentInstance);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const collection = findCollection(model, currentInstance, item.name);
|
|
27
|
+
if (collection == null) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const itemInstances = currentInstance[item.name];
|
|
31
|
+
check.assert(BuilderInstancesSchema, itemInstances, 'Collection field is not an array! ❌');
|
|
32
|
+
itemInstances.forEach((itemInstance, index) => {
|
|
33
|
+
walkItems(item.items, collection.model, [...collectionPath, item.name, index], [...labelContext, `${ordinal(index)} ${composeLabel(item.label)}`], itemInstance);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
function emitPage(page, model, collectionPath, labelContext, currentInstance) {
|
|
38
|
+
const options = page.paths.flatMap((path) => {
|
|
39
|
+
const option = findOption(model, currentInstance, path);
|
|
40
|
+
if (option == null) {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
const fullPath = [...collectionPath, ...path];
|
|
44
|
+
return [
|
|
45
|
+
{
|
|
46
|
+
option,
|
|
47
|
+
value: readPath(currentInstance, path),
|
|
48
|
+
update: (updateInstance, updateValue) => setPath(updateInstance, fullPath, updateValue)
|
|
72
49
|
}
|
|
73
|
-
|
|
50
|
+
];
|
|
51
|
+
});
|
|
52
|
+
if (options.length === 0) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
layout.push({ label: composeLabel(page.label, labelContext), options });
|
|
56
|
+
}
|
|
57
|
+
function emitDescribe(describe, model, labelContext, currentInstance) {
|
|
58
|
+
const composedLabel = composeLabel(describe.label, labelContext);
|
|
59
|
+
const values = describe.paths.flatMap((path) => {
|
|
60
|
+
const option = findOption(model, currentInstance, path);
|
|
61
|
+
if (option == null) {
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
const value = readPath(currentInstance, path);
|
|
65
|
+
if (value == null) {
|
|
66
|
+
return [];
|
|
74
67
|
}
|
|
68
|
+
return [value];
|
|
75
69
|
});
|
|
70
|
+
if (values.length === 0) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
description.push([composedLabel, values.join(' ')]);
|
|
74
|
+
}
|
|
75
|
+
function composeLabel(label, labelContext = []) {
|
|
76
|
+
const resolved = resolveRef(label, refs);
|
|
77
|
+
check.assert(v.string(), resolved, 'Label did not resolve to a string! ❌');
|
|
78
|
+
if (labelContext.length === 0) {
|
|
79
|
+
return resolved;
|
|
80
|
+
}
|
|
81
|
+
return `${labelContext.join(', ')}, ${resolved}`;
|
|
76
82
|
}
|
|
77
|
-
function
|
|
83
|
+
function findOption(model, instance, path) {
|
|
78
84
|
const optionName = path.at(-1);
|
|
79
85
|
check.assert(v.string(), optionName);
|
|
80
86
|
const collectionPairs = path.slice(0, -1);
|
|
81
|
-
const
|
|
82
|
-
if (!
|
|
87
|
+
const descended = descendPairs(model, instance, collectionPairs);
|
|
88
|
+
if (!descended) {
|
|
83
89
|
return null;
|
|
84
90
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
91
|
+
const [scopeModel, scopeInstance] = descended;
|
|
92
|
+
const entry = scopeModel.options.find((option) => option.name === optionName);
|
|
93
|
+
return entry == null ? null : resolveOption(entry, scopeInstance, refs);
|
|
88
94
|
}
|
|
89
|
-
function descendPairs(
|
|
95
|
+
function descendPairs(model, instance, remaining) {
|
|
90
96
|
if (remaining.length === 0) {
|
|
91
|
-
return
|
|
97
|
+
return [model, instance];
|
|
92
98
|
}
|
|
93
|
-
const [collectionName,
|
|
99
|
+
const [collectionName, instanceIndex, ...rest] = remaining;
|
|
94
100
|
check.assert(v.string(), collectionName);
|
|
95
|
-
check.assert(v.number(),
|
|
96
|
-
const collection = findCollection(
|
|
101
|
+
check.assert(v.number(), instanceIndex);
|
|
102
|
+
const collection = findCollection(model, instance, collectionName);
|
|
97
103
|
if (!collection) {
|
|
98
104
|
return null;
|
|
99
105
|
}
|
|
100
|
-
const
|
|
101
|
-
if (!
|
|
106
|
+
const nextInstance = instance[collectionName].at(instanceIndex);
|
|
107
|
+
if (!nextInstance) {
|
|
102
108
|
return null;
|
|
103
109
|
}
|
|
104
|
-
return descendPairs(collection.
|
|
110
|
+
return descendPairs(collection.model, nextInstance, rest);
|
|
105
111
|
}
|
|
106
|
-
function findCollection(
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
.find((collection) => collection?.name === collectionName) ?? null);
|
|
112
|
+
function findCollection(model, instance, collectionName) {
|
|
113
|
+
const entry = model.collections.find((candidate) => candidate.name === collectionName);
|
|
114
|
+
return entry == null ? null : resolveCollection(entry, instance, refs);
|
|
110
115
|
}
|
|
111
116
|
}
|
|
112
117
|
function setPath(container, path, value) {
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export
|
|
5
|
-
export
|
|
6
|
-
export type BuilderCollectionResolved = BuilderCollection<string, BuilderCollectionConfig<BuilderValidated, number, number>, BuilderPaths>;
|
|
7
|
-
export declare function resolveOption(option: BuilderOptionValidated, model: unknown): BuilderOptionResolved | null;
|
|
8
|
-
export declare function resolveComponent(component: BuilderComponentValidated, model: unknown): BuilderComponentResolved | null;
|
|
9
|
-
export declare function resolveCollection(collection: BuilderCollectionValidated, model: unknown): BuilderCollectionResolved | null;
|
|
1
|
+
import type { BuilderCollectionConfigValidated, BuilderCollectionValidated, BuilderComponentDetailsSerialised, BuilderComponentValidated, BuilderOptionValidated, BuilderOptionValuesSerialised, BuilderRefEntities } from '../entities/index';
|
|
2
|
+
export declare function resolveOption(option: BuilderOptionValidated, model: unknown, refs?: BuilderRefEntities): BuilderOptionValuesSerialised | null;
|
|
3
|
+
export declare function resolveComponent(component: BuilderComponentValidated, model: unknown, refs?: BuilderRefEntities): BuilderComponentDetailsSerialised | null;
|
|
4
|
+
export declare function resolveCollection(collection: BuilderCollectionValidated, model: unknown, refs?: BuilderRefEntities): BuilderCollectionConfigValidated | null;
|
|
5
|
+
export declare function resolveRef(value: unknown, refs: BuilderRefEntities): unknown;
|
package/dist/mappers/resolve.js
CHANGED
|
@@ -1,41 +1,33 @@
|
|
|
1
1
|
import { check } from '../check.js';
|
|
2
|
-
import {
|
|
2
|
+
import { BuilderCollectionConfigSerialisedSchema, BuilderComponentDetailsSerialisedSchema, BuilderOptionValuesSerialisedSchema } from '../entities/index.js';
|
|
3
3
|
import { BuilderPathsSchema, readPath } from '../paths.js';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
8
|
-
check.assert(BuilderPathsSchema, option.gatePaths);
|
|
9
|
-
const result = resolveWhen(option.gatePaths, option.payload, model);
|
|
10
|
-
if (!result) {
|
|
11
|
-
return null;
|
|
12
|
-
}
|
|
13
|
-
return new BuilderOption(option.name, result);
|
|
4
|
+
import { BuilderRefSerialisedSchema } from '../references.js';
|
|
5
|
+
export function resolveOption(option, model, refs = []) {
|
|
6
|
+
return resolveEntry(option, BuilderOptionValuesSerialisedSchema, model, refs);
|
|
14
7
|
}
|
|
15
|
-
export function resolveComponent(component, model) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const result = resolveWhen(component.gatePaths, component.payload, model);
|
|
21
|
-
if (!result) {
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
24
|
-
return new BuilderComponent(component.name, result);
|
|
8
|
+
export function resolveComponent(component, model, refs = []) {
|
|
9
|
+
return resolveEntry(component, BuilderComponentDetailsSerialisedSchema, model, refs);
|
|
10
|
+
}
|
|
11
|
+
export function resolveCollection(collection, model, refs = []) {
|
|
12
|
+
return resolveEntry(collection, BuilderCollectionConfigSerialisedSchema, model, refs);
|
|
25
13
|
}
|
|
26
|
-
export function
|
|
27
|
-
if (check.is(
|
|
28
|
-
return
|
|
14
|
+
export function resolveRef(value, refs) {
|
|
15
|
+
if (!check.is(BuilderRefSerialisedSchema, value)) {
|
|
16
|
+
return value;
|
|
29
17
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
18
|
+
const found = refs.find((entry) => entry.id === value.id);
|
|
19
|
+
return found?.serialised ?? value;
|
|
20
|
+
}
|
|
21
|
+
function resolveEntry(entry, schema, model, refs = []) {
|
|
22
|
+
const payload = resolveRef(entry.payload, refs);
|
|
23
|
+
if (check.is(schema, payload)) {
|
|
24
|
+
return payload;
|
|
34
25
|
}
|
|
35
|
-
|
|
26
|
+
check.assert(BuilderPathsSchema, entry.paths);
|
|
27
|
+
return pickWhenBranch(payload, entry.paths, model);
|
|
36
28
|
}
|
|
37
|
-
function
|
|
38
|
-
if (!
|
|
29
|
+
function pickWhenBranch(config, gates, instance) {
|
|
30
|
+
if (!gates.every((path) => readPath(instance, path) != null)) {
|
|
39
31
|
return null;
|
|
40
32
|
}
|
|
41
33
|
switch (config.type) {
|
|
@@ -44,10 +36,10 @@ function resolveWhen(gatePaths, config, model) {
|
|
|
44
36
|
}
|
|
45
37
|
case 'match': {
|
|
46
38
|
const selectMap = config.selectMap;
|
|
47
|
-
return selectMap[`${readPath(
|
|
39
|
+
return selectMap[`${readPath(instance, config.matchPath)}`] ?? null;
|
|
48
40
|
}
|
|
49
41
|
case 'unless': {
|
|
50
|
-
const value = readPath(
|
|
42
|
+
const value = readPath(instance, config.unlessPath);
|
|
51
43
|
if (config.disabledValues.includes(value)) {
|
|
52
44
|
return null;
|
|
53
45
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createVariants } from './variants.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createVariants } from './variants.js';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { BuilderOptionValidated, BuilderWhen } from '../../entities/index';
|
|
2
|
+
import type { BuilderInstances } from '../../instance';
|
|
3
|
+
import type { BuilderPaths } from '../../paths';
|
|
4
|
+
export type GraphKeys = ReadonlySet<string>;
|
|
5
|
+
export type GraphPath = {
|
|
6
|
+
name: string;
|
|
7
|
+
keys: GraphKeys;
|
|
8
|
+
instances: BuilderInstances;
|
|
9
|
+
};
|
|
10
|
+
export type GraphPaths = ReadonlyArray<GraphPath>;
|
|
11
|
+
export declare function crossProduct(left: BuilderInstances, right: BuilderInstances): BuilderInstances;
|
|
12
|
+
export declare function dependencyKeys(payload: unknown | BuilderWhen, paths?: BuilderPaths): ReadonlyArray<string>;
|
|
13
|
+
export declare class BuilderOptionGraph {
|
|
14
|
+
#private;
|
|
15
|
+
readonly paths: GraphPaths;
|
|
16
|
+
constructor(paths?: GraphPaths);
|
|
17
|
+
get(name: string): GraphPath;
|
|
18
|
+
add(option: BuilderOptionValidated): BuilderOptionGraph;
|
|
19
|
+
}
|
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
import { check } from '../../check.js';
|
|
2
|
+
import { BuilderWhenMatchSchema, BuilderWhenUnlessSchema } from '../../entities/index.js';
|
|
2
3
|
import { resolveOption } from '../resolve.js';
|
|
3
|
-
|
|
4
|
+
export function crossProduct(left, right) {
|
|
5
|
+
return left.flatMap((leftModel) => right.map((rightModel) => ({ ...leftModel, ...rightModel })));
|
|
6
|
+
}
|
|
7
|
+
export function dependencyKeys(payload, paths = []) {
|
|
8
|
+
const keys = new Set(paths.map(([first]) => String(first)));
|
|
9
|
+
if (check.is(BuilderWhenMatchSchema, payload)) {
|
|
10
|
+
const [firstMatchSegment] = payload.matchPath;
|
|
11
|
+
keys.add(String(firstMatchSegment));
|
|
12
|
+
}
|
|
13
|
+
else if (check.is(BuilderWhenUnlessSchema, payload)) {
|
|
14
|
+
const [firstUnlessSegment] = payload.unlessPath;
|
|
15
|
+
keys.add(String(firstUnlessSegment));
|
|
16
|
+
}
|
|
17
|
+
return Array.from(keys);
|
|
18
|
+
}
|
|
4
19
|
export class BuilderOptionGraph {
|
|
5
20
|
paths;
|
|
6
21
|
constructor(paths = []) {
|
|
@@ -12,43 +27,39 @@ export class BuilderOptionGraph {
|
|
|
12
27
|
return graphPath;
|
|
13
28
|
}
|
|
14
29
|
add(option) {
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
const optionDependencyKeys = dependencyKeys(payload, gatePaths);
|
|
30
|
+
const { paths, payload } = option;
|
|
31
|
+
const optionDependencyKeys = dependencyKeys(payload, paths);
|
|
18
32
|
if (optionDependencyKeys.length === 0) {
|
|
19
|
-
const
|
|
20
|
-
check.truthy(
|
|
21
|
-
const values = this.#optionValues(
|
|
33
|
+
const payload = resolveOption(option, {});
|
|
34
|
+
check.truthy(payload, `Option '${option.name}' without dependencies must resolve! ❌`);
|
|
35
|
+
const values = this.#optionValues(option.name, payload);
|
|
22
36
|
return new BuilderOptionGraph([
|
|
23
37
|
...this.paths,
|
|
24
38
|
{
|
|
25
39
|
name: option.name,
|
|
26
40
|
keys: new Set(),
|
|
27
|
-
|
|
41
|
+
instances: values.map((value) => ({ [option.name]: value }))
|
|
28
42
|
}
|
|
29
43
|
]);
|
|
30
44
|
}
|
|
31
45
|
const merged = this.#mergePaths(new Set(optionDependencyKeys), this.paths);
|
|
32
|
-
const
|
|
33
|
-
merged.
|
|
34
|
-
const
|
|
35
|
-
if (
|
|
36
|
-
this.#optionValues(
|
|
37
|
-
|
|
46
|
+
const finalInstances = [];
|
|
47
|
+
merged.instances.forEach((instance) => {
|
|
48
|
+
const payload = resolveOption(option, instance);
|
|
49
|
+
if (payload) {
|
|
50
|
+
this.#optionValues(option.name, payload).forEach((value) => {
|
|
51
|
+
finalInstances.push({ ...instance, [option.name]: value });
|
|
38
52
|
});
|
|
39
53
|
}
|
|
40
54
|
else {
|
|
41
|
-
|
|
55
|
+
finalInstances.push({ ...instance });
|
|
42
56
|
}
|
|
43
57
|
});
|
|
44
58
|
return new BuilderOptionGraph([
|
|
45
59
|
...this.paths,
|
|
46
|
-
{ name: option.name, keys: merged.keys,
|
|
60
|
+
{ name: option.name, keys: merged.keys, instances: finalInstances }
|
|
47
61
|
]);
|
|
48
62
|
}
|
|
49
|
-
#has(name) {
|
|
50
|
-
return this.paths.some((graphPath) => graphPath.name === name);
|
|
51
|
-
}
|
|
52
63
|
#mergePaths(dependencyKeys, graphPaths) {
|
|
53
64
|
const dependencyPaths = Array.from(dependencyKeys).map((dependencyKey) => {
|
|
54
65
|
const dependencyPath = graphPaths.find((graphPath) => graphPath.name === dependencyKey);
|
|
@@ -58,9 +69,9 @@ export class BuilderOptionGraph {
|
|
|
58
69
|
const [first, ...rest] = dependencyPaths;
|
|
59
70
|
return rest.reduce((merged, next) => {
|
|
60
71
|
const keys = new Set([...merged.keys, ...next.keys, next.name]);
|
|
61
|
-
const
|
|
62
|
-
return { keys,
|
|
63
|
-
}, { keys: new Set([...first.keys, first.name]),
|
|
72
|
+
const instances = crossProduct(next.instances, merged.instances);
|
|
73
|
+
return { keys, instances };
|
|
74
|
+
}, { keys: new Set([...first.keys, first.name]), instances: first.instances });
|
|
64
75
|
}
|
|
65
76
|
#optionValues(name, values) {
|
|
66
77
|
if (values.type === 'select') {
|