@builder-builder/builder 0.0.11 → 0.0.12

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.
@@ -112,6 +112,8 @@ export declare const BuilderWhenConfigSchema: v.SchemaWithPipe<readonly [v.Varia
112
112
  id: string;
113
113
  }>]>, v.SchemaWithPipe<readonly [v.ArraySchema<v.UnionSchema<[v.StringSchema<undefined>, v.NumberSchema<undefined>], undefined>, undefined>, v.ReadonlyAction<(string | number)[]>]>], undefined>;
114
114
  }, undefined>], undefined>, v.ReadonlyAction<{
115
+ type: "enable";
116
+ } | {
115
117
  type: "match";
116
118
  matchPath: readonly (string | number)[] | Readonly<{
117
119
  type: "parameter";
@@ -131,8 +133,6 @@ export declare const BuilderWhenConfigSchema: v.SchemaWithPipe<readonly [v.Varia
131
133
  type: "ref";
132
134
  id: string;
133
135
  }>;
134
- } | {
135
- type: "enable";
136
136
  }>]>;
137
137
  export type BuilderWhenConfig = v.InferOutput<typeof BuilderWhenConfigSchema>;
138
138
  export type BuilderWhenGeneric = BuilderWhen<unknown, unknown, unknown, unknown>;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export type { BB, BBOptions } from './bb';
2
- export type { BuilderBindings, BuilderBindingsSerialised, BuilderCollection, BuilderCollectionConfig, BuilderCollectionConfigSerialised, BuilderCollections, BuilderCollectionSerialised, BuilderCollectionsSerialised, BuilderCollectionWhen, BuilderCollectionWhenSerialised, BuilderComponent, BuilderComponentDetails, BuilderComponentDetailsSerialised, BuilderComponentField, BuilderComponentFields, BuilderComponentFieldSerialised, BuilderComponentFieldsSerialised, BuilderComponentFieldValueType, BuilderComponents, BuilderComponentSerialised, BuilderComponentsSerialised, BuilderComponentWhen, BuilderComponentWhenSerialised, BuilderDescription, BuilderDescriptionItem, BuilderEntityKind, BuilderEntitySerialised, BuilderExpectation, BuilderExpectationKind, BuilderExpectations, BuilderExpectationSerialised, BuilderExpectationsSerialised, BuilderInstanceOf, BuilderModel, BuilderModels, BuilderModelSerialised, BuilderModelValidated, BuilderOption, BuilderOptions, BuilderOptionSerialised, BuilderOptionsSerialised, BuilderOptionValues, BuilderOptionValuesSerialised, BuilderOptionWhen, BuilderOptionWhenSerialised, BuilderRefEntities, BuilderRefEntity, BuilderSelectType, BuilderSelectTypeLabels, BuilderSelectTypeSerialised, BuilderSelectTypeValues, BuilderSerialised, BuilderToggleType, BuilderToggleTypeSerialised, BuilderToggleValueType, BuilderUI, BuilderUIDescribe, BuilderUIDescribeSerialised, BuilderUIItem, BuilderUIItems, BuilderUIItemsSerialised, BuilderUIPage, BuilderUIPages, BuilderUIPageSerialised, BuilderUIPagesSerialised, BuilderUIs, BuilderUIsSerialised, BuilderUISerialised, BuilderUIValidated, BuilderValidated, BuilderEnableConfig, BuilderMatchConfig, BuilderMatchSelectMap, BuilderUnlessConfig, BuilderWhen, BuilderWhenConfig, BuilderWhenSerialised } from './entities/index';
2
+ export type { BuilderBindings, BuilderBindingsSerialised, BuilderCollection, BuilderCollectionConfig, BuilderCollectionConfigSerialised, BuilderCollections, BuilderCollectionSerialised, BuilderCollectionsSerialised, BuilderCollectionWhen, BuilderCollectionWhenSerialised, BuilderComponent, BuilderComponentDetails, BuilderComponentDetailsSerialised, BuilderComponentField, BuilderComponentFields, BuilderComponentFieldSerialised, BuilderComponentFieldsSerialised, BuilderComponentFieldValueType, BuilderComponents, BuilderComponentSerialised, BuilderComponentsSerialised, BuilderComponentWhen, BuilderComponentWhenSerialised, BuilderDescription, BuilderDescriptionItem, BuilderEntityKind, BuilderEntitySerialised, BuilderExpectation, BuilderExpectationKind, BuilderExpectations, BuilderExpectationSerialised, BuilderExpectationsSerialised, BuilderInstanceOf, BuilderModel, BuilderModels, BuilderModelSerialised, BuilderModelValidated, BuilderOption, BuilderOptions, BuilderOptionSerialised, BuilderOptionsSerialised, BuilderOptionValues, BuilderOptionValuesSerialised, BuilderOptionWhen, BuilderOptionWhenSerialised, BuilderRefEntities, BuilderRefEntity, BuilderSelectType, BuilderSelectTypeLabels, BuilderSelectTypeSerialised, BuilderSelectTypeValues, BuilderSerialised, BuilderToggleType, BuilderToggleTypeSerialised, BuilderToggleValueType, BuilderUI, BuilderUIDescribe, BuilderUIDescribeSerialised, BuilderUIItem, BuilderUIItems, BuilderUIItemsSerialised, BuilderUIPage, BuilderUIPages, BuilderUIPageSerialised, BuilderUIPagesSerialised, BuilderUIs, BuilderUIsSerialised, BuilderUISerialised, BuilderUIValidated, BuilderValidated, BuilderComponentVariantsValidated, BuilderInstanceValidated, BuilderEnableConfig, BuilderMatchConfig, BuilderMatchSelectMap, BuilderUnlessConfig, BuilderWhen, BuilderWhenConfig, BuilderWhenSerialised } from './entities/index';
3
3
  export type { BuilderEnvironment } from './environment';
4
4
  export type { BuilderError, BuilderErrorBase, BuilderErrorLocation, BuilderErrors } from './exception';
5
5
  export type { BuilderComponentVariantsValidationResult, BuilderErrorDuplicateName, BuilderErrorInvalidCollection, BuilderErrorInvalidCollectionBounds, BuilderErrorInvalidDetail, BuilderErrorInvalidInput, BuilderErrorInvalidOption, BuilderErrorInvalidPath, BuilderErrorInvalidPathReason, BuilderErrorInvalidSelectMapKey, BuilderErrorInvalidVariant, BuilderErrorMissingComponent, BuilderErrorMissingDetail, BuilderErrorMissingReference, BuilderErrorMissingVariant, BuilderErrorUnboundParameter, BuilderErrorUnexpectedComponent, BuilderErrorUnexpectedDetail, BuilderErrorUnmetExpectation, BuilderErrorUnvalidated, BuilderInstanceValidationResult, BuilderModelValidationResult, BuilderOrder, BuilderRenderOption, BuilderRenderOptions, BuilderRenderPage, BuilderRenderPages, BuilderRenderResult, BuilderRenderUpdate, BuilderUIValidationResult, BuilderValidationResult, BuilderVariantsValidationOptions } from './mappers/index';
@@ -1,13 +1,14 @@
1
1
  import { check } from '../check.js';
2
- import { optionValueSchema } from '../entities/index.js';
2
+ import { modelsMerge, optionValueSchema } from '../entities/index.js';
3
3
  import { resolveCollection, resolveOption } from './resolve.js';
4
4
  export function createInstance(entity, partial = {}, refs = []) {
5
5
  const model = 'model' in entity ? entity.model : entity;
6
6
  return buildInstance(model, partial, refs);
7
7
  }
8
8
  function buildInstance(model, partial, refs) {
9
+ const merged = modelsMerge(model);
9
10
  let instance = { ...partial };
10
- model.options.forEach((option) => {
11
+ merged.options.forEach((option) => {
11
12
  const { name } = option;
12
13
  const payload = resolveOption(option, instance, refs);
13
14
  if (payload == null) {
@@ -19,7 +20,7 @@ function buildInstance(model, partial, refs) {
19
20
  }
20
21
  instance = { ...instance, [name]: payload.defaultValue };
21
22
  });
22
- model.collections.forEach((collection) => {
23
+ merged.collections.forEach((collection) => {
23
24
  const { name } = collection;
24
25
  const payload = resolveCollection(collection, instance, refs);
25
26
  if (payload == null) {
@@ -3,6 +3,7 @@ import type { BuilderPrimitive } from '../../primitive';
3
3
  import type { BuilderInstance } from '../../instance';
4
4
  export type BuilderRenderUpdate = (model: BuilderInstance, primitive: BuilderPrimitive) => BuilderInstance;
5
5
  export type BuilderRenderOption = Readonly<{
6
+ name: string;
6
7
  value: BuilderPrimitive;
7
8
  update: BuilderRenderUpdate;
8
9
  option: BuilderOptionValuesSerialised;
@@ -1,5 +1,6 @@
1
1
  import * as v from 'valibot';
2
2
  import { check } from '../../check.js';
3
+ import { modelsMerge } from '../../entities/model/index.js';
3
4
  import { BuilderInstancesSchema } from '../../instance.js';
4
5
  import { readPath } from '../../paths.js';
5
6
  import { resolveCollection, resolveOption, resolveRef } from '../resolve.js';
@@ -29,20 +30,23 @@ export function render(builder, instance, refs = []) {
29
30
  }
30
31
  const itemInstances = currentInstance[item.name];
31
32
  check.assert(BuilderInstancesSchema, itemInstances, 'Collection field is not an array! ❌');
33
+ const mergedItemModel = modelsMerge(collection.model);
32
34
  itemInstances.forEach((itemInstance, index) => {
33
- walkItems(item.items, collection.model, [...collectionPath, item.name, index], [...labelContext, `${ordinal(index)} ${composeLabel(item.label)}`], itemInstance);
35
+ walkItems(item.items, mergedItemModel, [...collectionPath, item.name, index], [...labelContext, `${ordinal(index)} ${composeLabel(item.label)}`], itemInstance);
34
36
  });
35
37
  });
36
38
  }
37
39
  function emitPage(page, model, collectionPath, labelContext, currentInstance) {
38
40
  const options = page.paths.flatMap((path) => {
39
- const option = findOption(model, currentInstance, path);
40
- if (option == null) {
41
+ const found = findOption(model, currentInstance, path);
42
+ if (found == null) {
41
43
  return [];
42
44
  }
43
45
  const fullPath = [...collectionPath, ...path];
46
+ const [name, option] = found;
44
47
  return [
45
48
  {
49
+ name,
46
50
  option,
47
51
  value: readPath(currentInstance, path),
48
52
  update: (updateInstance, updateValue) => setPath(updateInstance, fullPath, updateValue)
@@ -57,8 +61,8 @@ export function render(builder, instance, refs = []) {
57
61
  function emitDescribe(describe, model, labelContext, currentInstance) {
58
62
  const composedLabel = composeLabel(describe.label, labelContext);
59
63
  const values = describe.paths.flatMap((path) => {
60
- const option = findOption(model, currentInstance, path);
61
- if (option == null) {
64
+ const found = findOption(model, currentInstance, path);
65
+ if (found == null) {
62
66
  return [];
63
67
  }
64
68
  const value = readPath(currentInstance, path);
@@ -78,6 +82,9 @@ export function render(builder, instance, refs = []) {
78
82
  if (labelContext.length === 0) {
79
83
  return resolved;
80
84
  }
85
+ if (resolved === '') {
86
+ return labelContext.join(', ');
87
+ }
81
88
  return `${labelContext.join(', ')}, ${resolved}`;
82
89
  }
83
90
  function findOption(model, instance, path) {
@@ -90,7 +97,14 @@ export function render(builder, instance, refs = []) {
90
97
  }
91
98
  const [scopeModel, scopeInstance] = descended;
92
99
  const entry = scopeModel.options.find((option) => option.name === optionName);
93
- return entry == null ? null : resolveOption(entry, scopeInstance, refs);
100
+ if (entry == null) {
101
+ return null;
102
+ }
103
+ const optionValues = resolveOption(entry, scopeInstance, refs);
104
+ if (optionValues == null) {
105
+ return null;
106
+ }
107
+ return [entry.name, optionValues];
94
108
  }
95
109
  function descendPairs(model, instance, remaining) {
96
110
  if (remaining.length === 0) {
@@ -59,23 +59,52 @@ export function validateModelStructure(input, resolve, location) {
59
59
  const checkPaths = (entry, entryLocation) => (skipPathValidation ? [] : checkEntryPaths(modelInput, entry, entryLocation));
60
60
  options.forEach((entry, entryIndex) => errors.push(...checkPaths(entry, [...location, 'options', entryIndex])));
61
61
  components.forEach((entry, entryIndex) => errors.push(...checkPaths(entry, [...location, 'components', entryIndex])));
62
- collections.forEach((entry, entryIndex) => {
62
+ const resolvedCollections = collections.map((entry, entryIndex) => {
63
63
  const collectionLocation = [...location, 'collections', entryIndex];
64
64
  errors.push(...checkPaths(entry, collectionLocation), ...checkCollectionBounds(entry, collectionLocation));
65
- collectionNestedModels(entry, collectionLocation).forEach(([nested, nestedLocation]) => {
66
- const [, nestedErrors] = validateModelStructure(nested, resolve, nestedLocation);
67
- errors.push(...nestedErrors);
68
- });
65
+ const [resolvedEntry, entryErrors] = resolveCollectionInnerModels(entry, resolve, [...collectionLocation, 'payload']);
66
+ errors.push(...entryErrors);
67
+ return resolvedEntry;
69
68
  });
70
69
  const data = {
71
70
  ...modelInput,
72
71
  models: childModels,
73
72
  options,
74
73
  components,
75
- collections
74
+ collections: resolvedCollections
76
75
  };
77
76
  return [data, errors];
78
77
  }
78
+ function resolveCollectionInnerModels(entry, resolve, payloadLocation) {
79
+ const errors = [];
80
+ const newPayload = mapCollectionConfigs(entry.payload, payloadLocation, (config, configLocation) => {
81
+ if (!check.is(BuilderModelSerialisedSchema, config.model)) {
82
+ return config;
83
+ }
84
+ const [validated, modelErrors] = validateModelStructure(config.model, resolve, [...configLocation, 'model']);
85
+ errors.push(...modelErrors);
86
+ return { ...config, model: validated };
87
+ });
88
+ return [{ ...entry, payload: newPayload }, errors];
89
+ }
90
+ function mapCollectionConfigs(payload, location, visit) {
91
+ if (check.is(BuilderCollectionConfigSerialisedSchema, payload)) {
92
+ return visit(payload, location);
93
+ }
94
+ if (!check.is(BuilderWhenSerialisedSchema, payload)) {
95
+ return payload;
96
+ }
97
+ const when = payload;
98
+ if (when.type === 'match') {
99
+ const selectMap = when.selectMap;
100
+ const newSelectMap = Object.fromEntries(Object.entries(selectMap).map(([key, value]) => [
101
+ key,
102
+ mapCollectionConfigs(value, [...location, 'selectMap', key], visit)
103
+ ]));
104
+ return { ...when, selectMap: newSelectMap };
105
+ }
106
+ return { ...when, payload: mapCollectionConfigs(when.payload, [...location, 'payload'], visit) };
107
+ }
79
108
  function walkEntries(entries, entryKind, resolve, location) {
80
109
  const seen = new Set();
81
110
  const items = [];
@@ -130,11 +159,6 @@ function checkCollectionBounds(collection, location) {
130
159
  return [];
131
160
  });
132
161
  }
133
- function collectionNestedModels(collection, location) {
134
- return collectionConfigs(collection, location).flatMap(([config, configLocation]) => check.is(BuilderModelSerialisedSchema, config.model)
135
- ? [[config.model, [...configLocation, 'model']]]
136
- : []);
137
- }
138
162
  function collectionConfigs(collection, location) {
139
163
  const { payload } = collection;
140
164
  const payloadLocation = [...location, 'payload'];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@builder-builder/builder",
3
- "version": "0.0.11",
3
+ "version": "0.0.12",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {