@builder-builder/builder 0.0.25 → 0.0.26
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/client/schema.d.ts +4 -4
- package/dist/entities/builder/builder.js +2 -1
- package/dist/entities/collection/collection.js +2 -1
- package/dist/entities/collection/config.d.ts +20 -20
- package/dist/entities/collection/config.js +3 -2
- package/dist/entities/component/component.d.ts +30 -30
- package/dist/entities/component/component.js +2 -1
- package/dist/entities/component/config.d.ts +12 -12
- package/dist/entities/component/field.d.ts +4 -4
- package/dist/entities/component/field.js +4 -3
- package/dist/entities/expectation.d.ts +2 -2
- package/dist/entities/expectation.js +2 -1
- package/dist/entities/index.d.ts +1 -1
- package/dist/entities/kind.d.ts +1 -1
- package/dist/entities/kind.js +43 -3
- package/dist/entities/model/models.d.ts +3 -3
- package/dist/entities/option/config.d.ts +4 -4
- package/dist/entities/option/option.d.ts +22 -22
- package/dist/entities/option/option.js +2 -1
- package/dist/entities/option/select.d.ts +1 -1
- package/dist/entities/option/select.js +5 -4
- package/dist/entities/option/toggle.d.ts +1 -1
- package/dist/entities/option/toggle.js +4 -3
- package/dist/entities/paths.d.ts +2 -2
- package/dist/entities/paths.js +2 -1
- package/dist/entities/pricing/expression.js +5 -4
- package/dist/entities/pricing/rates.js +2 -1
- package/dist/entities/references.d.ts +2 -2
- package/dist/entities/references.js +2 -1
- package/dist/entities/serialise.d.ts +201 -113
- package/dist/entities/serialise.js +4 -3
- package/dist/entities/tags.d.ts +1 -1
- package/dist/entities/tags.js +2 -1
- package/dist/entities/ui/describe.d.ts +78 -34
- package/dist/entities/ui/describe.js +3 -2
- package/dist/entities/ui/input.d.ts +92 -48
- package/dist/entities/ui/input.js +5 -4
- package/dist/entities/ui/page.d.ts +76 -32
- package/dist/entities/ui/page.js +2 -1
- package/dist/entities/ui/pages.d.ts +3 -3
- package/dist/entities/ui/pages.js +3 -2
- package/dist/entities/validated.d.ts +1 -0
- package/dist/entities/when.d.ts +16 -16
- package/dist/entities/when.js +2 -2
- package/dist/errors/errors.d.ts +10 -0
- package/dist/errors/errors.js +6 -0
- package/dist/instance.d.ts +7 -7
- package/dist/instance.js +4 -4
- package/dist/mappers/index.d.ts +1 -1
- package/dist/mappers/price.js +1 -2
- package/dist/mappers/render/collection.d.ts +9 -0
- package/dist/mappers/render/collection.js +27 -0
- package/dist/mappers/render/compose.d.ts +5 -0
- package/dist/mappers/render/compose.js +15 -0
- package/dist/mappers/render/description.d.ts +3 -0
- package/dist/mappers/render/description.js +17 -0
- package/dist/mappers/render/index.d.ts +3 -1
- package/dist/mappers/render/option.d.ts +20 -0
- package/dist/mappers/render/option.js +25 -0
- package/dist/mappers/render/page.d.ts +11 -0
- package/dist/mappers/render/page.js +11 -0
- package/dist/mappers/render/paths.d.ts +3 -0
- package/dist/mappers/render/paths.js +21 -0
- package/dist/mappers/render/render.d.ts +1 -1
- package/dist/mappers/render/render.js +33 -98
- package/dist/mappers/resolve.d.ts +2 -1
- package/dist/mappers/resolve.js +24 -23
- package/dist/primitive.d.ts +5 -0
- package/dist/primitive.js +6 -1
- package/dist/public.d.ts +1 -1
- package/dist/references.d.ts +6 -6
- package/dist/references.js +3 -2
- package/dist/validate/model.js +16 -5
- package/dist/validate/paths.js +3 -5
- package/dist/validate/pricing.js +5 -6
- package/dist/validate/resolve.d.ts +2 -1
- package/dist/validate/resolve.js +87 -73
- package/dist/validate/ui.js +14 -13
- package/package.json +1 -1
- package/dist/mappers/render/pages.d.ts +0 -24
- package/dist/mappers/render/pages.js +0 -2
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { BuilderModelValidated, BuilderOptionConfigSerialised, BuilderPath, BuilderReferences, BuilderUIInputValidated, BuilderValidated } from '../../entities/index';
|
|
2
|
+
import type { BuilderInstance } from '../../instance';
|
|
3
|
+
import type { BuilderPrimitive } from '../../primitive';
|
|
4
|
+
import * as v from 'valibot';
|
|
5
|
+
export type BuilderRenderOptionUpdate = (instance: BuilderInstance, primitive: BuilderPrimitive) => BuilderInstance;
|
|
6
|
+
export declare const BuilderRenderMetadataSchema: v.SchemaWithPipe<readonly [v.RecordSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, v.UnknownSchema, undefined>, v.ReadonlyAction<{
|
|
7
|
+
[x: string]: unknown;
|
|
8
|
+
}>]>;
|
|
9
|
+
export type BuilderRenderMetadata = v.InferOutput<typeof BuilderRenderMetadataSchema>;
|
|
10
|
+
export type BuilderRenderOption = Readonly<{
|
|
11
|
+
name: string;
|
|
12
|
+
value: BuilderPrimitive;
|
|
13
|
+
update: BuilderRenderOptionUpdate;
|
|
14
|
+
option: BuilderOptionConfigSerialised;
|
|
15
|
+
displayName?: string;
|
|
16
|
+
kind?: string;
|
|
17
|
+
metadata?: BuilderRenderMetadata;
|
|
18
|
+
}>;
|
|
19
|
+
export type BuilderRenderOptions = ReadonlyArray<BuilderRenderOption>;
|
|
20
|
+
export declare function renderOption(input: BuilderUIInputValidated, path: BuilderPath, builder: BuilderValidated, model: BuilderModelValidated, instance: BuilderInstance, references: BuilderReferences): BuilderRenderOption | null;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as v from 'valibot';
|
|
2
|
+
import { check } from '../../errors/index.js';
|
|
3
|
+
import { BuilderPrimitiveSchema, NameSchema } from '../../primitive.js';
|
|
4
|
+
import { createInstance } from '../instance.js';
|
|
5
|
+
import { resolvePath } from '../resolve.js';
|
|
6
|
+
import { composeMetadata, composeString } from './compose.js';
|
|
7
|
+
import { writePath } from './paths.js';
|
|
8
|
+
export const BuilderRenderMetadataSchema = v.pipe(v.record(NameSchema, v.unknown()), v.readonly());
|
|
9
|
+
export function renderOption(input, path, builder, model, instance, references) {
|
|
10
|
+
const found = resolvePath(model, instance, input.path, references);
|
|
11
|
+
if (found == null) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
const fullPath = [...path, ...input.path];
|
|
15
|
+
check.assert(BuilderPrimitiveSchema, found.value);
|
|
16
|
+
return {
|
|
17
|
+
name: found.name,
|
|
18
|
+
option: found.payload,
|
|
19
|
+
value: found.value,
|
|
20
|
+
update: (updateInstance, updateValue) => createInstance(builder, writePath(updateInstance, fullPath, updateValue), references),
|
|
21
|
+
displayName: input.displayName && composeString(input.displayName, references),
|
|
22
|
+
kind: input.kind && composeString(input.kind, references),
|
|
23
|
+
metadata: input.metadata && composeMetadata(input.metadata, references)
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { BuilderModelValidated, BuilderPath, BuilderReferences, BuilderUIPageValidated, BuilderValidated } from '../../entities/index';
|
|
2
|
+
import type { BuilderInstance } from '../../instance';
|
|
3
|
+
import type { BuilderRenderCollections } from './collection';
|
|
4
|
+
import type { BuilderRenderOptions } from './option';
|
|
5
|
+
export type BuilderRenderPage = Readonly<{
|
|
6
|
+
label: string;
|
|
7
|
+
options: BuilderRenderOptions;
|
|
8
|
+
collections: BuilderRenderCollections;
|
|
9
|
+
}>;
|
|
10
|
+
export type BuilderRenderPages = ReadonlyArray<BuilderRenderPage>;
|
|
11
|
+
export declare function renderPage(page: BuilderUIPageValidated, label: string, path: BuilderPath, collections: BuilderRenderCollections, builder: BuilderValidated, model: BuilderModelValidated, instance: BuilderInstance, references: BuilderReferences): BuilderRenderPage | null;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { renderOption } from './option.js';
|
|
2
|
+
export function renderPage(page, label, path, collections, builder, model, instance, references) {
|
|
3
|
+
const options = page.inputs.flatMap((input) => {
|
|
4
|
+
const option = renderOption(input, path, builder, model, instance, references);
|
|
5
|
+
return option == null ? [] : [option];
|
|
6
|
+
});
|
|
7
|
+
if (options.length === 0) {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
return { label, options, collections };
|
|
11
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { check } from '../../errors/index.js';
|
|
2
|
+
import { NumberSchema } from '../../primitive.js';
|
|
3
|
+
export function readPath(container, path) {
|
|
4
|
+
return path.reduce((current, segment) => current == null ? undefined : current[segment], container);
|
|
5
|
+
}
|
|
6
|
+
export function writePath(container, path, value) {
|
|
7
|
+
if (path.length === 0) {
|
|
8
|
+
return value;
|
|
9
|
+
}
|
|
10
|
+
const [head, ...tail] = path;
|
|
11
|
+
if (check.is(NumberSchema, head)) {
|
|
12
|
+
const next = Array.isArray(container) ? [...container] : [];
|
|
13
|
+
next[head] = writePath(next[head], tail, value);
|
|
14
|
+
return next;
|
|
15
|
+
}
|
|
16
|
+
const next = container != null && !Array.isArray(container)
|
|
17
|
+
? { ...container }
|
|
18
|
+
: {};
|
|
19
|
+
next[head] = writePath(next[head], tail, value);
|
|
20
|
+
return next;
|
|
21
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BuilderDescription, BuilderInstanceValidated, BuilderReferences, BuilderValidated } from '../../entities/index';
|
|
2
|
-
import type { BuilderRenderPages } from './
|
|
2
|
+
import type { BuilderRenderPages } from './page';
|
|
3
3
|
export type BuilderRenderResult = Readonly<{
|
|
4
4
|
layout: BuilderRenderPages;
|
|
5
5
|
description: BuilderDescription;
|
|
@@ -1,120 +1,55 @@
|
|
|
1
|
-
import * as v from 'valibot';
|
|
2
1
|
import { check } from '../../errors/index.js';
|
|
3
2
|
import { BuilderInstancesSchema } from '../../instance.js';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
3
|
+
import { resolveCollection } from '../resolve.js';
|
|
4
|
+
import { renderCollection } from './collection.js';
|
|
5
|
+
import { composeLabel, composeString } from './compose.js';
|
|
6
|
+
import { renderDescription } from './description.js';
|
|
7
7
|
import { ordinal } from './ordinal.js';
|
|
8
|
-
import {
|
|
8
|
+
import { renderPage } from './page.js';
|
|
9
9
|
export function render(builder, instance, references = []) {
|
|
10
10
|
const layout = [];
|
|
11
11
|
const description = [];
|
|
12
|
-
|
|
12
|
+
renderUITree(builder.ui);
|
|
13
13
|
return { layout, description };
|
|
14
|
-
function
|
|
15
|
-
ui.uis.forEach(
|
|
16
|
-
|
|
14
|
+
function renderUITree(ui) {
|
|
15
|
+
ui.uis.forEach(renderUITree);
|
|
16
|
+
renderUIItems(ui.items, builder.model, instance, [], [], {});
|
|
17
17
|
}
|
|
18
|
-
function
|
|
18
|
+
function renderUIItems(items, model, instance, labels, path, collections) {
|
|
19
19
|
items.forEach((item) => {
|
|
20
20
|
if (item.type === 'page') {
|
|
21
|
-
|
|
21
|
+
const page = renderPage(item, composeLabel(item.label, labels, references), path, collections, builder, model, instance, references);
|
|
22
|
+
if (page != null) {
|
|
23
|
+
layout.push(page);
|
|
24
|
+
}
|
|
22
25
|
return;
|
|
23
26
|
}
|
|
24
27
|
if (item.type === 'describe') {
|
|
25
|
-
|
|
28
|
+
const descriptionItem = renderDescription(item, composeLabel(item.label, labels, references), model, instance, references);
|
|
29
|
+
if (descriptionItem != null) {
|
|
30
|
+
description.push(descriptionItem);
|
|
31
|
+
}
|
|
26
32
|
return;
|
|
27
33
|
}
|
|
28
|
-
const
|
|
34
|
+
const definition = model.collections.find((candidate) => candidate.name === item.name);
|
|
35
|
+
if (definition == null) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const collection = resolveCollection(definition, model, instance, references);
|
|
29
39
|
if (collection == null) {
|
|
30
40
|
return;
|
|
31
41
|
}
|
|
32
|
-
const
|
|
33
|
-
check.assert(BuilderInstancesSchema,
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
42
|
+
const instances = instance[item.name];
|
|
43
|
+
check.assert(BuilderInstancesSchema, instances);
|
|
44
|
+
const itemsPath = [...path, item.name];
|
|
45
|
+
const { min, max } = collection;
|
|
46
|
+
const { length } = instances;
|
|
47
|
+
instances.forEach((itemInstance, index) => {
|
|
48
|
+
renderUIItems(item.items, collection.model, itemInstance, [...labels, `${ordinal(index)} ${composeString(item.label, references)}`], [...itemsPath, index], {
|
|
49
|
+
...collections,
|
|
50
|
+
[item.name]: renderCollection(itemsPath, index, min, max, length, builder, references)
|
|
51
|
+
});
|
|
37
52
|
});
|
|
38
53
|
});
|
|
39
54
|
}
|
|
40
|
-
function emitPage(page, model, collectionPath, labelContext, currentInstance) {
|
|
41
|
-
const options = page.inputs.flatMap((input) => {
|
|
42
|
-
const { path } = input;
|
|
43
|
-
const found = resolvePath(model, currentInstance, path, references);
|
|
44
|
-
if (found == null) {
|
|
45
|
-
return [];
|
|
46
|
-
}
|
|
47
|
-
const fullPath = [...collectionPath, ...path];
|
|
48
|
-
check.assert(BuilderPrimitiveSchema, found.value);
|
|
49
|
-
return [
|
|
50
|
-
{
|
|
51
|
-
name: found.name,
|
|
52
|
-
option: found.payload,
|
|
53
|
-
value: found.value,
|
|
54
|
-
update: (updateInstance, updateValue) => createInstance(builder, setPath(updateInstance, fullPath, updateValue), references),
|
|
55
|
-
displayName: input.displayName && composeString(input.displayName),
|
|
56
|
-
kind: input.kind && composeString(input.kind),
|
|
57
|
-
metadata: input.metadata && composeMetadata(input.metadata)
|
|
58
|
-
}
|
|
59
|
-
];
|
|
60
|
-
});
|
|
61
|
-
if (options.length === 0) {
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
layout.push({ label: composeLabel(page.label, labelContext), options });
|
|
65
|
-
}
|
|
66
|
-
function emitDescribe(describe, model, labelContext, currentInstance) {
|
|
67
|
-
const composedLabel = composeLabel(describe.label, labelContext);
|
|
68
|
-
const values = describe.inputs.flatMap((input) => {
|
|
69
|
-
const { path } = input;
|
|
70
|
-
const found = resolvePath(model, currentInstance, path, references);
|
|
71
|
-
if (found?.value == null) {
|
|
72
|
-
return [];
|
|
73
|
-
}
|
|
74
|
-
check.assert(BuilderPrimitiveSchema, found.value);
|
|
75
|
-
return [found.value];
|
|
76
|
-
});
|
|
77
|
-
if (values.length === 0) {
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
description.push([composedLabel, values.join(' ')]);
|
|
81
|
-
}
|
|
82
|
-
function composeLabel(label, labelContext = []) {
|
|
83
|
-
const resolved = resolveReference(label, references);
|
|
84
|
-
check.assert(v.string(), resolved);
|
|
85
|
-
if (labelContext.length === 0) {
|
|
86
|
-
return resolved;
|
|
87
|
-
}
|
|
88
|
-
if (resolved === '') {
|
|
89
|
-
return labelContext.join(', ');
|
|
90
|
-
}
|
|
91
|
-
return `${labelContext.join(', ')}, ${resolved}`;
|
|
92
|
-
}
|
|
93
|
-
function composeString(value) {
|
|
94
|
-
const resolved = resolveReference(value, references);
|
|
95
|
-
check.assert(v.string(), resolved);
|
|
96
|
-
return resolved;
|
|
97
|
-
}
|
|
98
|
-
function composeMetadata(value) {
|
|
99
|
-
const resolved = resolveReference(value, references);
|
|
100
|
-
check.assert(BuilderRenderMetadataSchema, resolved);
|
|
101
|
-
return Object.fromEntries(Object.entries(resolved).map(([key, entry]) => [key, resolveReference(entry, references)]));
|
|
102
|
-
}
|
|
103
|
-
function findCollection(model, instance, collectionName) {
|
|
104
|
-
const entry = model.collections.find((candidate) => candidate.name === collectionName);
|
|
105
|
-
return entry == null ? null : resolveCollection(entry, model, instance, references);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
function setPath(container, path, value) {
|
|
109
|
-
const [head, ...tail] = path;
|
|
110
|
-
if (typeof head === 'number') {
|
|
111
|
-
const arrayContainer = container ? [...container] : [];
|
|
112
|
-
arrayContainer[head] = tail.length === 0 ? value : setPath(arrayContainer[head], tail, value);
|
|
113
|
-
return arrayContainer;
|
|
114
|
-
}
|
|
115
|
-
const objectContainer = container ? container : {};
|
|
116
|
-
return {
|
|
117
|
-
...objectContainer,
|
|
118
|
-
[head]: tail.length === 0 ? value : setPath(objectContainer[head], tail, value)
|
|
119
|
-
};
|
|
120
55
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import type { BuilderCollectionConfigsSerialised, BuilderCollectionConfigValidated, BuilderCollectionSerialised, BuilderCollectionValidated, BuilderComponentConfigsSerialised, BuilderComponentConfigValidated, BuilderComponentSerialised, BuilderComponentValidated, BuilderModelValidated, BuilderOptionConfigsSerialised, BuilderOptionConfigValidated, BuilderOptionSerialised, BuilderOptionValidated, BuilderPath, BuilderReferences } from '../entities/index';
|
|
2
2
|
import type { BuilderInstance } from '../instance';
|
|
3
|
+
import * as v from 'valibot';
|
|
3
4
|
export declare function resolveOption(option: BuilderOptionValidated, model: BuilderModelValidated, instance: unknown, references?: BuilderReferences): BuilderOptionConfigValidated | null;
|
|
4
5
|
export declare function resolveOptions(option: BuilderOptionSerialised, references?: BuilderReferences): BuilderOptionConfigsSerialised;
|
|
5
6
|
export declare function resolveComponent(component: BuilderComponentValidated, model: BuilderModelValidated, instance: unknown, references?: BuilderReferences): BuilderComponentConfigValidated | null;
|
|
6
7
|
export declare function resolveComponents(component: BuilderComponentSerialised, references?: BuilderReferences): BuilderComponentConfigsSerialised;
|
|
7
8
|
export declare function resolveCollection(collection: BuilderCollectionValidated, model: BuilderModelValidated, instance: unknown, references?: BuilderReferences): BuilderCollectionConfigValidated | null;
|
|
8
9
|
export declare function resolveCollections(collection: BuilderCollectionSerialised, references?: BuilderReferences): BuilderCollectionConfigsSerialised;
|
|
9
|
-
export declare function resolveReference(value: unknown, references: BuilderReferences):
|
|
10
|
+
export declare function resolveReference<Schema extends v.GenericSchema = v.GenericSchema<unknown>>(value: unknown, references: BuilderReferences, schema?: Schema): v.InferOutput<Schema>;
|
|
10
11
|
export type ResolvedPath = {
|
|
11
12
|
readonly name: string;
|
|
12
13
|
readonly payload: BuilderOptionConfigValidated;
|
package/dist/mappers/resolve.js
CHANGED
|
@@ -1,38 +1,40 @@
|
|
|
1
1
|
import * as v from 'valibot';
|
|
2
|
-
import { BuilderCollectionConfigSerialisedSchema, BuilderComponentConfigSerialisedSchema, BuilderOptionConfigSerialisedSchema,
|
|
2
|
+
import { BuilderCollectionConfigSerialisedSchema, BuilderCollectionWhenSerialisedSchema, BuilderComponentConfigSerialisedSchema, BuilderComponentWhenSerialisedSchema, BuilderOptionConfigSerialisedSchema, BuilderOptionWhenSerialisedSchema, BuilderPathsSchema, modelsMerge, whenBranches } from '../entities/index.js';
|
|
3
3
|
import { check } from '../errors/index.js';
|
|
4
4
|
import { BuilderInstanceSchema, BuilderInstancesSchema } from '../instance.js';
|
|
5
|
-
import { BuilderPrimitiveSchema } from '../primitive.js';
|
|
6
|
-
import { BuilderRefSerialisedSchema } from '../references.js';
|
|
5
|
+
import { BuilderPrimitiveSchema, NameSchema, NumberSchema } from '../primitive.js';
|
|
6
|
+
import { BuilderRefSerialisedSchema, paramable } from '../references.js';
|
|
7
7
|
export function resolveOption(option, model, instance, references = []) {
|
|
8
|
-
return resolveEntryInstance(option, BuilderOptionConfigSerialisedSchema, model, instance, references);
|
|
8
|
+
return resolveEntryInstance(option, BuilderOptionConfigSerialisedSchema, BuilderOptionWhenSerialisedSchema, model, instance, references);
|
|
9
9
|
}
|
|
10
10
|
export function resolveOptions(option, references = []) {
|
|
11
|
-
return resolveEntryExhaustive(option, BuilderOptionConfigSerialisedSchema, references);
|
|
11
|
+
return resolveEntryExhaustive(option, BuilderOptionConfigSerialisedSchema, BuilderOptionWhenSerialisedSchema, references);
|
|
12
12
|
}
|
|
13
13
|
export function resolveComponent(component, model, instance, references = []) {
|
|
14
|
-
return resolveEntryInstance(component, BuilderComponentConfigSerialisedSchema, model, instance, references);
|
|
14
|
+
return resolveEntryInstance(component, BuilderComponentConfigSerialisedSchema, BuilderComponentWhenSerialisedSchema, model, instance, references);
|
|
15
15
|
}
|
|
16
16
|
export function resolveComponents(component, references = []) {
|
|
17
|
-
return resolveEntryExhaustive(component, BuilderComponentConfigSerialisedSchema, references);
|
|
17
|
+
return resolveEntryExhaustive(component, BuilderComponentConfigSerialisedSchema, BuilderComponentWhenSerialisedSchema, references);
|
|
18
18
|
}
|
|
19
19
|
export function resolveCollection(collection, model, instance, references = []) {
|
|
20
|
-
return resolveEntryInstance(collection, BuilderCollectionConfigSerialisedSchema, model, instance, references);
|
|
20
|
+
return resolveEntryInstance(collection, BuilderCollectionConfigSerialisedSchema, BuilderCollectionWhenSerialisedSchema, model, instance, references);
|
|
21
21
|
}
|
|
22
22
|
export function resolveCollections(collection, references = []) {
|
|
23
|
-
return resolveEntryExhaustive(collection, BuilderCollectionConfigSerialisedSchema, references);
|
|
23
|
+
return resolveEntryExhaustive(collection, BuilderCollectionConfigSerialisedSchema, BuilderCollectionWhenSerialisedSchema, references);
|
|
24
24
|
}
|
|
25
|
-
export function resolveReference(value, references) {
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
export function resolveReference(value, references, schema = v.unknown()) {
|
|
26
|
+
let resolved = value;
|
|
27
|
+
if (check.is(BuilderRefSerialisedSchema, value)) {
|
|
28
|
+
const found = references.find((entry) => entry.id === value.id);
|
|
29
|
+
check.invariant(found);
|
|
30
|
+
resolved = found.serialised;
|
|
28
31
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return found.serialised;
|
|
32
|
+
check.assert(schema, resolved);
|
|
33
|
+
return resolved;
|
|
32
34
|
}
|
|
33
35
|
export function resolvePath(model, instance, path, references = []) {
|
|
34
36
|
const optionName = path.at(-1);
|
|
35
|
-
check.assert(
|
|
37
|
+
check.assert(NameSchema, optionName);
|
|
36
38
|
const descended = resolveItems(model, instance, path.slice(0, -1), references);
|
|
37
39
|
if (descended == null) {
|
|
38
40
|
return null;
|
|
@@ -53,8 +55,8 @@ export function resolveItems(model, instance, pairs, references = []) {
|
|
|
53
55
|
return [model, instance];
|
|
54
56
|
}
|
|
55
57
|
const [name, index, ...rest] = pairs;
|
|
56
|
-
check.assert(
|
|
57
|
-
check.assert(
|
|
58
|
+
check.assert(NameSchema, name);
|
|
59
|
+
check.assert(NumberSchema, index);
|
|
58
60
|
const merged = modelsMerge(model);
|
|
59
61
|
const collection = merged.collections.find((entry) => entry.name === name);
|
|
60
62
|
check.invariant(collection);
|
|
@@ -70,12 +72,11 @@ export function resolveItems(model, instance, pairs, references = []) {
|
|
|
70
72
|
}
|
|
71
73
|
return resolveItems(resolved.model, item, rest, references);
|
|
72
74
|
}
|
|
73
|
-
function resolveEntryInstance(entry, schema, model, instance, references) {
|
|
74
|
-
const payload = resolveReference(entry.payload, references);
|
|
75
|
+
function resolveEntryInstance(entry, schema, whenSchema, model, instance, references) {
|
|
76
|
+
const payload = resolveReference(entry.payload, references, paramable(v.union([schema, whenSchema])));
|
|
75
77
|
if (check.is(schema, payload)) {
|
|
76
78
|
return payload;
|
|
77
79
|
}
|
|
78
|
-
check.assert(BuilderWhenSerialisedSchema, payload);
|
|
79
80
|
check.assert(BuilderPathsSchema, entry.paths);
|
|
80
81
|
const config = payload;
|
|
81
82
|
if (!entry.paths.every((path) => Boolean(resolvePath(model, instance, path, references)?.value))) {
|
|
@@ -103,6 +104,6 @@ function resolveEntryInstance(entry, schema, model, instance, references) {
|
|
|
103
104
|
}
|
|
104
105
|
}
|
|
105
106
|
}
|
|
106
|
-
function resolveEntryExhaustive(entry, schema, references) {
|
|
107
|
-
return whenBranches(resolveReference(entry.payload, references), schema);
|
|
107
|
+
function resolveEntryExhaustive(entry, schema, whenSchema, references) {
|
|
108
|
+
return whenBranches(resolveReference(entry.payload, references, paramable(v.union([schema, whenSchema]))), schema);
|
|
108
109
|
}
|
package/dist/primitive.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import * as v from 'valibot';
|
|
2
|
+
export declare const StringSchema: v.StringSchema<undefined>;
|
|
3
|
+
export declare const NumberSchema: v.NumberSchema<undefined>;
|
|
4
|
+
export declare const BooleanSchema: v.BooleanSchema<undefined>;
|
|
5
|
+
export declare const NameSchema: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
|
|
6
|
+
export declare const IdSchema: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
|
|
2
7
|
export declare const BuilderPrimitiveSchema: v.NullableSchema<v.UnionSchema<[v.StringSchema<undefined>, v.BooleanSchema<undefined>, v.NumberSchema<undefined>], undefined>, undefined>;
|
|
3
8
|
export type BuilderPrimitive = v.InferOutput<typeof BuilderPrimitiveSchema>;
|
|
4
9
|
export declare const BuilderPrimitivesSchema: v.SchemaWithPipe<readonly [v.ArraySchema<v.NullableSchema<v.UnionSchema<[v.StringSchema<undefined>, v.BooleanSchema<undefined>, v.NumberSchema<undefined>], undefined>, undefined>, undefined>, v.ReadonlyAction<(string | number | boolean | null)[]>]>;
|
package/dist/primitive.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
1
|
import * as v from 'valibot';
|
|
2
|
-
export const
|
|
2
|
+
export const StringSchema = v.string();
|
|
3
|
+
export const NumberSchema = v.number();
|
|
4
|
+
export const BooleanSchema = v.boolean();
|
|
5
|
+
export const NameSchema = v.pipe(StringSchema, v.minLength(1));
|
|
6
|
+
export const IdSchema = v.pipe(StringSchema, v.minLength(1));
|
|
7
|
+
export const BuilderPrimitiveSchema = v.nullable(v.union([StringSchema, BooleanSchema, NumberSchema]));
|
|
3
8
|
export const BuilderPrimitivesSchema = v.pipe(v.array(BuilderPrimitiveSchema), v.readonly());
|
package/dist/public.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export type { BuilderEnvironment } from './environment';
|
|
|
4
4
|
export type { BuilderError, BuilderErrorLocation, BuilderErrors } from './errors/index';
|
|
5
5
|
export type { BuilderErrorKind } from './errors/index.js';
|
|
6
6
|
export type { BuilderComponentVariant, BuilderComponentVariants, BuilderInstance, BuilderInstanceInput, BuilderInstances, BuilderVariants } from './instance';
|
|
7
|
-
export type { BuilderOrder, BuilderRenderMetadata, BuilderRenderOption, BuilderRenderOptions, BuilderRenderPage, BuilderRenderPages, BuilderRenderResult
|
|
7
|
+
export type { BuilderOrder, BuilderRenderCollection, BuilderRenderCollectionAddRemove, BuilderRenderCollections, BuilderRenderMetadata, BuilderRenderOption, BuilderRenderOptions, BuilderRenderOptionUpdate, BuilderRenderPage, BuilderRenderPages, BuilderRenderResult } from './mappers/index';
|
|
8
8
|
export type { BuilderPrimitive, BuilderPrimitives } from './primitive';
|
|
9
9
|
export type { BuilderParameter, BuilderParameterSerialised, BuilderRef, Paramable, ParamableSerialised } from './references';
|
|
10
10
|
export type { BuilderInstanceValidationResult, BuilderModelValidationResult, BuilderPricingValidationResult, BuilderUIValidationResult, BuilderValidationResult, BuilderVariantsValidationOptions, BuilderVariantsValidationResult } from './validate/index';
|
package/dist/references.d.ts
CHANGED
|
@@ -9,8 +9,8 @@ export declare class BuilderParameter<const Name extends string = string> {
|
|
|
9
9
|
export declare const BuilderParameterSchema: v.InstanceSchema<typeof BuilderParameter, undefined>;
|
|
10
10
|
export declare const BuilderParameterSerialisedSchema: v.SchemaWithPipe<readonly [v.ObjectSchema<{
|
|
11
11
|
readonly type: v.LiteralSchema<"parameter", undefined>;
|
|
12
|
-
readonly id: v.StringSchema<undefined>;
|
|
13
|
-
readonly name: v.StringSchema<undefined>;
|
|
12
|
+
readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
|
|
13
|
+
readonly name: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
|
|
14
14
|
}, undefined>, v.ReadonlyAction<{
|
|
15
15
|
type: "parameter";
|
|
16
16
|
id: string;
|
|
@@ -25,7 +25,7 @@ export declare class BuilderRef {
|
|
|
25
25
|
export declare const BuilderRefSchema: v.InstanceSchema<typeof BuilderRef, undefined>;
|
|
26
26
|
export declare const BuilderRefSerialisedSchema: v.SchemaWithPipe<readonly [v.ObjectSchema<{
|
|
27
27
|
readonly type: v.LiteralSchema<"ref", undefined>;
|
|
28
|
-
readonly id: v.StringSchema<undefined>;
|
|
28
|
+
readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
|
|
29
29
|
}, undefined>, v.ReadonlyAction<{
|
|
30
30
|
type: "ref";
|
|
31
31
|
id: string;
|
|
@@ -35,15 +35,15 @@ export declare function parameter<const Name extends string>(name: Name): Builde
|
|
|
35
35
|
export declare function ref(id: string): BuilderRef;
|
|
36
36
|
export declare function paramable<Schema extends v.GenericSchema>(paramable: Schema): v.UnionSchema<[v.SchemaWithPipe<readonly [v.ObjectSchema<{
|
|
37
37
|
readonly type: v.LiteralSchema<"parameter", undefined>;
|
|
38
|
-
readonly id: v.StringSchema<undefined>;
|
|
39
|
-
readonly name: v.StringSchema<undefined>;
|
|
38
|
+
readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
|
|
39
|
+
readonly name: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
|
|
40
40
|
}, undefined>, v.ReadonlyAction<{
|
|
41
41
|
type: "parameter";
|
|
42
42
|
id: string;
|
|
43
43
|
name: string;
|
|
44
44
|
}>]>, v.SchemaWithPipe<readonly [v.ObjectSchema<{
|
|
45
45
|
readonly type: v.LiteralSchema<"ref", undefined>;
|
|
46
|
-
readonly id: v.StringSchema<undefined>;
|
|
46
|
+
readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
|
|
47
47
|
}, undefined>, v.ReadonlyAction<{
|
|
48
48
|
type: "ref";
|
|
49
49
|
id: string;
|
package/dist/references.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as v from 'valibot';
|
|
2
2
|
import { check } from './errors/index.js';
|
|
3
|
+
import { IdSchema, NameSchema } from './primitive.js';
|
|
3
4
|
export class BuilderParameter {
|
|
4
5
|
id;
|
|
5
6
|
name;
|
|
@@ -9,7 +10,7 @@ export class BuilderParameter {
|
|
|
9
10
|
}
|
|
10
11
|
}
|
|
11
12
|
export const BuilderParameterSchema = v.instance(BuilderParameter);
|
|
12
|
-
export const BuilderParameterSerialisedSchema = v.pipe(v.object({ type: v.literal('parameter'), id:
|
|
13
|
+
export const BuilderParameterSerialisedSchema = v.pipe(v.object({ type: v.literal('parameter'), id: IdSchema, name: NameSchema }), v.readonly());
|
|
13
14
|
export class BuilderRef {
|
|
14
15
|
type = 'ref';
|
|
15
16
|
id;
|
|
@@ -18,7 +19,7 @@ export class BuilderRef {
|
|
|
18
19
|
}
|
|
19
20
|
}
|
|
20
21
|
export const BuilderRefSchema = v.instance(BuilderRef);
|
|
21
|
-
export const BuilderRefSerialisedSchema = v.pipe(v.object({ type: v.literal('ref'), id:
|
|
22
|
+
export const BuilderRefSerialisedSchema = v.pipe(v.object({ type: v.literal('ref'), id: IdSchema }), v.readonly());
|
|
22
23
|
export function parameter(name) {
|
|
23
24
|
return new BuilderParameter(name);
|
|
24
25
|
}
|
package/dist/validate/model.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as v from 'valibot';
|
|
2
|
+
import { BuilderCollectionConfigSerialisedSchema, BuilderComponentConfigSerialisedSchema, BuilderModelSerialisedSchema, BuilderOptionConfigSerialisedSchema, BuilderPathsSchema, BuilderWhenSerialisedSchema, whenBranches, model, modelsMerge, serialise, validateCollectionConfig, validateComponentConfig, validateSelect, validateToggle } from '../entities/index.js';
|
|
2
3
|
import { BuilderErrorsScope, check } from '../errors/index.js';
|
|
3
4
|
import { isParamable } from '../references.js';
|
|
4
5
|
import { validate } from './brand.js';
|
|
@@ -41,8 +42,8 @@ export function validateModelStructure(input, resolve, errors) {
|
|
|
41
42
|
};
|
|
42
43
|
return walkStructure(input);
|
|
43
44
|
function walkStructure(input) {
|
|
44
|
-
const resolved = resolve(input);
|
|
45
|
-
if (
|
|
45
|
+
const resolved = resolve(input, BuilderModelSerialisedSchema);
|
|
46
|
+
if (resolved == null) {
|
|
46
47
|
return validate(serialise.model(model()));
|
|
47
48
|
}
|
|
48
49
|
const modelInput = resolved;
|
|
@@ -81,6 +82,15 @@ export function validateModelStructure(input, resolve, errors) {
|
|
|
81
82
|
components,
|
|
82
83
|
collections
|
|
83
84
|
};
|
|
85
|
+
function payloadSchemaFor(kind) {
|
|
86
|
+
if (kind === 'option') {
|
|
87
|
+
return BuilderOptionConfigSerialisedSchema;
|
|
88
|
+
}
|
|
89
|
+
if (kind === 'component') {
|
|
90
|
+
return BuilderComponentConfigSerialisedSchema;
|
|
91
|
+
}
|
|
92
|
+
return BuilderCollectionConfigSerialisedSchema;
|
|
93
|
+
}
|
|
84
94
|
function walkEntries(entries, kind, validateBranches) {
|
|
85
95
|
const seenLocal = new Set();
|
|
86
96
|
const items = [];
|
|
@@ -99,10 +109,11 @@ export function validateModelStructure(input, resolve, errors) {
|
|
|
99
109
|
function resolveEntry(entry, seenLocal, kind) {
|
|
100
110
|
let paths = entry.paths;
|
|
101
111
|
if (entry.paths != null) {
|
|
102
|
-
const resolvedPaths = errors.scope('paths', () => resolve(entry.paths));
|
|
112
|
+
const resolvedPaths = errors.scope('paths', () => resolve(entry.paths, BuilderPathsSchema));
|
|
103
113
|
paths = resolvedPaths ?? entry.paths;
|
|
104
114
|
}
|
|
105
|
-
const
|
|
115
|
+
const payloadSchema = v.union([payloadSchemaFor(kind), BuilderWhenSerialisedSchema]);
|
|
116
|
+
const payload = errors.scope('payload', () => resolve(entry.payload, payloadSchema));
|
|
106
117
|
const resolvedEntry = { ...entry, paths, payload: payload ?? entry.payload };
|
|
107
118
|
if (seenLocal.has(resolvedEntry.name)) {
|
|
108
119
|
if (kind === 'option') {
|
package/dist/validate/paths.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import * as v from 'valibot';
|
|
2
1
|
import { BuilderModelSerialisedSchema } from '../entities/index.js';
|
|
3
2
|
import { check } from '../errors/index.js';
|
|
4
3
|
import { resolveCollections } from '../mappers/index.js';
|
|
5
|
-
|
|
6
|
-
const StringSchema = v.string();
|
|
4
|
+
import { NameSchema, NumberSchema } from '../primitive.js';
|
|
7
5
|
export function checkPath(model, path, errors) {
|
|
8
6
|
if (path.length === 0) {
|
|
9
7
|
errors.pathEmpty();
|
|
@@ -15,7 +13,7 @@ export function checkPath(model, path, errors) {
|
|
|
15
13
|
return;
|
|
16
14
|
}
|
|
17
15
|
const optionName = path.at(-1);
|
|
18
|
-
if (!check.is(
|
|
16
|
+
if (!check.is(NameSchema, optionName)) {
|
|
19
17
|
errors.scope(lastIndex, () => errors.pathInvalidSegment());
|
|
20
18
|
return;
|
|
21
19
|
}
|
|
@@ -39,7 +37,7 @@ function walkPath(models, remaining, offset, errors) {
|
|
|
39
37
|
return models;
|
|
40
38
|
}
|
|
41
39
|
const [collectionName, index, ...rest] = remaining;
|
|
42
|
-
if (!check.is(
|
|
40
|
+
if (!check.is(NameSchema, collectionName)) {
|
|
43
41
|
errors.scope(offset, () => errors.pathInvalidSegment());
|
|
44
42
|
return null;
|
|
45
43
|
}
|
package/dist/validate/pricing.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import * as v from 'valibot';
|
|
2
1
|
import { BuilderPricingExpressionSchema, BuilderPricingSerialisedSchema, BuilderRatesSchema, pricing, serialise } from '../entities/index.js';
|
|
3
2
|
import { BuilderErrorsScope, check } from '../errors/index.js';
|
|
3
|
+
import { NumberSchema } from '../primitive.js';
|
|
4
4
|
import { validate } from './brand.js';
|
|
5
5
|
import { resolver } from './resolve.js';
|
|
6
6
|
const EMPTY_PRICING = validate(serialise.pricing(pricing()));
|
|
7
|
-
const NumberSchema = v.number();
|
|
8
7
|
export function validatePricing(input, references = [], errors = new BuilderErrorsScope(input)) {
|
|
9
8
|
if (!check.is(BuilderPricingSerialisedSchema, input)) {
|
|
10
9
|
errors.entityInvalid('pricing');
|
|
@@ -16,8 +15,8 @@ export function validatePricing(input, references = [], errors = new BuilderErro
|
|
|
16
15
|
}
|
|
17
16
|
export function validatePricingStructure(input, resolve, errors) {
|
|
18
17
|
const rates = errors.scope('rates', () => input.rates.flatMap((entry, index) => {
|
|
19
|
-
const resolved = resolve(entry);
|
|
20
|
-
if (
|
|
18
|
+
const resolved = resolve(entry, BuilderRatesSchema);
|
|
19
|
+
if (resolved != null) {
|
|
21
20
|
return [resolved];
|
|
22
21
|
}
|
|
23
22
|
errors.scope(index, () => errors.pricingInvalidRateValue());
|
|
@@ -29,8 +28,8 @@ export function validatePricingStructure(input, resolve, errors) {
|
|
|
29
28
|
}
|
|
30
29
|
return { rates, formula };
|
|
31
30
|
function resolveExpression(input) {
|
|
32
|
-
const resolved = resolve(input);
|
|
33
|
-
if (
|
|
31
|
+
const resolved = resolve(input, BuilderPricingExpressionSchema);
|
|
32
|
+
if (resolved == null) {
|
|
34
33
|
errors.pricingMalformedExpression();
|
|
35
34
|
return null;
|
|
36
35
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { BuilderBindings, BuilderReferences } from '../entities/index';
|
|
2
2
|
import type { BuilderErrorsScope } from '../errors/index';
|
|
3
|
-
|
|
3
|
+
import * as v from 'valibot';
|
|
4
|
+
export type BuilderResolve = <S extends v.GenericSchema = v.GenericSchema<unknown>>(value: unknown, schema?: S) => v.InferOutput<S> | null;
|
|
4
5
|
export declare function resolver(errors: BuilderErrorsScope, references?: BuilderReferences, bindings?: BuilderBindings): BuilderResolve;
|