@builder-builder/builder 0.0.4 → 0.0.6

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.
Files changed (69) hide show
  1. package/dist/core/builder.d.ts +27 -20
  2. package/dist/core/builder.js +43 -15
  3. package/dist/core/collection/collection.d.ts +11 -12
  4. package/dist/core/collection/collection.js +5 -23
  5. package/dist/core/collection/index.d.ts +1 -1
  6. package/dist/core/collection/method.d.ts +22 -43
  7. package/dist/core/component/component.d.ts +1 -6
  8. package/dist/core/component/component.js +0 -7
  9. package/dist/core/component/graph.d.ts +0 -1
  10. package/dist/core/component/graph.js +8 -7
  11. package/dist/core/component/index.d.ts +1 -1
  12. package/dist/core/component/method.d.ts +7 -9
  13. package/dist/core/expectation.d.ts +45 -0
  14. package/dist/{assert → core}/expectation.js +6 -5
  15. package/dist/core/graph.d.ts +2 -1
  16. package/dist/core/graph.js +3 -1
  17. package/dist/core/index.d.ts +9 -6
  18. package/dist/core/index.js +3 -2
  19. package/dist/core/option/graph.d.ts +1 -2
  20. package/dist/core/option/graph.js +6 -7
  21. package/dist/core/option/method.d.ts +34 -61
  22. package/dist/core/option/method.js +4 -14
  23. package/dist/core/option/option.d.ts +5 -4
  24. package/dist/core/option/option.js +17 -36
  25. package/dist/core/parameter.d.ts +25 -12
  26. package/dist/core/parameter.js +18 -12
  27. package/dist/core/when/config.d.ts +20 -0
  28. package/dist/core/when/config.js +4 -0
  29. package/dist/core/when/constrain.d.ts +14 -0
  30. package/dist/core/when/index.d.ts +5 -0
  31. package/dist/core/when/index.js +2 -0
  32. package/dist/core/when/nullability.d.ts +18 -0
  33. package/dist/core/when/nullability.js +1 -0
  34. package/dist/core/when/resolve.d.ts +18 -0
  35. package/dist/core/when/resolve.js +22 -0
  36. package/dist/index.d.ts +6 -9
  37. package/dist/index.js +1 -2
  38. package/dist/{config.d.ts → model.d.ts} +1 -1
  39. package/dist/model.js +1 -0
  40. package/dist/paths.d.ts +5 -2
  41. package/dist/resolve/index.d.ts +2 -2
  42. package/dist/resolve/instance.d.ts +2 -2
  43. package/dist/resolve/models.d.ts +1 -1
  44. package/dist/resolve/order.d.ts +5 -4
  45. package/dist/resolve/order.js +8 -8
  46. package/dist/resolve/render.d.ts +4 -4
  47. package/dist/resolve/render.js +49 -60
  48. package/dist/resolve/validate.d.ts +6 -5
  49. package/dist/resolve/validate.js +5 -4
  50. package/dist/schemas/index.d.ts +0 -4
  51. package/dist/schemas/index.js +0 -2
  52. package/dist/serialise/deserialise.js +6 -6
  53. package/dist/serialise/index.d.ts +2 -2
  54. package/dist/serialise/index.js +1 -1
  55. package/dist/{schemas/serialise.d.ts → serialise/schemas.d.ts} +184 -162
  56. package/dist/{schemas/serialise.js → serialise/schemas.js} +24 -25
  57. package/dist/serialise/serialise.d.ts +1 -1
  58. package/dist/serialise/serialise.js +9 -3
  59. package/dist/ui.d.ts +10 -8
  60. package/dist/ui.js +37 -19
  61. package/package.json +2 -1
  62. package/dist/assert/assert.d.ts +0 -28
  63. package/dist/assert/assert.js +0 -28
  64. package/dist/assert/expectation.d.ts +0 -20
  65. package/dist/assert/index.d.ts +0 -3
  66. package/dist/assert/index.js +0 -2
  67. package/dist/schemas/layout.d.ts +0 -52
  68. package/dist/schemas/layout.js +0 -6
  69. /package/dist/{config.js → core/when/constrain.js} +0 -0
@@ -2,10 +2,9 @@ import type { GraphPath, GraphPaths } from '../graph';
2
2
  import { BuilderOption } from './option.js';
3
3
  export type BuilderOptionGraphs = ReadonlyArray<BuilderOptionGraph>;
4
4
  export declare class BuilderOptionGraph {
5
+ #private;
5
6
  readonly paths: GraphPaths;
6
7
  constructor(paths?: GraphPaths);
7
- static merge(...graphs: BuilderOptionGraphs): BuilderOptionGraph;
8
- has(name: string): boolean;
9
8
  get(name: string): GraphPath;
10
9
  add(option: BuilderOption): BuilderOptionGraph;
11
10
  }
@@ -1,3 +1,4 @@
1
+ import { crossProduct } from '../graph.js';
1
2
  import * as v from 'valibot';
2
3
  import { check } from '../../check.js';
3
4
  import { BuilderOption, BuilderOptionValuesSchema } from './option.js';
@@ -7,18 +8,13 @@ export class BuilderOptionGraph {
7
8
  constructor(paths = []) {
8
9
  this.paths = paths;
9
10
  }
10
- static merge(...graphs) {
11
- return new BuilderOptionGraph(graphs.flatMap((graph) => graph.paths));
12
- }
13
- has(name) {
14
- return this.paths.some((graphPath) => graphPath.name === name);
15
- }
16
11
  get(name) {
17
12
  const graphPath = this.paths.find((graphPath) => graphPath.name === name);
18
13
  check.truthy(graphPath, `Option '${name}' not found in graph! ❌`);
19
14
  return graphPath;
20
15
  }
21
16
  add(option) {
17
+ check.falsy(this.#has(option.name), `Duplicate option name '${option.name}'! ❌`);
22
18
  const dependencyKeys = option.dependencyKeys();
23
19
  if (dependencyKeys.length === 0) {
24
20
  const values = optionValues(option);
@@ -49,6 +45,9 @@ export class BuilderOptionGraph {
49
45
  { name: option.name, keys: merged.keys, models: finalModels }
50
46
  ]);
51
47
  }
48
+ #has(name) {
49
+ return this.paths.some((graphPath) => graphPath.name === name);
50
+ }
52
51
  }
53
52
  function mergePaths(dependencyKeys, graphPaths) {
54
53
  const dependencyPaths = Array.from(dependencyKeys).map((dependencyKey) => {
@@ -59,7 +58,7 @@ function mergePaths(dependencyKeys, graphPaths) {
59
58
  const [first, ...rest] = dependencyPaths;
60
59
  return rest.reduce((merged, next) => {
61
60
  const keys = new Set([...merged.keys, ...next.keys, next.name]);
62
- const models = next.models.flatMap((nextModel) => merged.models.map((mergedModel) => ({ ...nextModel, ...mergedModel })));
61
+ const models = crossProduct(next.models, merged.models);
63
62
  return { keys, models };
64
63
  }, { keys: new Set([...first.keys, first.name]), models: first.models });
65
64
  }
@@ -1,97 +1,70 @@
1
- import type { BuilderPrimitive } from '../../config';
2
- import type { BuilderPath, BuilderPaths, BuilderResolvePath, BuilderValidPath } from '../../paths';
3
- import type { BuilderStateMerge, BuilderState } from '../builder';
4
- import type { Builder } from '../builder';
5
- import type { BuilderOptionValueType, BuilderOptionValues, BuilderOptionValuesMap } from './option';
6
- import type { BuilderOption } from './option';
1
+ import type { BuilderPrimitive } from '../../model';
2
+ import type { BuilderPath, BuilderResolvePath, BuilderValidPath, BuilderValidPaths } from '../../paths';
3
+ import type { BuilderMerge, BuilderState } from '../builder';
4
+ import type { BuilderWhenEnableConfig, BuilderWhenMatchConfig, BuilderWhenUnlessConfig, WhenNullability, WhenPathsNullable } from '../when/index';
5
+ import type { BuilderOption, BuilderOptionValueType, BuilderOptionValues, BuilderOptionValuesMap } from './option';
7
6
  import { BuilderParameter } from '../parameter.js';
8
- export type BuilderOptionEnableConfig<Values extends BuilderOptionValues | BuilderParameter = BuilderOptionValues | BuilderParameter> = {
9
- readonly type: 'enable';
10
- readonly values: Values;
11
- };
12
- export type BuilderOptionMatchConfig<SelectMap extends BuilderOptionValuesMap | BuilderParameter = BuilderOptionValuesMap | BuilderParameter, MatchPath extends BuilderPath = BuilderPath, Values extends BuilderOptionValues | BuilderParameter = BuilderOptionValues | BuilderParameter> = {
13
- readonly type: 'match';
14
- readonly matchPath: MatchPath;
15
- readonly selectMap: SelectMap;
16
- readonly values: Values;
17
- };
18
- export type BuilderOptionUnlessConfig<Values extends BuilderOptionValues | BuilderParameter = BuilderOptionValues | BuilderParameter, UnlessPath extends BuilderPath = BuilderPath> = {
19
- readonly type: 'unless';
20
- readonly unlessPath: UnlessPath;
21
- readonly disabledValues: ReadonlyArray<BuilderPrimitive>;
22
- readonly values: Values;
23
- };
7
+ export type BuilderOptionEnableConfig<Values extends BuilderOptionValues | BuilderParameter = BuilderOptionValues | BuilderParameter> = BuilderWhenEnableConfig<OptionPayload<Values>>;
8
+ export type BuilderOptionMatchConfig<SelectMap extends BuilderOptionValuesMap | BuilderParameter = BuilderOptionValuesMap | BuilderParameter, MatchPath extends BuilderPath = BuilderPath> = BuilderWhenMatchConfig<SelectMap, MatchPath>;
9
+ export type BuilderOptionUnlessConfig<Values extends BuilderOptionValues | BuilderParameter = BuilderOptionValues | BuilderParameter, UnlessPath extends BuilderPath = BuilderPath> = BuilderWhenUnlessConfig<OptionPayload<Values>, UnlessPath>;
24
10
  export type BuilderOptionWhenConfig = BuilderOptionEnableConfig | BuilderOptionMatchConfig | BuilderOptionUnlessConfig;
25
11
  export type BuilderOptionWhenConfigValues<Config extends BuilderOptionWhenConfig> = Config extends {
26
12
  readonly values: infer Values;
27
- } ? Values extends BuilderOptionValues ? Values : never : never;
28
- type ExtractWhenParameter<Config extends BuilderOptionWhenConfig> = Config extends {
29
- readonly values: infer Values;
30
- } ? Values extends BuilderParameter ? Values : never : never;
13
+ } ? Values extends BuilderOptionValues ? Values : never : Config extends BuilderOptionMatchConfig<infer SelectMapType> ? SelectMapType extends BuilderOptionValuesMap ? NonNullable<SelectMapType[keyof SelectMapType]> & BuilderOptionValues : never : never;
31
14
  export type BuilderOptionMethod<State extends BuilderState> = {
32
- <const Name extends string, const Values extends BuilderOptionValues>(name: Name, values: Values): Builder<BuilderStateMerge<State, {
15
+ <const Name extends string, const Values extends BuilderOptionValues>(name: Name, values: Values): BuilderMerge<State, {
33
16
  model: State['model'] & {
34
17
  [K in Name]: BuilderOptionValueType<Values>;
35
18
  };
36
19
  options: [...State['options'], BuilderOption<Name, Values>];
37
- }>>;
38
- <const Name extends string>(name: Name, values: BuilderParameter): Builder<BuilderStateMerge<State, {
20
+ }>;
21
+ <const Name extends string>(name: Name, values: BuilderParameter): BuilderMerge<State, {
39
22
  model: State['model'] & {
40
23
  [K in Name]: string;
41
24
  };
42
25
  options: [...State['options'], BuilderOption<Name, BuilderParameter>];
43
- }>>;
26
+ }>;
44
27
  when: {
45
- <const GatePaths extends ReadonlyArray<BuilderValidPath<State['model']>>, const Name extends string>(gatePaths: GatePaths, name: Name, config: BuilderParameter): Builder<BuilderStateMerge<State, {
28
+ <const GatePaths extends BuilderValidPaths<State['model']>, const Name extends string>(gatePaths: GatePaths, name: Name, config: BuilderParameter): BuilderMerge<State, {
46
29
  model: State['model'] & {
47
- [K in Name]: string | OptionGatePathsNullable<State['model'], GatePaths>;
30
+ [K in Name]: string | WhenPathsNullable<State['model'], GatePaths>;
48
31
  };
49
32
  options: [...State['options'], BuilderOption<Name, BuilderParameter>];
50
- components: State['components'];
51
- collections: State['collections'];
52
- }>>;
53
- <const GatePaths extends ReadonlyArray<BuilderValidPath<State['model']>>, const Name extends string, const Config extends BuilderOptionWhenConfig>(gatePaths: GatePaths, name: Name, config: Config & WhenConfigConstrained<State['model'], Config>): Builder<BuilderStateMerge<State, WhenConfigResult<State, GatePaths, Name, Config>>>;
33
+ }>;
34
+ <const GatePaths extends BuilderValidPaths<State['model']>, const Name extends string, const Config extends BuilderOptionWhenConfig>(gatePaths: GatePaths, name: Name, config: Config & ValidOptionWhenConfig<State['model'], Config>): BuilderMerge<State, OptionWhenResult<State, GatePaths, Name, Config>>;
54
35
  };
55
36
  };
56
- declare function createEnable<const Values extends BuilderOptionValues>(values: Values): BuilderOptionEnableConfig<Values>;
57
- declare function createEnableParameter(): BuilderParameter;
58
37
  export declare const enable: typeof createEnable & {
59
- parameter: typeof createEnableParameter;
38
+ parameter: () => BuilderParameter;
60
39
  };
61
- declare function createMatch<const MatchPath extends BuilderPath, const SelectMap extends BuilderOptionValuesMap>(matchPath: MatchPath, selectMap: SelectMap): BuilderOptionMatchConfig<SelectMap, MatchPath>;
62
- declare function createMatchParameter(): BuilderParameter;
63
40
  export declare const match: typeof createMatch & {
64
- parameter: typeof createMatchParameter;
41
+ parameter: () => BuilderParameter;
65
42
  };
66
- declare function createUnless<const Values extends BuilderOptionValues, const UnlessPath extends BuilderPath>(unlessPath: UnlessPath, disabledValues: ReadonlyArray<BuilderPrimitive>, values: Values): BuilderOptionUnlessConfig<Values, UnlessPath>;
67
- declare function createUnlessParameter(): BuilderParameter;
68
43
  export declare const unless: typeof createUnless & {
69
- parameter: typeof createUnlessParameter;
44
+ parameter: () => BuilderParameter;
70
45
  };
71
- type OptionConfigNullable<Config extends BuilderOptionWhenConfig> = Config extends BuilderOptionUnlessConfig ? null : Config extends BuilderOptionMatchConfig<infer SelectMapType> ? SelectMapType extends BuilderOptionValuesMap ? null extends SelectMapType[keyof SelectMapType] ? null : never : null : never;
72
- type OptionGatePathNullable<Model, Path extends BuilderPath> = null extends BuilderResolvePath<Model, Path> ? null : never;
73
- type OptionGatePathsNullable<Model, GatePaths extends BuilderPaths> = GatePaths extends readonly [
74
- infer Head extends BuilderPath,
75
- ...infer Tail extends BuilderPaths
76
- ] ? OptionGatePathNullable<Model, Head> | OptionGatePathsNullable<Model, Tail> : never;
77
- type OptionWhenNullability<Model, GatePaths extends BuilderPaths, Config extends BuilderOptionWhenConfig> = OptionGatePathsNullable<Model, GatePaths> | OptionConfigNullable<Config>;
78
- type WhenConfigResult<State extends BuilderState, GatePaths extends BuilderPaths, Name extends string, Config extends BuilderOptionWhenConfig> = ExtractWhenParameter<Config> extends never ? {
46
+ type OptionPayload<Values extends BuilderOptionValues | BuilderParameter = BuilderOptionValues | BuilderParameter> = {
47
+ readonly values: Values;
48
+ };
49
+ type WhenParameterOf<Config extends BuilderOptionWhenConfig> = Config extends {
50
+ readonly values: infer Values;
51
+ } ? Values extends BuilderParameter ? Values : never : never;
52
+ type OptionWhenResult<State extends BuilderState, GatePaths extends BuilderValidPaths<State['model']>, Name extends string, Config extends BuilderOptionWhenConfig> = WhenParameterOf<Config> extends never ? {
79
53
  model: State['model'] & {
80
- [K in Name]: BuilderOptionValueType<BuilderOptionWhenConfigValues<Config>> | OptionWhenNullability<State['model'], GatePaths, Config>;
54
+ [K in Name]: BuilderOptionValueType<BuilderOptionWhenConfigValues<Config>> | WhenNullability<State['model'], GatePaths, Config>;
81
55
  };
82
56
  options: [...State['options'], BuilderOption<Name, BuilderOptionWhenConfigValues<Config>>];
83
- components: State['components'];
84
- collections: State['collections'];
85
57
  } : {
86
58
  model: State['model'] & {
87
59
  [K in Name]: string | null;
88
60
  };
89
- options: [...State['options'], BuilderOption<Name, ExtractWhenParameter<Config>>];
90
- components: State['components'];
91
- collections: State['collections'];
61
+ options: [...State['options'], BuilderOption<Name, WhenParameterOf<Config>>];
92
62
  };
93
- type MatchKeyOfConfig<Model, Config extends BuilderOptionWhenConfig> = Config extends BuilderOptionMatchConfig<any, infer MatchPath> ? BuilderResolvePath<Model, MatchPath> & string : string;
94
- type WhenConfigConstrained<Model, Config extends BuilderOptionWhenConfig> = Config extends BuilderOptionMatchConfig<infer SelectMap, infer MatchPath> ? SelectMap extends BuilderParameter ? BuilderOptionMatchConfig<SelectMap, MatchPath & Readonly<BuilderValidPath<Model>>> : BuilderOptionMatchConfig<Record<MatchKeyOfConfig<Model, Config>, BuilderOptionValuesMap[string]>, MatchPath & Readonly<BuilderValidPath<Model>>> : Config extends BuilderOptionUnlessConfig<infer Values, infer UnlessPath> ? Values extends BuilderParameter ? BuilderOptionUnlessConfig<Values, UnlessPath & Readonly<BuilderValidPath<Model>>> : Config & {
63
+ type WhenMatchKeyOf<Model, Config extends BuilderOptionWhenConfig> = Config extends BuilderOptionMatchConfig<any, infer MatchPath> ? BuilderResolvePath<Model, MatchPath> & string : string;
64
+ type ValidOptionWhenConfig<Model, Config extends BuilderOptionWhenConfig> = Config extends BuilderOptionMatchConfig<infer SelectMap, infer MatchPath> ? SelectMap extends BuilderParameter ? BuilderOptionMatchConfig<SelectMap, MatchPath & Readonly<BuilderValidPath<Model>>> : BuilderOptionMatchConfig<Record<WhenMatchKeyOf<Model, Config>, BuilderOptionValuesMap[string]>, MatchPath & Readonly<BuilderValidPath<Model>>> : Config extends BuilderOptionUnlessConfig<infer Values, infer UnlessPath> ? Values extends BuilderParameter ? BuilderOptionUnlessConfig<Values, UnlessPath & Readonly<BuilderValidPath<Model>>> : Config & {
95
65
  readonly unlessPath: Readonly<BuilderValidPath<Model>>;
96
66
  } : Config;
67
+ declare function createEnable<const Values extends BuilderOptionValues>(values: Values): BuilderOptionEnableConfig<Values>;
68
+ declare function createMatch<const MatchPath extends BuilderPath, const SelectMap extends BuilderOptionValuesMap>(matchPath: MatchPath, selectMap: SelectMap): BuilderOptionMatchConfig<SelectMap, MatchPath>;
69
+ declare function createUnless<const Values extends BuilderOptionValues, const UnlessPath extends BuilderPath>(unlessPath: UnlessPath, disabledValues: ReadonlyArray<BuilderPrimitive>, values: Values): BuilderOptionUnlessConfig<Values, UnlessPath>;
97
70
  export {};
@@ -1,23 +1,13 @@
1
1
  import { BuilderParameter } from '../parameter.js';
2
+ export const enable = Object.assign(createEnable, { parameter: () => new BuilderParameter() });
3
+ export const match = Object.assign(createMatch, { parameter: () => new BuilderParameter() });
4
+ export const unless = Object.assign(createUnless, { parameter: () => new BuilderParameter() });
2
5
  function createEnable(values) {
3
6
  return { type: 'enable', values };
4
7
  }
5
- function createEnableParameter() {
6
- return new BuilderParameter();
7
- }
8
- export const enable = Object.assign(createEnable, { parameter: createEnableParameter });
9
8
  function createMatch(matchPath, selectMap) {
10
- const values = Object.values(selectMap).find((value) => value !== null);
11
- return { type: 'match', matchPath, selectMap, values };
12
- }
13
- function createMatchParameter() {
14
- return new BuilderParameter();
9
+ return { type: 'match', matchPath, selectMap };
15
10
  }
16
- export const match = Object.assign(createMatch, { parameter: createMatchParameter });
17
11
  function createUnless(unlessPath, disabledValues, values) {
18
12
  return { type: 'unless', unlessPath, disabledValues, values };
19
13
  }
20
- function createUnlessParameter() {
21
- return new BuilderParameter();
22
- }
23
- export const unless = Object.assign(createUnless, { parameter: createUnlessParameter });
@@ -1,16 +1,17 @@
1
1
  import type { BuilderPaths } from '../../paths';
2
- import type { BuilderOptionValues } from '../../schemas/serialise';
3
- import type { BuilderOptionWhenConfig } from './method';
4
2
  import type { BuilderParameter } from '../parameter';
3
+ import type { BuilderOptionWhenConfig } from './method';
5
4
  import type { BuilderSelectTypeValues } from './select';
6
5
  import * as v from 'valibot';
7
6
  import { BuilderSelectType } from './select.js';
8
7
  import { BuilderToggleType } from './toggle.js';
8
+ export declare const BuilderOptionValuesSchema: v.UnionSchema<[v.InstanceSchema<typeof BuilderSelectType, undefined>, v.InstanceSchema<typeof BuilderToggleType, undefined>], undefined>;
9
+ export type BuilderOptionValues = v.InferOutput<typeof BuilderOptionValuesSchema>;
10
+ export declare const BuilderOptionValuesMapSchema: v.RecordSchema<v.StringSchema<undefined>, v.NullableSchema<v.UnionSchema<[v.InstanceSchema<typeof BuilderSelectType, undefined>, v.InstanceSchema<typeof BuilderToggleType, undefined>], undefined>, undefined>, undefined>;
11
+ export type BuilderOptionValuesMap = v.InferOutput<typeof BuilderOptionValuesMapSchema>;
9
12
  export type BuilderOptionValueSchema = v.GenericSchema<string | number | boolean | null>;
10
13
  export type BuilderSelectTypeGeneric = BuilderSelectType<BuilderSelectTypeValues, BuilderOptionValueSchema>;
11
14
  export type BuilderToggleTypeGeneric = BuilderToggleType<BuilderOptionValueSchema>;
12
- export type { BuilderOptionValues, BuilderOptionValuesMap } from '../../schemas/serialise';
13
- export { BuilderOptionValuesMapSchema, BuilderOptionValuesSchema } from '../../schemas/serialise.js';
14
15
  export type BuilderOptionValueType<Values> = Values extends BuilderParameter ? string : Values extends {
15
16
  readonly value: infer Value;
16
17
  } ? Value : never;
@@ -1,10 +1,13 @@
1
1
  import * as v from 'valibot';
2
2
  import { check } from '../../check.js';
3
- import { readPath } from '../../paths.js';
4
- import { BuilderOptionValuesMapSchema, BuilderOptionValuesSchema } from '../../schemas/serialise.js';
3
+ import { resolve } from '../when/index.js';
5
4
  import { BuilderSelectType } from './select.js';
6
5
  import { BuilderToggleType } from './toggle.js';
7
- export { BuilderOptionValuesMapSchema, BuilderOptionValuesSchema } from '../../schemas/serialise.js';
6
+ export const BuilderOptionValuesSchema = v.union([
7
+ v.instance(BuilderSelectType),
8
+ v.instance(BuilderToggleType)
9
+ ]);
10
+ export const BuilderOptionValuesMapSchema = v.record(v.string(), v.nullable(BuilderOptionValuesSchema));
8
11
  export class BuilderOption {
9
12
  name;
10
13
  values;
@@ -17,44 +20,22 @@ export class BuilderOption {
17
20
  this.config = config;
18
21
  }
19
22
  resolve(model) {
20
- const { values } = this;
21
- check.assert(BuilderOptionValuesSchema, values);
22
- const resolved = new BuilderOption(this.name, values);
23
- if (this.config === null) {
24
- return resolved;
25
- }
26
- if (!this.gatePaths.every((path) => !!readPath(model, path))) {
27
- return null;
28
- }
29
- switch (this.config.type) {
30
- case 'enable': {
31
- check.assert(BuilderOptionValuesSchema, this.config.values);
32
- return resolved;
33
- }
34
- case 'match': {
35
- const { selectMap } = this.config;
36
- check.assert(BuilderOptionValuesMapSchema, selectMap);
37
- const matchPath = this.config.matchPath;
38
- const entry = selectMap[String(readPath(model, matchPath))];
39
- return entry ? new BuilderOption(this.name, entry) : null;
40
- }
41
- case 'unless': {
42
- check.assert(BuilderOptionValuesSchema, this.config.values);
43
- const value = readPath(model, this.config.unlessPath);
44
- return !this.config.disabledValues.includes(value)
45
- ? resolved
46
- : null;
47
- }
48
- }
23
+ check.assert(BuilderOptionValuesSchema, this.values);
24
+ return resolve(this, model, (selectMap, matchValue) => {
25
+ check.assert(BuilderOptionValuesMapSchema, selectMap);
26
+ const entry = selectMap[matchValue];
27
+ return entry ? new BuilderOption(this.name, entry) : null;
28
+ });
49
29
  }
50
30
  dependencyKeys() {
51
- const keys = new Set(this.gatePaths.map((path) => String(path[0])));
31
+ const keys = new Set(this.gatePaths.map(([first]) => String(first)));
52
32
  if (this.config?.type === 'match') {
53
- const matchPath = this.config.matchPath;
54
- keys.add(String(matchPath[0]));
33
+ const [firstMatchSegment] = this.config.matchPath;
34
+ keys.add(String(firstMatchSegment));
55
35
  }
56
36
  else if (this.config?.type === 'unless') {
57
- keys.add(String(this.config.unlessPath[0]));
37
+ const [firstUnlessSegment] = this.config.unlessPath;
38
+ keys.add(String(firstUnlessSegment));
58
39
  }
59
40
  return Array.from(keys);
60
41
  }
@@ -1,35 +1,48 @@
1
+ import type { BuilderValidPath } from '../paths';
1
2
  import type { BuilderState, BuilderStateMerge } from './builder';
2
- import type { BuilderOption, BuilderOptionEntries, BuilderOptionValues, BuilderOptionWhenConfig } from './option/index';
3
+ import type { BuilderOption, BuilderOptionEnableConfig, BuilderOptionEntries, BuilderOptionMatchConfig, BuilderOptionUnlessConfig, BuilderOptionValues, BuilderOptionWhenConfig } from './option/index';
4
+ import type { WhenConfigNullable } from './when/index';
5
+ import * as v from 'valibot';
3
6
  export declare class BuilderParameter {
4
7
  readonly parameter: true;
5
8
  }
6
- export declare function bindOptions<Bindings extends Record<string, unknown>>(options: BuilderOptionEntries, bindings: Bindings): BuilderOptionEntries;
9
+ export declare const BuilderParameterSchema: v.InstanceSchema<typeof BuilderParameter, undefined>;
7
10
  export type ParameterisedOptions<Options extends BuilderOptionEntries> = {
8
11
  [K in keyof Options]: Options[K] extends BuilderOption<infer Name, infer Values> ? Values extends BuilderParameter ? BuilderOption<Name, Values> : never : never;
9
12
  }[number];
10
13
  export type BuilderBindings<State extends BuilderState> = {
11
- readonly [P in ParameterisedOptions<State['options']> as P['name']]?: BuilderOptionValues | BuilderOptionWhenConfig;
14
+ readonly [P in ParameterisedOptions<State['options']> as P['name']]?: ValidBinding<State['model']>;
12
15
  };
13
16
  export type ReplaceOption<Options extends BuilderOptionEntries, BoundNames extends string> = Options extends readonly [
14
17
  infer Head extends BuilderOption,
15
18
  ...infer Tail extends BuilderOptionEntries
16
19
  ] ? Head extends BuilderOption<infer Name, infer Values> ? Values extends BuilderParameter ? Name extends BoundNames ? [...ReplaceOption<Tail, BoundNames>] : [Head, ...ReplaceOption<Tail, BoundNames>] : [Head, ...ReplaceOption<Tail, BoundNames>] : [Head, ...ReplaceOption<Tail, BoundNames>] : [];
17
- type BindingModelType<Binding> = Binding extends {
20
+ export type BuilderBoundState<State extends BuilderState, Bindings extends Record<string, unknown>> = BuilderStateMerge<State, {
21
+ options: ReplaceOption<State['options'], Extract<keyof Bindings, string>>;
22
+ model: Omit<State['model'], keyof Bindings> & {
23
+ [K in Extract<keyof Bindings, string>]: BindingModelType<Bindings[K]>;
24
+ };
25
+ }>;
26
+ export declare function extractValues(config: BuilderOptionWhenConfig): BuilderOptionValues;
27
+ export declare function bindOptions<Bindings extends Record<string, unknown>>(options: BuilderOptionEntries, bindings: Bindings): BuilderOptionEntries;
28
+ type ValidEnableConfig = BuilderOptionEnableConfig<BuilderOptionEnableConfig['values']>;
29
+ type ValidMatchConfig<Model> = BuilderOptionMatchConfig<BuilderOptionMatchConfig['selectMap'], Readonly<BuilderValidPath<Model>>>;
30
+ type ValidUnlessConfig<Model> = BuilderOptionUnlessConfig<BuilderOptionUnlessConfig['values'], Readonly<BuilderValidPath<Model>>>;
31
+ type ValidBinding<Model> = BuilderOptionValues | ValidEnableConfig | ValidMatchConfig<Model> | ValidUnlessConfig<Model>;
32
+ type BindingConfigNullable<Binding> = Binding extends {
33
+ readonly type: string;
34
+ } ? WhenConfigNullable<Binding> : never;
35
+ type BindingValueType<Binding> = Binding extends {
18
36
  readonly type: 'match';
19
37
  readonly selectMap: infer SelectMap extends Record<string, unknown>;
20
38
  } ? NonNullable<SelectMap[keyof SelectMap]> extends {
21
39
  readonly value: infer Value;
22
- } ? Value | null : string | null : Binding extends {
40
+ } ? Value : string : Binding extends {
23
41
  readonly values: infer Values;
24
42
  } ? Values extends {
25
43
  readonly value: infer Value;
26
- } ? Value | null : string | null : Binding extends {
44
+ } ? Value : string : Binding extends {
27
45
  readonly value: infer Value;
28
46
  } ? Value : string;
29
- export type BuilderBoundState<State extends BuilderState, Bindings extends Record<string, unknown>> = BuilderStateMerge<State, {
30
- options: ReplaceOption<State['options'], Extract<keyof Bindings, string>>;
31
- model: Omit<State['model'], keyof Bindings> & {
32
- [K in Extract<keyof Bindings, string>]: BindingModelType<Bindings[K]>;
33
- };
34
- }>;
47
+ type BindingModelType<Binding> = BindingValueType<Binding> | BindingConfigNullable<Binding>;
35
48
  export {};
@@ -1,25 +1,31 @@
1
+ import * as v from 'valibot';
2
+ import { BuilderWhenConfigSchema } from './when/index.js';
1
3
  export class BuilderParameter {
2
4
  parameter = true;
3
5
  }
4
- function createOption(option, values, config) {
5
- const OptionConstructor = option.constructor;
6
- return new OptionConstructor(option.name, values, option.gatePaths, config);
7
- }
8
- function isWhenConfig(binding) {
9
- return typeof binding === 'object' && binding !== null && 'type' in binding;
10
- }
11
- function bindOption(option, binding) {
12
- if (isWhenConfig(binding)) {
13
- return createOption(option, binding.values, binding);
6
+ export const BuilderParameterSchema = v.instance(BuilderParameter);
7
+ export function extractValues(config) {
8
+ if (config.type === 'match') {
9
+ return Object.values(config.selectMap).find((value) => value !== null);
14
10
  }
15
- return createOption(option, binding, option.config);
11
+ return config.values;
16
12
  }
17
13
  export function bindOptions(options, bindings) {
18
14
  return options.map((option) => {
19
15
  const binding = bindings[option.name];
20
- if (binding === undefined) {
16
+ if (binding == null) {
21
17
  return option;
22
18
  }
23
19
  return bindOption(option, binding);
24
20
  });
25
21
  }
22
+ function createOption(option, values, config) {
23
+ const OptionConstructor = option.constructor;
24
+ return new OptionConstructor(option.name, values, option.gatePaths, config);
25
+ }
26
+ function bindOption(option, binding) {
27
+ if (v.is(BuilderWhenConfigSchema, binding)) {
28
+ return createOption(option, extractValues(binding), binding);
29
+ }
30
+ return createOption(option, binding, option.config);
31
+ }
@@ -0,0 +1,20 @@
1
+ import type { BuilderPrimitive } from '../../model';
2
+ import type { BuilderPath } from '../../paths';
3
+ import * as v from 'valibot';
4
+ export declare const BuilderWhenConfigSchema: v.ObjectSchema<{
5
+ readonly type: v.PicklistSchema<["enable", "match", "unless"], undefined>;
6
+ }, undefined>;
7
+ export type BuilderWhenConfig = v.InferOutput<typeof BuilderWhenConfigSchema>;
8
+ export type BuilderWhenEnableConfig<Payload> = {
9
+ readonly type: 'enable';
10
+ } & Payload;
11
+ export type BuilderWhenMatchConfig<SelectMap = Record<string, unknown>, MatchPath extends BuilderPath = BuilderPath> = {
12
+ readonly type: 'match';
13
+ readonly matchPath: MatchPath;
14
+ readonly selectMap: SelectMap;
15
+ };
16
+ export type BuilderWhenUnlessConfig<Payload, UnlessPath extends BuilderPath = BuilderPath> = {
17
+ readonly type: 'unless';
18
+ readonly unlessPath: UnlessPath;
19
+ readonly disabledValues: ReadonlyArray<BuilderPrimitive>;
20
+ } & Payload;
@@ -0,0 +1,4 @@
1
+ import * as v from 'valibot';
2
+ export const BuilderWhenConfigSchema = v.object({
3
+ type: v.picklist(['enable', 'match', 'unless'])
4
+ });
@@ -0,0 +1,14 @@
1
+ import type { BuilderValidPath } from '../../paths';
2
+ export type WhenConfigConstrained<Model, Config extends {
3
+ readonly type: string;
4
+ }> = Config extends {
5
+ readonly type: 'match';
6
+ readonly matchPath: infer MatchPath;
7
+ } ? Config & {
8
+ readonly matchPath: MatchPath & Readonly<BuilderValidPath<Model>>;
9
+ } : Config extends {
10
+ readonly type: 'unless';
11
+ readonly unlessPath: infer UnlessPath;
12
+ } ? Config & {
13
+ readonly unlessPath: UnlessPath & Readonly<BuilderValidPath<Model>>;
14
+ } : Config;
@@ -0,0 +1,5 @@
1
+ export type { BuilderWhenConfig, BuilderWhenEnableConfig, BuilderWhenMatchConfig, BuilderWhenUnlessConfig } from './config';
2
+ export { BuilderWhenConfigSchema } from './config.js';
3
+ export type { WhenConfigNullable, WhenNullability, WhenPathsNullable } from './nullability';
4
+ export type { WhenConfigConstrained } from './constrain';
5
+ export { resolve } from './resolve.js';
@@ -0,0 +1,2 @@
1
+ export { BuilderWhenConfigSchema } from './config.js';
2
+ export { resolve } from './resolve.js';
@@ -0,0 +1,18 @@
1
+ import type { BuilderPath, BuilderPaths, BuilderResolvePath } from '../../paths';
2
+ export type WhenConfigNullable<Config extends {
3
+ readonly type: string;
4
+ }> = Config extends {
5
+ readonly type: 'unless';
6
+ } ? null : Config extends {
7
+ readonly type: 'match';
8
+ readonly selectMap: infer SelectMap;
9
+ } ? null extends SelectMap[keyof SelectMap] ? null : never : never;
10
+ export type WhenPathsNullable<Model, GatePaths extends BuilderPaths> = GatePaths extends readonly [
11
+ infer Head extends BuilderPath,
12
+ ...infer Tail extends BuilderPaths
13
+ ] ? WhenPathNullable<Model, Head> | WhenPathsNullable<Model, Tail> : never;
14
+ export type WhenNullability<Model, GatePaths extends BuilderPaths, Config extends {
15
+ readonly type: string;
16
+ }> = WhenPathsNullable<Model, GatePaths> | WhenConfigNullable<Config>;
17
+ type WhenPathNullable<Model, Path extends BuilderPath> = null extends BuilderResolvePath<Model, Path> ? null : never;
18
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,18 @@
1
+ import type { BuilderPath, BuilderPaths } from '../../paths';
2
+ export declare function resolve<Entry extends Resolvable>(entry: Entry, model: unknown, onMatch: (selectMap: unknown, matchValue: string) => Entry | null): Entry | null;
3
+ type ResolvableConfig = {
4
+ readonly type: 'enable';
5
+ } | {
6
+ readonly type: 'match';
7
+ readonly matchPath: BuilderPath;
8
+ readonly selectMap: unknown;
9
+ } | {
10
+ readonly type: 'unless';
11
+ readonly unlessPath: BuilderPath;
12
+ readonly disabledValues: ReadonlyArray<unknown>;
13
+ };
14
+ interface Resolvable {
15
+ readonly gatePaths: BuilderPaths;
16
+ readonly config: ResolvableConfig | null;
17
+ }
18
+ export {};
@@ -0,0 +1,22 @@
1
+ import { readPath } from '../../paths.js';
2
+ export function resolve(entry, model, onMatch) {
3
+ if (entry.config === null) {
4
+ return entry;
5
+ }
6
+ if (!entry.gatePaths.every((path) => !!readPath(model, path))) {
7
+ return null;
8
+ }
9
+ switch (entry.config.type) {
10
+ case 'enable': {
11
+ return entry;
12
+ }
13
+ case 'match': {
14
+ const matchValue = String(readPath(model, entry.config.matchPath));
15
+ return onMatch(entry.config.selectMap, matchValue);
16
+ }
17
+ case 'unless': {
18
+ const value = readPath(model, entry.config.unlessPath);
19
+ return !entry.config.disabledValues.includes(value) ? entry : null;
20
+ }
21
+ }
22
+ }
package/dist/index.d.ts CHANGED
@@ -1,15 +1,12 @@
1
- export type { BuilderModelAsserted, BuilderUIModelAsserted } from './assert/assert';
2
- export type { BuilderExpectations } from './assert/index';
3
- export type { BuilderData, BuilderModel, BuilderModelMutable, BuilderModels, BuilderPrimitive, BuilderPrimitives, BuilderVariant, BuilderVariants } from './config';
4
- export type { Builder, BuilderCollectionConfig, BuilderCollectionEntries, BuilderCollectionModelOf, BuilderCollectionNamesOf, BuilderCollectionOf, BuilderComponentEntries, BuilderComponentNamesOf, BuilderFactory, BuilderGeneric, BuilderModelOf, BuilderOptionEntries, BuilderOptionValues, BuilderOptionValuesMap, BuilderPart, BuilderParts, BuilderSelectTypeLabels, BuilderSelectTypeValues, BuilderState, BuilderStateOf } from './core/index';
1
+ export type { BuilderData, BuilderModel, BuilderModels, BuilderPrimitive, BuilderPrimitives, BuilderVariant, BuilderVariants } from './model';
2
+ export type { Builder, Builders, BuilderCollectionEntries, BuilderComponentEntries, BuilderGeneric, BuilderModelOf, BuilderOptionEntries } from './core/index';
5
3
  export type { BuilderModelPaths, BuilderResolvePath, BuilderValidPath } from './paths';
6
4
  export type { BuilderPath, BuilderPaths } from './schemas/index';
7
- export type { BuilderDataValidated, BuilderDescription, BuilderDescriptionItem, BuilderErrorComponentMissing, BuilderErrorComponentUnexpected, BuilderErrorsValidate, BuilderErrorValidate, BuilderErrorVariantInvalid, BuilderErrorVariantMissing, BuilderLayout, BuilderLayoutOption, BuilderLayoutOptions, BuilderLayoutPage, BuilderOrder, BuilderRenderLayoutOption, BuilderRenderLayoutOptions, BuilderRenderPage, BuilderRenderPages, BuilderRenderResult, BuilderValidateResult } from './resolve/index';
5
+ export type { BuilderDataValidated, BuilderDescription, BuilderDescriptionItem, BuilderErrorComponentMissing, BuilderErrorComponentUnexpected, BuilderErrorsValidate, BuilderErrorValidate, BuilderErrorVariantInvalid, BuilderErrorVariantMissing, BuilderOrder, BuilderRenderOption, BuilderRenderOptions, BuilderRenderPage, BuilderRenderPages, BuilderRenderResult, BuilderValidateResult } from './resolve/index';
8
6
  export type { BuilderUICollection, BuilderUIDescribe, BuilderUIItem, BuilderUIItems, BuilderUIPage } from './schemas/index';
9
- export type { BuilderUI, BuilderUIFactory, BuilderUIPart, BuilderUIParts } from './ui';
10
- export type { BuilderCollectionSerialised, BuilderCollectionWhenConfigSerialised, BuilderComponentSerialised, BuilderOptionSerialised, BuilderOptionWhenConfigSerialised, BuilderSelectTypeSerialised, BuilderSerialised, BuilderToggleTypeSerialised, BuilderUISerialised, BuilderValuesSerialised } from './serialise/index';
11
- export { BuilderExpectation } from './assert/expectation.js';
12
- export { assert, component, option } from './assert/index.js';
7
+ export type { BuilderUI, BuilderUIs } from './ui';
8
+ export type { BuilderCollectionSerialised, BuilderCollectionWhenConfigSerialised, BuilderComponentSerialised, BuilderOptionSerialised, BuilderOptionWhenConfigSerialised, BuilderParameterSerialised, BuilderSelectTypeSerialised, BuilderSerialised, BuilderToggleTypeSerialised, BuilderUISerialised, BuilderValuesSerialised } from './serialise/index';
9
+ export { BuilderExpectation, has } from './core/index.js';
13
10
  export { builder, BuilderCollection, BuilderComponent, BuilderOption, BuilderParameter, BuilderSelectType, BuilderToggleType, collection, enable, match, select, toggleBoolean, toggleNumber, toggleString, unless } from './core/index.js';
14
11
  export { instance, models, order, ordinal, render, validate } from './resolve/index.js';
15
12
  export { deserialise, serialise } from './serialise/index.js';
package/dist/index.js CHANGED
@@ -1,5 +1,4 @@
1
- export { BuilderExpectation } from './assert/expectation.js';
2
- export { assert, component, option } from './assert/index.js';
1
+ export { BuilderExpectation, has } from './core/index.js';
3
2
  export { builder, BuilderCollection, BuilderComponent, BuilderOption, BuilderParameter, BuilderSelectType, BuilderToggleType, collection, enable, match, select, toggleBoolean, toggleNumber, toggleString, unless } from './core/index.js';
4
3
  export { instance, models, order, ordinal, render, validate } from './resolve/index.js';
5
4
  export { deserialise, serialise } from './serialise/index.js';
@@ -3,7 +3,7 @@ export type { BuilderPrimitive, BuilderPrimitives } from './schemas/index';
3
3
  export type BuilderModel = {
4
4
  readonly [key: string]: BuilderPrimitive | BuilderModels;
5
5
  };
6
- export type BuilderModelMutable = Record<string, unknown>;
6
+ export type BuilderModelInput = Record<string, unknown>;
7
7
  export type BuilderModels = ReadonlyArray<BuilderModel>;
8
8
  export type BuilderVariant = {
9
9
  readonly model: BuilderModel;
package/dist/model.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/dist/paths.d.ts CHANGED
@@ -1,10 +1,13 @@
1
- export type { BuilderPath, BuilderPaths } from './schemas/index';
2
1
  import type { BuilderGeneric, BuilderModelOf } from './core/index';
3
2
  import type { BuilderPath, BuilderPrimitive } from './schemas/index';
3
+ export type { BuilderPath, BuilderPaths } from './schemas/index';
4
4
  export type BuilderValidPath<Model, Depth extends ReadonlyArray<never> = []> = Depth['length'] extends 10 ? never : Model extends BuilderPrimitive | null ? never : Model extends ReadonlyArray<infer Item> ? [number] | [number, ...BuilderValidPath<Item, [...Depth, never]>] : {
5
5
  [Key in keyof Model & string]: [Key] | (Model[Key] extends BuilderPrimitive | null ? never : [Key, ...BuilderValidPath<Model[Key], [...Depth, never]>]);
6
6
  }[keyof Model & string];
7
- export type BuilderModelPaths<Builder extends BuilderGeneric> = ReadonlyArray<BuilderValidPath<BuilderModelOf<Builder>>>;
7
+ export type BuilderValidPaths<Model> = ReadonlyArray<BuilderValidPath<Model>>;
8
+ export type BuilderModelPaths<Builder extends BuilderGeneric | null> = [Builder] extends [
9
+ BuilderGeneric
10
+ ] ? BuilderValidPaths<BuilderModelOf<Builder>> : ReadonlyArray<never>;
8
11
  export type BuilderResolvePath<Model, Path extends BuilderPath> = Path extends readonly [
9
12
  infer Head extends keyof Model & string
10
13
  ] ? Model[Head] : Path extends readonly [
@@ -1,7 +1,7 @@
1
1
  export type { BuilderOrder } from './order';
2
- export type { BuilderRenderLayoutOption, BuilderRenderLayoutOptions, BuilderRenderPage, BuilderRenderPages, BuilderRenderResult } from './render';
2
+ export type { BuilderRenderOption, BuilderRenderOptions, BuilderRenderPage, BuilderRenderPages, BuilderRenderResult } from './render';
3
3
  export type { BuilderDataValidated, BuilderErrorVariantInvalid, BuilderErrorComponentMissing, BuilderErrorVariantMissing, BuilderErrorComponentUnexpected, BuilderErrorValidate, BuilderErrorsValidate, BuilderValidateResult } from './validate';
4
- export type { BuilderDescription, BuilderDescriptionItem, BuilderLayout, BuilderLayoutOption, BuilderLayoutOptions, BuilderLayoutPage } from '../schemas/index';
4
+ export type { BuilderDescription, BuilderDescriptionItem } from '../schemas/index';
5
5
  export { instance } from './instance.js';
6
6
  export { models } from './models.js';
7
7
  export { order } from './order.js';