@fougere/schema 0.12.1-alpha.0 → 0.12.2-alpha.0

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 (246) hide show
  1. package/dist/FougereFieldAxes.d.ts.map +1 -0
  2. package/dist/FougereFieldAxes.js.map +1 -0
  3. package/dist/Schema.d.ts +4 -3
  4. package/dist/Schema.d.ts.map +1 -1
  5. package/dist/Schema.js +3 -0
  6. package/dist/Schema.js.map +1 -1
  7. package/dist/SchemaConstraints.d.ts +13 -10
  8. package/dist/SchemaConstraints.d.ts.map +1 -1
  9. package/dist/SchemaConstraints.js +32 -20
  10. package/dist/SchemaConstraints.js.map +1 -1
  11. package/dist/SchemaDefinition.d.ts.map +1 -1
  12. package/dist/SchemaDefinition.js +6 -5
  13. package/dist/SchemaDefinition.js.map +1 -1
  14. package/dist/SchemaError.d.ts +4 -1
  15. package/dist/SchemaError.d.ts.map +1 -1
  16. package/dist/SchemaError.js +5 -2
  17. package/dist/SchemaError.js.map +1 -1
  18. package/dist/SchemaView.d.ts +3 -2
  19. package/dist/SchemaView.d.ts.map +1 -1
  20. package/dist/axis/Axes.d.ts +1 -1
  21. package/dist/axis/Axes.js +3 -3
  22. package/dist/axis/Axis.d.ts +12 -2
  23. package/dist/axis/Axis.d.ts.map +1 -1
  24. package/dist/axis/boundary/Boundary.d.ts +9 -2
  25. package/dist/axis/boundary/Boundary.d.ts.map +1 -1
  26. package/dist/axis/boundary/Boundary.js +6 -2
  27. package/dist/axis/boundary/Boundary.js.map +1 -1
  28. package/dist/axis/boundary/Decoder.js.map +1 -1
  29. package/dist/axis/lifecycle/Lifecycle.d.ts +13 -4
  30. package/dist/axis/lifecycle/Lifecycle.d.ts.map +1 -1
  31. package/dist/axis/lifecycle/Lifecycle.js +8 -4
  32. package/dist/axis/lifecycle/Lifecycle.js.map +1 -1
  33. package/dist/axis/lifecycle/apply.js +1 -1
  34. package/dist/axis/lifecycle/apply.js.map +1 -1
  35. package/dist/axis/role/Role.d.ts +17 -10
  36. package/dist/axis/role/Role.d.ts.map +1 -1
  37. package/dist/axis/role/Role.js +30 -10
  38. package/dist/axis/role/Role.js.map +1 -1
  39. package/dist/axis/shape/Shape.d.ts +32 -9
  40. package/dist/axis/shape/Shape.d.ts.map +1 -1
  41. package/dist/axis/shape/Shape.js +43 -12
  42. package/dist/axis/shape/Shape.js.map +1 -1
  43. package/dist/axis/shape/ShapeFormat.d.ts +10 -0
  44. package/dist/axis/shape/ShapeFormat.d.ts.map +1 -0
  45. package/dist/axis/shape/ShapeFormat.js +32 -0
  46. package/dist/axis/shape/ShapeFormat.js.map +1 -0
  47. package/dist/entity/EntityDeclarations.d.ts +3 -2
  48. package/dist/entity/EntityDeclarations.d.ts.map +1 -1
  49. package/dist/entity/FieldGroups.d.ts +9 -0
  50. package/dist/entity/FieldGroups.d.ts.map +1 -0
  51. package/dist/entity/FieldGroups.js +2 -0
  52. package/dist/entity/FieldGroups.js.map +1 -0
  53. package/dist/field/Field.d.ts +35 -16
  54. package/dist/field/Field.d.ts.map +1 -1
  55. package/dist/field/Field.js +53 -8
  56. package/dist/field/Field.js.map +1 -1
  57. package/dist/field/FieldFormat.d.ts +1 -1
  58. package/dist/field/FieldFormat.js +4 -4
  59. package/dist/field/FieldFormat.js.map +1 -1
  60. package/dist/field/FieldSet.d.ts +12 -3
  61. package/dist/field/FieldSet.d.ts.map +1 -1
  62. package/dist/field/FieldSet.js +22 -15
  63. package/dist/field/FieldSet.js.map +1 -1
  64. package/dist/index.d.ts +1 -0
  65. package/dist/index.d.ts.map +1 -1
  66. package/dist/index.js.map +1 -1
  67. package/dist/lib/Format.d.ts +21 -2
  68. package/dist/lib/Format.d.ts.map +1 -1
  69. package/dist/lib/Format.js +31 -3
  70. package/dist/lib/Format.js.map +1 -1
  71. package/dist/lib/UnionToIntersection.d.ts +7 -0
  72. package/dist/lib/UnionToIntersection.d.ts.map +1 -0
  73. package/dist/lib/UnionToIntersection.js +2 -0
  74. package/dist/lib/UnionToIntersection.js.map +1 -0
  75. package/dist/lib/utils.d.ts +1 -1
  76. package/dist/lib/utils.d.ts.map +1 -1
  77. package/dist/lib/utils.js +1 -1
  78. package/dist/lib/utils.js.map +1 -1
  79. package/dist/projection/Cases.d.ts +1 -1
  80. package/dist/projection/Cases.d.ts.map +1 -1
  81. package/dist/projection/Cases.js +20 -8
  82. package/dist/projection/Cases.js.map +1 -1
  83. package/dist/projection/Visibility.d.ts.map +1 -1
  84. package/dist/projection/Visibility.js +6 -6
  85. package/dist/projection/Visibility.js.map +1 -1
  86. package/dist/projection/card/Bundle.d.ts.map +1 -1
  87. package/dist/projection/card/Bundle.js.map +1 -1
  88. package/dist/projection/card/Card.d.ts.map +1 -1
  89. package/dist/projection/card/Card.js +21 -30
  90. package/dist/projection/card/Card.js.map +1 -1
  91. package/dist/projection/card/CardForms.js +1 -1
  92. package/dist/projection/card/Diff.js.map +1 -1
  93. package/dist/projection/card/FieldExtension.d.ts +2 -2
  94. package/dist/projection/card/FieldExtension.d.ts.map +1 -1
  95. package/dist/projection/card/RoleDescriptor.d.ts +7 -2
  96. package/dist/projection/card/RoleDescriptor.d.ts.map +1 -1
  97. package/dist/projection/card/RoleDescriptor.js +2 -2
  98. package/dist/projection/card/RoleDescriptor.js.map +1 -1
  99. package/dist/projection/card/ShapeKeywords.d.ts +1 -1
  100. package/dist/projection/card/ShapeKeywords.d.ts.map +1 -1
  101. package/dist/validator/FieldDeclarationValidator.d.ts.map +1 -1
  102. package/dist/validator/FieldDeclarationValidator.js +7 -10
  103. package/dist/validator/FieldDeclarationValidator.js.map +1 -1
  104. package/dist/validator/FieldValueValidator.d.ts.map +1 -1
  105. package/dist/validator/FieldValueValidator.js +0 -2
  106. package/dist/validator/FieldValueValidator.js.map +1 -1
  107. package/dist/validator/InputValidator.d.ts +7 -1
  108. package/dist/validator/InputValidator.d.ts.map +1 -1
  109. package/dist/validator/InputValidator.js +15 -14
  110. package/dist/validator/InputValidator.js.map +1 -1
  111. package/dist/vocabulary/preset/created.d.ts +2 -2
  112. package/dist/vocabulary/preset/created.d.ts.map +1 -1
  113. package/dist/vocabulary/preset/created.js +2 -2
  114. package/dist/vocabulary/preset/created.js.map +1 -1
  115. package/dist/vocabulary/preset/updated.d.ts +2 -2
  116. package/dist/vocabulary/preset/updated.d.ts.map +1 -1
  117. package/dist/vocabulary/preset/updated.js +2 -2
  118. package/dist/vocabulary/preset/updated.js.map +1 -1
  119. package/dist/vocabulary/primitive/bool.d.ts +2 -5
  120. package/dist/vocabulary/primitive/bool.d.ts.map +1 -1
  121. package/dist/vocabulary/primitive/bool.js +1 -5
  122. package/dist/vocabulary/primitive/bool.js.map +1 -1
  123. package/dist/vocabulary/primitive/date.d.ts +2 -3
  124. package/dist/vocabulary/primitive/date.d.ts.map +1 -1
  125. package/dist/vocabulary/primitive/date.js +2 -3
  126. package/dist/vocabulary/primitive/date.js.map +1 -1
  127. package/dist/vocabulary/primitive/json.d.ts +3 -3
  128. package/dist/vocabulary/primitive/json.d.ts.map +1 -1
  129. package/dist/vocabulary/primitive/json.js +11 -11
  130. package/dist/vocabulary/primitive/json.js.map +1 -1
  131. package/dist/vocabulary/primitive/list.d.ts +6 -5
  132. package/dist/vocabulary/primitive/list.d.ts.map +1 -1
  133. package/dist/vocabulary/primitive/list.js +13 -7
  134. package/dist/vocabulary/primitive/list.js.map +1 -1
  135. package/dist/vocabulary/primitive/many.d.ts +2 -4
  136. package/dist/vocabulary/primitive/many.d.ts.map +1 -1
  137. package/dist/vocabulary/primitive/many.js +2 -4
  138. package/dist/vocabulary/primitive/many.js.map +1 -1
  139. package/dist/vocabulary/primitive/number.d.ts +2 -4
  140. package/dist/vocabulary/primitive/number.d.ts.map +1 -1
  141. package/dist/vocabulary/primitive/number.js +1 -3
  142. package/dist/vocabulary/primitive/number.js.map +1 -1
  143. package/dist/vocabulary/primitive/oneOf.d.ts +4 -7
  144. package/dist/vocabulary/primitive/oneOf.d.ts.map +1 -1
  145. package/dist/vocabulary/primitive/oneOf.js +19 -11
  146. package/dist/vocabulary/primitive/oneOf.js.map +1 -1
  147. package/dist/vocabulary/primitive/primary.d.ts +2 -2
  148. package/dist/vocabulary/primitive/primary.d.ts.map +1 -1
  149. package/dist/vocabulary/primitive/primary.js +2 -3
  150. package/dist/vocabulary/primitive/primary.js.map +1 -1
  151. package/dist/vocabulary/primitive/ref.d.ts +2 -6
  152. package/dist/vocabulary/primitive/ref.d.ts.map +1 -1
  153. package/dist/vocabulary/primitive/ref.js +1 -1
  154. package/dist/vocabulary/primitive/ref.js.map +1 -1
  155. package/dist/vocabulary/primitive/text.d.ts +2 -4
  156. package/dist/vocabulary/primitive/text.d.ts.map +1 -1
  157. package/dist/vocabulary/primitive/text.js +1 -3
  158. package/dist/vocabulary/primitive/text.js.map +1 -1
  159. package/dist/vocabulary/rule/nullable.d.ts +0 -1
  160. package/dist/vocabulary/rule/nullable.d.ts.map +1 -1
  161. package/dist/vocabulary/rule/nullable.js +0 -1
  162. package/dist/vocabulary/rule/nullable.js.map +1 -1
  163. package/dist/vocabulary/rule/optional.d.ts +0 -1
  164. package/dist/vocabulary/rule/optional.d.ts.map +1 -1
  165. package/dist/vocabulary/rule/optional.js +0 -1
  166. package/dist/vocabulary/rule/optional.js.map +1 -1
  167. package/dist/vocabulary/rule/readOnly.d.ts +0 -2
  168. package/dist/vocabulary/rule/readOnly.d.ts.map +1 -1
  169. package/dist/vocabulary/rule/readOnly.js +0 -2
  170. package/dist/vocabulary/rule/readOnly.js.map +1 -1
  171. package/dist/vocabulary/rule/writeOnly.d.ts +0 -2
  172. package/dist/vocabulary/rule/writeOnly.d.ts.map +1 -1
  173. package/dist/vocabulary/rule/writeOnly.js +0 -2
  174. package/dist/vocabulary/rule/writeOnly.js.map +1 -1
  175. package/dist/vocabulary/vocabulary.d.ts +2 -3
  176. package/dist/vocabulary/vocabulary.d.ts.map +1 -1
  177. package/dist/vocabulary/vocabulary.js +17 -21
  178. package/dist/vocabulary/vocabulary.js.map +1 -1
  179. package/package.json +1 -1
  180. package/src/Schema.ts +11 -8
  181. package/src/SchemaConstraints.ts +40 -22
  182. package/src/SchemaDefinition.ts +7 -5
  183. package/src/SchemaError.ts +8 -2
  184. package/src/SchemaView.ts +3 -2
  185. package/src/axis/Axes.ts +3 -3
  186. package/src/axis/Axis.ts +13 -2
  187. package/src/axis/boundary/Boundary.ts +16 -2
  188. package/src/axis/boundary/Decoder.ts +2 -0
  189. package/src/axis/lifecycle/Lifecycle.ts +15 -4
  190. package/src/axis/lifecycle/apply.ts +1 -1
  191. package/src/axis/role/Role.ts +41 -9
  192. package/src/axis/shape/Shape.ts +89 -23
  193. package/src/axis/shape/ShapeFormat.ts +37 -0
  194. package/src/entity/EntityDeclarations.ts +3 -2
  195. package/src/entity/FieldGroups.ts +9 -0
  196. package/src/field/Field.ts +84 -21
  197. package/src/field/FieldFormat.ts +5 -5
  198. package/src/field/FieldSet.ts +27 -19
  199. package/src/index.ts +1 -0
  200. package/src/lib/Format.ts +36 -3
  201. package/src/lib/UnionToIntersection.ts +10 -0
  202. package/src/lib/utils.ts +5 -1
  203. package/src/projection/Cases.ts +25 -8
  204. package/src/projection/Visibility.ts +9 -6
  205. package/src/projection/card/Bundle.ts +2 -0
  206. package/src/projection/card/Card.ts +26 -27
  207. package/src/projection/card/CardForms.ts +1 -1
  208. package/src/projection/card/Diff.ts +4 -0
  209. package/src/projection/card/FieldExtension.ts +2 -2
  210. package/src/projection/card/RoleDescriptor.ts +9 -4
  211. package/src/projection/card/ShapeKeywords.ts +1 -1
  212. package/src/validator/FieldDeclarationValidator.ts +7 -10
  213. package/src/validator/FieldValueValidator.ts +3 -1
  214. package/src/validator/InputValidator.ts +17 -12
  215. package/src/vocabulary/preset/created.ts +3 -3
  216. package/src/vocabulary/preset/updated.ts +4 -3
  217. package/src/vocabulary/primitive/bool.ts +3 -8
  218. package/src/vocabulary/primitive/date.ts +5 -4
  219. package/src/vocabulary/primitive/json.ts +27 -12
  220. package/src/vocabulary/primitive/list.ts +16 -9
  221. package/src/vocabulary/primitive/many.ts +3 -4
  222. package/src/vocabulary/primitive/number.ts +3 -8
  223. package/src/vocabulary/primitive/oneOf.ts +40 -24
  224. package/src/vocabulary/primitive/primary.ts +9 -5
  225. package/src/vocabulary/primitive/ref.ts +3 -7
  226. package/src/vocabulary/primitive/text.ts +3 -8
  227. package/src/vocabulary/rule/nullable.ts +0 -1
  228. package/src/vocabulary/rule/optional.ts +0 -1
  229. package/src/vocabulary/rule/readOnly.ts +0 -2
  230. package/src/vocabulary/rule/writeOnly.ts +0 -2
  231. package/src/vocabulary/vocabulary.ts +18 -22
  232. package/dist/entity/CompositeUnique.d.ts +0 -4
  233. package/dist/entity/CompositeUnique.d.ts.map +0 -1
  234. package/dist/entity/CompositeUnique.js +0 -2
  235. package/dist/entity/CompositeUnique.js.map +0 -1
  236. package/dist/field/FougereFieldAxes.d.ts.map +0 -1
  237. package/dist/field/FougereFieldAxes.js.map +0 -1
  238. package/dist/field/Meta.d.ts +0 -6
  239. package/dist/field/Meta.d.ts.map +0 -1
  240. package/dist/field/Meta.js +0 -3
  241. package/dist/field/Meta.js.map +0 -1
  242. package/src/entity/CompositeUnique.ts +0 -6
  243. package/src/field/Meta.ts +0 -5
  244. /package/dist/{field/FougereFieldAxes.d.ts → FougereFieldAxes.d.ts} +0 -0
  245. /package/dist/{field/FougereFieldAxes.js → FougereFieldAxes.js} +0 -0
  246. /package/src/{field/FougereFieldAxes.ts → FougereFieldAxes.ts} +0 -0
@@ -1,32 +1,48 @@
1
- import { Field } from '../../field/Field.js';
1
+ import { Field, type Shared } from '../../field/Field.js';
2
+ import type { Shape } from '../../axis/shape/Shape.js';
3
+ import { isArrayOf, isObject } from '../../lib/utils.js';
4
+ import { SchemaError } from '../../SchemaError.js';
2
5
 
3
- interface OneOfOptions<V extends string = string> {
4
- description?: string;
5
- default?: V;
6
- }
6
+ type Values = readonly [string, ...string[]] | readonly [number, ...number[]];
7
7
 
8
- export function oneOf<const T extends readonly string[]>(
9
- ...values: [...T]
10
- ): Field<T[number]>;
11
- export function oneOf<const T extends readonly string[]>(
12
- ...args: [...T, OneOfOptions<T[number]>]
8
+ export function oneOf<const T extends Values>(...values: [...T]): Field<T[number]>;
9
+
10
+ export function oneOf<const T extends Values>(
11
+ ...args: [...T, Shared<T[number]>]
13
12
  ): Field<T[number]>;
13
+
14
14
  /**
15
- * The set travels: GraphQL enum, form `select` and DDL `CHECK`, from this one declaration.
16
- * FR : l'ensemble voyage : enum GraphQL, `select` du formulaire, `CHECK` du DDL.
17
15
  * `oneOf('draft', 'published', { default: 'draft' })` → `{ type: 'string', enum: [...] }`
18
16
  */
19
- export function oneOf<const T extends readonly string[]>(
20
- ...args: [...T] | [...T, OneOfOptions<T[number]>]
17
+ export function oneOf<const T extends Values>(
18
+ ...args: [...T] | [...T, Shared<T[number]>]
21
19
  ): Field<T[number]> {
22
- const last = args[args.length - 1];
23
- const hasOpts = typeof last === 'object' && last !== null && !Array.isArray(last);
24
- const values = (hasOpts ? args.slice(0, -1) : args) as unknown as readonly string[];
25
- const opts = hasOpts ? (last as OneOfOptions) : {};
26
- return new Field<T[number]>({
27
- shape: { type: 'string', enum: values },
28
- lifecycle:
29
- opts.default !== undefined ? { create: { value: opts.default } } : undefined,
30
- meta: opts.description !== undefined ? { description: opts.description } : undefined,
31
- });
20
+ const given: readonly unknown[] = args;
21
+ const last = given.at(-1);
22
+
23
+ const opts = isObject(last) ? last : undefined;
24
+ const values = opts ? given.slice(0, -1) : given;
25
+
26
+ let shape: Shape | undefined = undefined;
27
+
28
+ if (values.length === 0)
29
+ throw new SchemaError(
30
+ 'oneOf() takes strings or numbers, then an optional object of options', { received: given },
31
+ );
32
+
33
+ if (isArrayOf(values, (value) => typeof value === 'string'))
34
+ shape = { type: 'string', enum: values };
35
+
36
+ if (isArrayOf(values, (value) => typeof value === 'number'))
37
+ shape = {
38
+ type: values.every(Number.isInteger) ? 'integer' : 'number',
39
+ enum: values,
40
+ };
41
+
42
+ if (shape === undefined)
43
+ throw new SchemaError(
44
+ 'oneOf() takes strings or numbers, then an optional object of options', { received: given },
45
+ );
46
+
47
+ return new Field<T[number]>({ shape }).setShared(opts);
32
48
  }
@@ -1,7 +1,7 @@
1
- import { Field } from '../../field/Field.js';
1
+ import { Field, type Described } from '../../field/Field.js';
2
2
  import { Generators, type GeneratorRef } from '../../axis/lifecycle/Generators.js';
3
3
 
4
- interface PrimaryOptions {
4
+ interface PrimaryOptions extends Described {
5
5
  generate?: GeneratorRef | [name: string, fn: () => string];
6
6
  }
7
7
 
@@ -9,30 +9,34 @@ export function primary(opts?: PrimaryOptions): Field<string>;
9
9
  export function primary<T>(field: Field<T>): Field<T>;
10
10
  /**
11
11
  * `primary()` for a generated id; `primary(number())` to make a declared field the key.
12
- * FR : `primary()` pour un identifiant généré ; `primary(number())` pour promouvoir un champ.
13
12
  * `primary()` → `create: { generate: 'cuid2' }`, `update: 'forbidden'`
14
13
  */
15
14
  export function primary(fieldOrOptions?: Field | PrimaryOptions): Field {
16
15
  if (Field.is(fieldOrOptions)) {
17
16
  const field = fieldOrOptions;
17
+
18
18
  return field.with({
19
19
  role: { ...field.role, primary: true },
20
20
  lifecycle: { ...field.lifecycle, update: 'forbidden' },
21
21
  });
22
22
  }
23
23
 
24
- const opts = (fieldOrOptions ?? {}) as PrimaryOptions;
24
+ const opts: PrimaryOptions = fieldOrOptions ?? {};
25
+
25
26
  let generate: GeneratorRef;
26
27
  if (Array.isArray(opts.generate)) {
27
28
  const [name, fn] = opts.generate;
29
+
28
30
  Generators.register(name, fn);
31
+
29
32
  generate = name;
30
33
  } else {
31
34
  generate = opts.generate ?? 'cuid2';
32
35
  }
36
+
33
37
  return new Field<string>({
34
38
  shape: { type: 'string' },
35
39
  role: { primary: true },
36
40
  lifecycle: { create: { generate }, update: 'forbidden' },
37
- });
41
+ }).setShared(opts);
38
42
  }
@@ -1,12 +1,8 @@
1
1
  import { type EntityConstructor } from '../../axis/role/EntityConstructor.js';
2
2
  import { Relation, type OnDelete } from '../../axis/role/Relation.js';
3
- import { Field } from '../../field/Field.js';
3
+ import { Field, type Shared } from '../../field/Field.js';
4
4
 
5
- export interface RefOptions {
6
- /**
7
- * What becomes of this row when the target's is deleted. `restrict` is the default because
8
- * it is what a foreign key already does when nothing is stated.
9
- */
5
+ export interface RefOptions extends Shared<string> {
10
6
  onDelete?: OnDelete;
11
7
  }
12
8
 
@@ -17,5 +13,5 @@ export function ref<E extends EntityConstructor>(
17
13
  return new Field<string>({
18
14
  shape: { type: 'string' },
19
15
  role: { relation: Relation.one(target, opts?.onDelete) },
20
- });
16
+ }).setShared(opts);
21
17
  }
@@ -1,13 +1,11 @@
1
- import { Field } from '../../field/Field.js';
1
+ import { Field, type Shared } from '../../field/Field.js';
2
2
  import { type StringFormat } from '../../axis/shape/StringFormat.js';
3
3
 
4
- export interface TextOptions {
4
+ export interface TextOptions extends Shared<string> {
5
5
  min?: number;
6
6
  max?: number;
7
7
  pattern?: string;
8
8
  format?: StringFormat;
9
- default?: string;
10
- description?: string;
11
9
  }
12
10
 
13
11
  export function text(opts?: TextOptions): Field<string> {
@@ -19,8 +17,5 @@ export function text(opts?: TextOptions): Field<string> {
19
17
  pattern: opts?.pattern,
20
18
  format: opts?.format,
21
19
  },
22
- lifecycle:
23
- opts?.default !== undefined ? { create: { value: opts.default } } : undefined,
24
- meta: opts?.description !== undefined ? { description: opts.description } : undefined,
25
- });
20
+ }).setShared(opts);
26
21
  }
@@ -4,7 +4,6 @@ import { type Field } from '../../field/Field.js';
4
4
 
5
5
  /**
6
6
  * Adds `null` and leaves the field REQUIRED — `optional()` is the one permitting absence.
7
- * FR : ajoute `null` en laissant le champ OBLIGATOIRE — `optional()` permet l'absence.
8
7
  * `nullable(text())` → `{ type: ['string', 'null'] }`, and `validate({})` still refuses
9
8
  */
10
9
  export const nullable: <T>(field: Field<T>) => Field<T | null> = vocabulary(
@@ -4,7 +4,6 @@ import { type Field } from '../../field/Field.js';
4
4
 
5
5
  /**
6
6
  * Adds `null` AND permits absence. A field that already states a `create` rule keeps it.
7
- * FR : ajoute `null` ET permet l'absence. Un champ qui énonce déjà un `create` le garde.
8
7
  * `optional(text())` → `{ type: ['string', 'null'] }` and `create: 'optional'`
9
8
  */
10
9
  export const optional: <T>(field: Field<T>) => Field<T | null> = vocabulary(
@@ -3,8 +3,6 @@ import { Boundary } from '../../axis/boundary/Boundary.js';
3
3
  import { Field } from '../../field/Field.js';
4
4
 
5
5
  /**
6
- * Closes the way in, so the field leaves `Visibility.input` and every form derived from it.
7
- * FR : ferme l'entrée : le champ quitte `Visibility.input` et tout formulaire qui en dérive.
8
6
  * `readOnly(text())` → `boundary.in` is `'closed'`
9
7
  */
10
8
  export const readOnly: <T>(field: Field<T>) => Field<T> = vocabulary(
@@ -3,8 +3,6 @@ import { Boundary } from '../../axis/boundary/Boundary.js';
3
3
  import { Field } from '../../field/Field.js';
4
4
 
5
5
  /**
6
- * Closes the way out, the dual of `readOnly`: the value is written and never sent back.
7
- * FR : ferme la sortie, dual de `readOnly` : la valeur s'écrit et ne repart jamais.
8
6
  * `writeOnly(text())` → `boundary.out` is `'closed'`
9
7
  */
10
8
  export const writeOnly: <T>(field: Field<T>) => Field<T> = vocabulary(
@@ -1,52 +1,48 @@
1
- import { Field } from '../field/Field.js';
1
+ import { Field, type FieldDeclaration } from '../field/Field.js';
2
2
  import { Axes } from '../axis/Axes.js';
3
3
  import { dequal } from 'dequal';
4
4
  import { SchemaError } from '../SchemaError.js';
5
5
 
6
- const memberSlots = (): string[] => [...Axes.names, 'meta'];
7
-
8
6
  /**
9
- * Builds a `rule/` word, which states members on the field it receives.
10
- * FR : fabrique un mot de `rule/`, qui énonce des membres sur le champ reçu.
7
+ * Builds a `rule/` word
11
8
  * `vocabulary('indexed', () => ({ role: { index: true } }))`
12
9
  */
13
10
  export function vocabulary(
14
- name: string,
11
+ word: string,
15
12
  states: (field: Field) => Partial<Field>,
16
13
  ): FieldWord {
17
- return (field) => field.with(merge(name, field, states(field)));
14
+ return (field) => field.with(merge(word, field, states(field)));
18
15
  }
19
16
 
20
17
  export type FieldWord = (field: Field<any>) => Field<any>;
21
18
 
22
19
  /**
23
- * Refuses two words stating one member differently, rather than letting the outer win.
24
- * FR : refuse deux mots qui énoncent un même membre différemment.
25
- * `readOnly(writeOnly(text()))` → both apply; `immutable(created())` → throws
20
+ * Refuses two words stating one member DIFFERENTLY, rather than letting the outer win.
21
+ * `readOnly(writeOnly(text()))` → both apply, they write two members; `immutable(created())`
22
+ * too, since both say `update: 'forbidden'`; `immutable(updated())` → throws.
26
23
  */
27
- function merge(name: string, field: Field, given: Partial<Field>): Partial<Field> {
24
+ function merge(word: string, field: Field, changes: Partial<FieldDeclaration>): Partial<Field> {
28
25
  const merged: Record<string, unknown> = {};
29
- const stated = given as Record<string, unknown>;
30
- const held = field as unknown as Record<string, unknown>;
31
- if ('shape' in given) merged.shape = given.shape;
26
+ if ('shape' in changes) merged.shape = changes.shape;
32
27
 
33
- for (const slot of memberSlots()) {
34
- const members = stated[slot];
28
+ for (const name of Axes.names as (keyof FieldDeclaration)[]) {
29
+ const members = changes[name];
35
30
  if (members === undefined) continue;
36
- const already = held[slot] as Record<string, unknown> | undefined;
37
- if (typeof members !== 'object' || members === null || typeof already !== 'object') {
38
- merged[slot] = members;
31
+ const already = field.axis(name);
32
+ if (typeof members !== 'object' || members === null || typeof already !== 'object' || already === null) {
33
+ merged[name] = members;
39
34
  continue;
40
35
  }
41
36
  for (const [member, value] of Object.entries(members)) {
42
- const previous = already?.[member];
37
+ const previous = (already as Record<string, unknown>)[member];
43
38
  if (previous === undefined || dequal(previous, value)) continue;
44
39
  throw new SchemaError(
45
- `vocabulary: \`${name}\` states ${slot}.${member} = ${JSON.stringify(value)}, but the ` +
40
+ `vocabulary: \`${word}\` states ${name}.${member} = ${JSON.stringify(value)}, but the ` +
46
41
  `field already states ${JSON.stringify(previous)}. Apply one or the other, not both.`,
47
42
  );
48
43
  }
49
- merged[slot] = { ...already, ...members };
44
+ merged[name] = { ...already, ...members };
50
45
  }
46
+
51
47
  return merged as Partial<Field>;
52
48
  }
@@ -1,4 +0,0 @@
1
- import type { FieldName } from '../field/FieldName.js';
2
- import type { Fields } from '../field/Fields.js';
3
- export type CompositeUnique<TFields extends Fields> = readonly (readonly FieldName<TFields>[])[];
4
- //# sourceMappingURL=CompositeUnique.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"CompositeUnique.d.ts","sourceRoot":"","sources":["../../src/entity/CompositeUnique.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAGjD,MAAM,MAAM,eAAe,CAAC,OAAO,SAAS,MAAM,IAChD,SAAS,CAAC,SAAS,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=CompositeUnique.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"CompositeUnique.js","sourceRoot":"","sources":["../../src/entity/CompositeUnique.ts"],"names":[],"mappings":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"FougereFieldAxes.d.ts","sourceRoot":"","sources":["../../src/field/FougereFieldAxes.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,gBAAgB;CAAG"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"FougereFieldAxes.js","sourceRoot":"","sources":["../../src/field/FougereFieldAxes.ts"],"names":[],"mappings":""}
@@ -1,6 +0,0 @@
1
- import { Format, type Accepted } from '../lib/Format.js';
2
- export declare const META_FORMAT: Format<{
3
- description?: string | undefined;
4
- }>;
5
- export type Meta = Accepted<typeof META_FORMAT>;
6
- //# sourceMappingURL=Meta.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Meta.d.ts","sourceRoot":"","sources":["../../src/field/Meta.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEzD,eAAO,MAAM,WAAW;;EAAmE,CAAC;AAE5F,MAAM,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,WAAW,CAAC,CAAC"}
@@ -1,3 +0,0 @@
1
- import { Format } from '../lib/Format.js';
2
- export const META_FORMAT = Format.of('field/meta').key('description', Format.text).closed();
3
- //# sourceMappingURL=Meta.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Meta.js","sourceRoot":"","sources":["../../src/field/Meta.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAiB,MAAM,kBAAkB,CAAC;AAEzD,MAAM,CAAC,MAAM,WAAW,GAAG,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC"}
@@ -1,6 +0,0 @@
1
- import type { FieldName } from '../field/FieldName.js';
2
- import type { Fields } from '../field/Fields.js';
3
-
4
- // Ex: [['title', 'name'], ['id']]
5
- export type CompositeUnique<TFields extends Fields> =
6
- readonly (readonly FieldName<TFields>[])[];
package/src/field/Meta.ts DELETED
@@ -1,5 +0,0 @@
1
- import { Format, type Accepted } from '../lib/Format.js';
2
-
3
- export const META_FORMAT = Format.of('field/meta').key('description', Format.text).closed();
4
-
5
- export type Meta = Accepted<typeof META_FORMAT>;