@fougere/schema 0.11.0-alpha.0 → 0.12.1-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 (287) hide show
  1. package/dist/Schema.d.ts +1 -1
  2. package/dist/Schema.d.ts.map +1 -1
  3. package/dist/Schema.js +4 -3
  4. package/dist/Schema.js.map +1 -1
  5. package/dist/SchemaConstructor.d.ts +3 -4
  6. package/dist/SchemaConstructor.d.ts.map +1 -1
  7. package/dist/SchemaDefinition.d.ts.map +1 -1
  8. package/dist/SchemaDefinition.js +2 -1
  9. package/dist/SchemaDefinition.js.map +1 -1
  10. package/dist/SchemaError.d.ts +4 -0
  11. package/dist/SchemaError.d.ts.map +1 -0
  12. package/dist/SchemaError.js +7 -0
  13. package/dist/SchemaError.js.map +1 -0
  14. package/dist/SchemaView.d.ts +1 -1
  15. package/dist/SchemaView.d.ts.map +1 -1
  16. package/dist/axis/Axes.d.ts +16 -0
  17. package/dist/axis/Axes.d.ts.map +1 -0
  18. package/dist/axis/Axes.js +27 -0
  19. package/dist/axis/Axes.js.map +1 -0
  20. package/dist/axis/Axis.d.ts +5 -9
  21. package/dist/axis/Axis.d.ts.map +1 -1
  22. package/dist/axis/Axis.js +1 -10
  23. package/dist/axis/Axis.js.map +1 -1
  24. package/dist/axis/boundary/Boundary.d.ts +29 -3
  25. package/dist/axis/boundary/Boundary.d.ts.map +1 -1
  26. package/dist/axis/boundary/Boundary.js +15 -11
  27. package/dist/axis/boundary/Boundary.js.map +1 -1
  28. package/dist/axis/boundary/Decoder.d.ts +10 -7
  29. package/dist/axis/boundary/Decoder.d.ts.map +1 -1
  30. package/dist/axis/boundary/Decoder.js +2 -2
  31. package/dist/axis/boundary/Decoder.js.map +1 -1
  32. package/dist/axis/lifecycle/Generators.d.ts +5 -5
  33. package/dist/axis/lifecycle/Generators.d.ts.map +1 -1
  34. package/dist/axis/lifecycle/Generators.js +5 -15
  35. package/dist/axis/lifecycle/Generators.js.map +1 -1
  36. package/dist/axis/lifecycle/Lifecycle.d.ts +18 -6
  37. package/dist/axis/lifecycle/Lifecycle.d.ts.map +1 -1
  38. package/dist/axis/lifecycle/Lifecycle.js +29 -14
  39. package/dist/axis/lifecycle/Lifecycle.js.map +1 -1
  40. package/dist/axis/lifecycle/apply.d.ts.map +1 -1
  41. package/dist/axis/lifecycle/apply.js +5 -22
  42. package/dist/axis/lifecycle/apply.js.map +1 -1
  43. package/dist/axis/role/Role.d.ts +18 -6
  44. package/dist/axis/role/Role.d.ts.map +1 -1
  45. package/dist/axis/role/Role.js +30 -16
  46. package/dist/axis/role/Role.js.map +1 -1
  47. package/dist/axis/shape/Shape.d.ts +2 -2
  48. package/dist/axis/shape/Shape.d.ts.map +1 -1
  49. package/dist/axis/shape/Shape.js +2 -2
  50. package/dist/axis/shape/Shape.js.map +1 -1
  51. package/dist/axis/shape/{Formats.d.ts → StringFormats.d.ts} +3 -3
  52. package/dist/axis/shape/StringFormats.d.ts.map +1 -0
  53. package/dist/axis/shape/{Formats.js → StringFormats.js} +3 -3
  54. package/dist/axis/shape/StringFormats.js.map +1 -0
  55. package/dist/entity/EntityAdapterSet.d.ts.map +1 -1
  56. package/dist/entity/EntityAdapterSet.js +3 -2
  57. package/dist/entity/EntityAdapterSet.js.map +1 -1
  58. package/dist/entity.d.ts +0 -1
  59. package/dist/entity.d.ts.map +1 -1
  60. package/dist/entity.js +0 -1
  61. package/dist/entity.js.map +1 -1
  62. package/dist/field/Field.d.ts +11 -5
  63. package/dist/field/Field.d.ts.map +1 -1
  64. package/dist/field/Field.js +10 -7
  65. package/dist/field/Field.js.map +1 -1
  66. package/dist/field/FieldFormat.d.ts +9 -0
  67. package/dist/field/FieldFormat.d.ts.map +1 -0
  68. package/dist/field/FieldFormat.js +12 -0
  69. package/dist/field/FieldFormat.js.map +1 -0
  70. package/dist/field/FieldSet.d.ts.map +1 -1
  71. package/dist/field/FieldSet.js +5 -3
  72. package/dist/field/FieldSet.js.map +1 -1
  73. package/dist/field/FougereFieldAxes.d.ts +3 -0
  74. package/dist/field/FougereFieldAxes.d.ts.map +1 -0
  75. package/dist/field/FougereFieldAxes.js +2 -0
  76. package/dist/field/FougereFieldAxes.js.map +1 -0
  77. package/dist/field/Meta.d.ts +5 -3
  78. package/dist/field/Meta.d.ts.map +1 -1
  79. package/dist/field/Meta.js +2 -1
  80. package/dist/field/Meta.js.map +1 -1
  81. package/dist/field/Values.d.ts +6 -0
  82. package/dist/field/Values.d.ts.map +1 -0
  83. package/dist/field/Values.js.map +1 -0
  84. package/dist/index.d.ts +8 -3
  85. package/dist/index.d.ts.map +1 -1
  86. package/dist/index.js +5 -3
  87. package/dist/index.js.map +1 -1
  88. package/dist/lib/Format.d.ts +56 -0
  89. package/dist/lib/Format.d.ts.map +1 -0
  90. package/dist/lib/Format.js +95 -0
  91. package/dist/lib/Format.js.map +1 -0
  92. package/dist/lib/JsonSchema.d.ts +2 -0
  93. package/dist/lib/JsonSchema.d.ts.map +1 -0
  94. package/dist/lib/JsonSchema.js +2 -0
  95. package/dist/lib/JsonSchema.js.map +1 -0
  96. package/dist/lib/Registry.d.ts +5 -4
  97. package/dist/lib/Registry.d.ts.map +1 -1
  98. package/dist/lib/Registry.js +14 -8
  99. package/dist/lib/Registry.js.map +1 -1
  100. package/dist/lib/ValidationResult.d.ts +2 -0
  101. package/dist/lib/ValidationResult.d.ts.map +1 -1
  102. package/dist/lib/ValidationResult.js +6 -0
  103. package/dist/lib/ValidationResult.js.map +1 -1
  104. package/dist/lib/Verdict.d.ts +12 -0
  105. package/dist/lib/Verdict.d.ts.map +1 -0
  106. package/dist/lib/Verdict.js +2 -0
  107. package/dist/lib/Verdict.js.map +1 -0
  108. package/dist/projection/Cases.js +52 -54
  109. package/dist/projection/Cases.js.map +1 -1
  110. package/dist/projection/Visibility.d.ts +11 -0
  111. package/dist/projection/Visibility.d.ts.map +1 -1
  112. package/dist/projection/Visibility.js +22 -0
  113. package/dist/projection/Visibility.js.map +1 -1
  114. package/dist/projection/card/Bundle.d.ts.map +1 -1
  115. package/dist/projection/card/Bundle.js +2 -1
  116. package/dist/projection/card/Bundle.js.map +1 -1
  117. package/dist/projection/card/Card.d.ts +1 -1
  118. package/dist/projection/card/Card.d.ts.map +1 -1
  119. package/dist/projection/card/Card.js +19 -11
  120. package/dist/projection/card/Card.js.map +1 -1
  121. package/dist/projection/card/CardForm.d.ts +7 -0
  122. package/dist/projection/card/CardForm.d.ts.map +1 -0
  123. package/dist/projection/card/CardForm.js +2 -0
  124. package/dist/projection/card/CardForm.js.map +1 -0
  125. package/dist/projection/card/CardForms.d.ts +10 -0
  126. package/dist/projection/card/CardForms.d.ts.map +1 -0
  127. package/dist/projection/card/CardForms.js +12 -0
  128. package/dist/projection/card/CardForms.js.map +1 -0
  129. package/dist/projection/card/Change.d.ts +2 -2
  130. package/dist/projection/card/Change.d.ts.map +1 -1
  131. package/dist/projection/card/Diff.d.ts.map +1 -1
  132. package/dist/projection/card/Diff.js +36 -39
  133. package/dist/projection/card/Diff.js.map +1 -1
  134. package/dist/projection/card/FieldExtension.d.ts +4 -2
  135. package/dist/projection/card/FieldExtension.d.ts.map +1 -1
  136. package/dist/projection/card/RoleDescriptor.d.ts +9 -2
  137. package/dist/projection/card/RoleDescriptor.d.ts.map +1 -1
  138. package/dist/projection/card/RoleDescriptor.js +40 -1
  139. package/dist/projection/card/RoleDescriptor.js.map +1 -1
  140. package/dist/projection/card/admission.d.ts +0 -14
  141. package/dist/projection/card/admission.d.ts.map +1 -1
  142. package/dist/projection/card/admission.js +2 -21
  143. package/dist/projection/card/admission.js.map +1 -1
  144. package/dist/validator/FieldDeclarationValidator.d.ts.map +1 -1
  145. package/dist/validator/FieldDeclarationValidator.js +5 -17
  146. package/dist/validator/FieldDeclarationValidator.js.map +1 -1
  147. package/dist/validator/FieldValueValidator.d.ts +3 -3
  148. package/dist/validator/FieldValueValidator.d.ts.map +1 -1
  149. package/dist/validator/FieldValueValidator.js +18 -35
  150. package/dist/validator/FieldValueValidator.js.map +1 -1
  151. package/dist/validator/InputValidator.d.ts +3 -0
  152. package/dist/validator/InputValidator.d.ts.map +1 -1
  153. package/dist/validator/InputValidator.js +28 -31
  154. package/dist/validator/InputValidator.js.map +1 -1
  155. package/dist/validator/JsonSchemaValidator.d.ts +23 -0
  156. package/dist/validator/JsonSchemaValidator.d.ts.map +1 -0
  157. package/dist/validator/JsonSchemaValidator.js +113 -0
  158. package/dist/validator/JsonSchemaValidator.js.map +1 -0
  159. package/dist/vocabulary/primitive/list.d.ts.map +1 -1
  160. package/dist/vocabulary/primitive/list.js +2 -1
  161. package/dist/vocabulary/primitive/list.js.map +1 -1
  162. package/dist/vocabulary/vocabulary.d.ts.map +1 -1
  163. package/dist/vocabulary/vocabulary.js +9 -6
  164. package/dist/vocabulary/vocabulary.js.map +1 -1
  165. package/package.json +1 -1
  166. package/src/Schema.ts +6 -4
  167. package/src/SchemaConstructor.ts +4 -4
  168. package/src/SchemaDefinition.ts +2 -1
  169. package/src/SchemaError.ts +7 -0
  170. package/src/SchemaView.ts +1 -1
  171. package/src/axis/Axes.ts +34 -0
  172. package/src/axis/Axis.ts +5 -20
  173. package/src/axis/boundary/Boundary.ts +26 -13
  174. package/src/axis/boundary/Decoder.ts +5 -4
  175. package/src/axis/lifecycle/Generators.ts +6 -18
  176. package/src/axis/lifecycle/Lifecycle.ts +41 -19
  177. package/src/axis/lifecycle/apply.ts +13 -21
  178. package/src/axis/role/Role.ts +35 -19
  179. package/src/axis/shape/Shape.ts +3 -3
  180. package/src/axis/shape/{Formats.ts → StringFormats.ts} +2 -2
  181. package/src/entity/EntityAdapterSet.ts +3 -2
  182. package/src/entity.ts +0 -1
  183. package/src/field/Field.ts +23 -12
  184. package/src/field/FieldFormat.ts +18 -0
  185. package/src/field/FieldSet.ts +5 -3
  186. package/src/field/FougereFieldAxes.ts +2 -0
  187. package/src/field/Meta.ts +5 -3
  188. package/src/{Values.ts → field/Values.ts} +2 -2
  189. package/src/index.ts +8 -3
  190. package/src/lib/Format.ts +139 -0
  191. package/src/lib/JsonSchema.ts +1 -0
  192. package/src/lib/Registry.ts +18 -9
  193. package/src/lib/ValidationResult.ts +8 -0
  194. package/src/lib/Verdict.ts +10 -0
  195. package/src/projection/Cases.ts +61 -57
  196. package/src/projection/Visibility.ts +22 -0
  197. package/src/projection/card/Bundle.ts +2 -1
  198. package/src/projection/card/Card.ts +24 -13
  199. package/src/projection/card/CardForm.ts +8 -0
  200. package/src/projection/card/CardForms.ts +13 -0
  201. package/src/projection/card/Change.ts +2 -2
  202. package/src/projection/card/Diff.ts +44 -44
  203. package/src/projection/card/FieldExtension.ts +5 -2
  204. package/src/projection/card/RoleDescriptor.ts +48 -2
  205. package/src/projection/card/admission.ts +2 -34
  206. package/src/validator/FieldDeclarationValidator.ts +5 -17
  207. package/src/validator/FieldValueValidator.ts +22 -46
  208. package/src/validator/InputValidator.ts +30 -32
  209. package/src/validator/JsonSchemaValidator.ts +142 -0
  210. package/src/vocabulary/primitive/list.ts +2 -1
  211. package/src/vocabulary/vocabulary.ts +9 -6
  212. package/dist/PartialValues.d.ts +0 -4
  213. package/dist/PartialValues.d.ts.map +0 -1
  214. package/dist/PartialValues.js +0 -2
  215. package/dist/PartialValues.js.map +0 -1
  216. package/dist/Values.d.ts +0 -6
  217. package/dist/Values.d.ts.map +0 -1
  218. package/dist/Values.js.map +0 -1
  219. package/dist/axis/boundary/Boundaries.d.ts +0 -17
  220. package/dist/axis/boundary/Boundaries.d.ts.map +0 -1
  221. package/dist/axis/boundary/Boundaries.js +0 -25
  222. package/dist/axis/boundary/Boundaries.js.map +0 -1
  223. package/dist/axis/boundary/BoundaryAxis.d.ts +0 -4
  224. package/dist/axis/boundary/BoundaryAxis.d.ts.map +0 -1
  225. package/dist/axis/boundary/BoundaryAxis.js +0 -30
  226. package/dist/axis/boundary/BoundaryAxis.js.map +0 -1
  227. package/dist/axis/boundary/BoundaryRef.d.ts +0 -3
  228. package/dist/axis/boundary/BoundaryRef.d.ts.map +0 -1
  229. package/dist/axis/boundary/BoundaryRef.js +0 -2
  230. package/dist/axis/boundary/BoundaryRef.js.map +0 -1
  231. package/dist/axis/boundary/BoundaryRules.d.ts +0 -9
  232. package/dist/axis/boundary/BoundaryRules.d.ts.map +0 -1
  233. package/dist/axis/boundary/BoundaryRules.js +0 -2
  234. package/dist/axis/boundary/BoundaryRules.js.map +0 -1
  235. package/dist/axis/lifecycle/Clock.d.ts +0 -18
  236. package/dist/axis/lifecycle/Clock.d.ts.map +0 -1
  237. package/dist/axis/lifecycle/Clock.js +0 -25
  238. package/dist/axis/lifecycle/Clock.js.map +0 -1
  239. package/dist/axis/lifecycle/LifecycleAxis.d.ts +0 -4
  240. package/dist/axis/lifecycle/LifecycleAxis.d.ts.map +0 -1
  241. package/dist/axis/lifecycle/LifecycleAxis.js +0 -52
  242. package/dist/axis/lifecycle/LifecycleAxis.js.map +0 -1
  243. package/dist/axis/lifecycle/LifecycleRules.d.ts +0 -12
  244. package/dist/axis/lifecycle/LifecycleRules.d.ts.map +0 -1
  245. package/dist/axis/lifecycle/LifecycleRules.js +0 -3
  246. package/dist/axis/lifecycle/LifecycleRules.js.map +0 -1
  247. package/dist/axis/role/RoleAxis.d.ts +0 -5
  248. package/dist/axis/role/RoleAxis.d.ts.map +0 -1
  249. package/dist/axis/role/RoleAxis.js +0 -93
  250. package/dist/axis/role/RoleAxis.js.map +0 -1
  251. package/dist/axis/role/RoleRules.d.ts +0 -8
  252. package/dist/axis/role/RoleRules.d.ts.map +0 -1
  253. package/dist/axis/role/RoleRules.js +0 -2
  254. package/dist/axis/role/RoleRules.js.map +0 -1
  255. package/dist/axis/shape/Formats.d.ts.map +0 -1
  256. package/dist/axis/shape/Formats.js.map +0 -1
  257. package/dist/lib/Checked.d.ts +0 -11
  258. package/dist/lib/Checked.d.ts.map +0 -1
  259. package/dist/lib/Checked.js +0 -2
  260. package/dist/lib/Checked.js.map +0 -1
  261. package/dist/projection/card/RelationDescriptor.d.ts +0 -5
  262. package/dist/projection/card/RelationDescriptor.d.ts.map +0 -1
  263. package/dist/projection/card/RelationDescriptor.js +0 -2
  264. package/dist/projection/card/RelationDescriptor.js.map +0 -1
  265. package/dist/projection/standard.d.ts +0 -14
  266. package/dist/projection/standard.d.ts.map +0 -1
  267. package/dist/projection/standard.js +0 -2
  268. package/dist/projection/standard.js.map +0 -1
  269. package/dist/validator/AdapterFieldValidator.d.ts +0 -14
  270. package/dist/validator/AdapterFieldValidator.d.ts.map +0 -1
  271. package/dist/validator/AdapterFieldValidator.js +0 -36
  272. package/dist/validator/AdapterFieldValidator.js.map +0 -1
  273. package/src/PartialValues.ts +0 -4
  274. package/src/axis/boundary/Boundaries.ts +0 -36
  275. package/src/axis/boundary/BoundaryAxis.ts +0 -32
  276. package/src/axis/boundary/BoundaryRef.ts +0 -3
  277. package/src/axis/boundary/BoundaryRules.ts +0 -4
  278. package/src/axis/lifecycle/Clock.ts +0 -26
  279. package/src/axis/lifecycle/LifecycleAxis.ts +0 -55
  280. package/src/axis/lifecycle/LifecycleRules.ts +0 -9
  281. package/src/axis/role/RoleAxis.ts +0 -104
  282. package/src/axis/role/RoleRules.ts +0 -8
  283. package/src/lib/Checked.ts +0 -5
  284. package/src/projection/card/RelationDescriptor.ts +0 -3
  285. package/src/projection/standard.ts +0 -13
  286. package/src/validator/AdapterFieldValidator.ts +0 -40
  287. /package/dist/{Values.js → field/Values.js} +0 -0
@@ -1,15 +1,16 @@
1
- import { Validator, format as engineFormats } from '@cfworker/json-schema';
1
+ import { format as engineFormats } from '@cfworker/json-schema';
2
2
  import { Boundary } from '../axis/boundary/Boundary.js';
3
3
  import { type FormatPredicate } from '../axis/shape/FormatPredicate.js';
4
- import { Formats } from '../axis/shape/Formats.js';
4
+ import { StringFormats } from '../axis/shape/StringFormats.js';
5
5
  import { type Shape } from '../axis/shape/Shape.js';
6
6
  import { Shapes } from '../axis/shape/Shape.js';
7
7
  import type { Field } from '../field/Field.js';
8
- import type { Checked } from '../lib/Checked.js';
9
- import type { OutputUnit } from '@cfworker/json-schema';
8
+ import type { Verdict } from '../lib/Verdict.js';
9
+ import { SchemaError } from '../SchemaError.js';
10
+ import type { JsonSchema } from '../lib/JsonSchema.js';
11
+ import { JsonSchemaValidator } from './JsonSchemaValidator.js';
10
12
 
11
13
  interface ShapePlan {
12
- validator: Validator;
13
14
  custom?: FormatPredicate;
14
15
  formatName?: string;
15
16
  }
@@ -24,24 +25,26 @@ export class FieldValueValidator {
24
25
  return new FieldValueValidator(field);
25
26
  }
26
27
 
27
- validate(value: unknown): Checked {
28
+ validate(value: unknown): Verdict {
28
29
  const shape = this.field.shape;
29
30
  const type = Shapes.typeOf(shape);
30
31
  const base = Shapes.of(shape).base;
31
32
  if (value !== null) {
32
33
  if (base?.type === 'object' && !base.properties) return { value };
33
34
  if (type === 'date' && value instanceof Date) {
34
- return Number.isNaN(value.getTime()) ? { error: 'Invalid date' } : { value };
35
+ return Number.isNaN(value.getTime()) ? { message: 'Invalid date' } : { value };
35
36
  }
36
37
  if ((type === 'number' || type === 'integer') && typeof value === 'number' && Number.isNaN(value)) {
37
- return { error: 'Expected a number' };
38
+ return { message: 'Expected a number' };
38
39
  }
39
40
  }
40
41
  const plan = FieldValueValidator.planFor(shape);
41
- const result = plan.validator.validate(value);
42
- if (!result.valid) return refusalOf(result.errors);
42
+ const refusal = JsonSchemaValidator.of(shape as JsonSchema).refusalOf(value, []);
43
+ if (refusal) {
44
+ return refusal.path.length > 0 ? { message: refusal.message, path: refusal.path } : { message: refusal.message };
45
+ }
43
46
  if (plan.custom && typeof value === 'string' && !plan.custom(value)) {
44
- return { error: `String does not match format "${plan.formatName}".` };
47
+ return { message: `String does not match format "${plan.formatName}".` };
45
48
  }
46
49
  return { value };
47
50
  }
@@ -50,12 +53,12 @@ export class FieldValueValidator {
50
53
  * The value admitted, then handed back in the form the domain writes — an ISO string
51
54
  * arrives as a `Date`. `null` passes untouched, and a refusal stops before the codec.
52
55
  */
53
- parse(value: unknown): Checked {
54
- const checked = this.validate(value);
55
- if ('error' in checked) return checked;
56
- if (checked.value === null) return { value: null };
56
+ parse(value: unknown): Verdict {
57
+ const verdict = this.validate(value);
58
+ if ('message' in verdict) return verdict;
59
+ if (verdict.value === null) return { value: null };
57
60
 
58
- return Boundary.of(this.field).decode(checked.value);
61
+ return Boundary.of(this.field).decode(verdict.value);
59
62
  }
60
63
 
61
64
  private static planFor(shape: Shape): ShapePlan {
@@ -64,7 +67,6 @@ export class FieldValueValidator {
64
67
  const base = Shapes.of(shape).base;
65
68
  const formatName = base?.type === 'string' ? base.format : undefined;
66
69
  plan = {
67
- validator: new Validator(shape as object, '2020-12', true),
68
70
  custom: formatName === undefined ? undefined : this.customFormatOf(formatName),
69
71
  formatName,
70
72
  };
@@ -74,39 +76,13 @@ export class FieldValueValidator {
74
76
  }
75
77
 
76
78
  private static customFormatOf(name: string): FormatPredicate | undefined {
77
- const custom = Formats.find(name);
79
+ const custom = StringFormats.find(name);
78
80
  if (!custom && !(name in engineFormats)) {
79
- throw new Error(
80
- `Unknown format: '${name}'. Register it with Formats.register('${name}', …) — ` +
81
+ throw new SchemaError(
82
+ `Unknown format: '${name}'. Register it with StringFormats.register('${name}', …) — ` +
81
83
  `the engine validates ${Object.keys(engineFormats).length} formats natively and this is not one of them.`,
82
84
  );
83
85
  }
84
86
  return custom;
85
87
  }
86
88
  }
87
-
88
- /**
89
- * The engine states its refusals outermost first, so `errors[0]` on a nested shape is the
90
- * parent's `Property "street" does not match schema.` — true, and never the reason. The
91
- * DEEPEST one is the reason, and it is the one that says where.
92
- */
93
- function refusalOf(errors: readonly OutputUnit[]): Checked {
94
- const deepest = errors.reduce<OutputUnit | undefined>(
95
- (held, one) => (held && depthOf(held) >= depthOf(one) ? held : one),
96
- undefined,
97
- );
98
- if (!deepest) return { error: 'Invalid value' };
99
- const path = locationOf(deepest.instanceLocation);
100
-
101
- return path.length > 0 ? { error: deepest.error, path } : { error: deepest.error };
102
- }
103
-
104
- const depthOf = (unit: OutputUnit): number => locationOf(unit.instanceLocation).length;
105
-
106
- /** `#/city/zip` — a JSON Pointer fragment, and `~1`/`~0` are how it spells `/` and `~`. */
107
- const locationOf = (instanceLocation: string): string[] =>
108
- instanceLocation
109
- .replace(/^#/, '')
110
- .split('/')
111
- .filter(Boolean)
112
- .map((segment) => segment.replace(/~1/g, '/').replace(/~0/g, '~'));
@@ -3,6 +3,7 @@ import { Lifecycle } from '../axis/lifecycle/Lifecycle.js';
3
3
  import { Role } from '../axis/role/Role.js';
4
4
  import type { Field } from '../field/Field.js';
5
5
  import type { Fields } from '../field/Fields.js';
6
+ import type { Verdict } from '../lib/Verdict.js';
6
7
  import type { ValidationError } from '../lib/ValidationError.js';
7
8
  import type { ValidationResult } from '../lib/ValidationResult.js';
8
9
  import { FieldValueValidator } from './FieldValueValidator.js';
@@ -36,45 +37,42 @@ export class InputValidator {
36
37
  }
37
38
 
38
39
  const data = input as Record<string, unknown>;
39
- const errors: ValidationError[] = [];
40
+ const errors: ValidationError[] = this.unknownIn(data);
40
41
  const row: Record<string, unknown> = {};
41
42
 
42
- for (const key of Object.keys(data)) {
43
- if (!Object.hasOwn(this.fields, key)) {
44
- errors.push({ path: [key], message: InputRefusal.unknownField });
45
- }
43
+ for (const [key, field] of Object.entries(this.fields)) {
44
+ const verdict = this.admit(field, data[key]);
45
+ if (verdict === undefined) continue;
46
+ if ('message' in verdict) errors.push({ path: [key, ...(verdict.path ?? [])], message: verdict.message });
47
+ else row[key] = verdict.value;
46
48
  }
47
49
 
48
- for (const [key, field] of Object.entries(this.fields)) {
49
- const path = [key];
50
- const value = data[key];
50
+ if (errors.length > 0) return { success: false, errors };
51
51
 
52
- if (value === undefined) {
53
- if (this.options.patch) continue;
54
- const absence = this.onAbsent(field);
55
- if (absence === null) {
56
- errors.push({ path, message: InputRefusal.required });
57
- continue;
58
- }
59
- if (absence === 'empty-list') row[key] = [];
60
- continue;
61
- }
52
+ return { success: true, data: row };
53
+ }
62
54
 
63
- if (Boundary.of(field).readOnly) {
64
- errors.push({ path, message: InputRefusal.readOnly });
65
- continue;
66
- }
67
- if (this.options.patch && Lifecycle.of(field).immutable) {
68
- errors.push({ path, message: InputRefusal.immutable });
69
- continue;
70
- }
55
+ private unknownIn(data: Record<string, unknown>): ValidationError[] {
56
+ return Object.keys(data)
57
+ .filter((key) => !Object.hasOwn(this.fields, key))
58
+ .map((key) => ({ path: [key], message: InputRefusal.unknownField }));
59
+ }
71
60
 
72
- const parsed = FieldValueValidator.of(field).parse(value);
73
- if ('error' in parsed) errors.push({ path: [...path, ...parsed.path ?? []], message: parsed.error });
74
- else row[key] = parsed.value;
75
- }
61
+ private admit(field: Field, value: unknown): Verdict | undefined {
62
+ if (value === undefined) return this.whenAbsent(field);
76
63
 
77
- if (errors.length > 0) return { success: false, errors };
78
- return { success: true, data: row };
64
+ if (Boundary.of(field).readOnly) return { message: InputRefusal.readOnly };
65
+ if (this.options.patch && Lifecycle.of(field).immutable) return { message: InputRefusal.immutable };
66
+
67
+ return FieldValueValidator.of(field).parse(value);
68
+ }
69
+
70
+ private whenAbsent(field: Field): Verdict | undefined {
71
+ if (this.options.patch) return undefined;
72
+
73
+ const absence = this.onAbsent(field);
74
+ if (absence === null) return { message: InputRefusal.required };
75
+
76
+ return absence === 'empty-list' ? { value: [] } : undefined;
79
77
  }
80
78
  }
@@ -0,0 +1,142 @@
1
+ import { Validator, type OutputUnit } from '@cfworker/json-schema';
2
+ import type { JsonSchema } from '../lib/JsonSchema.js';
3
+ import { isObject } from '../lib/utils.js';
4
+ import type { ValidationError } from '../lib/ValidationError.js';
5
+ import { locationOf } from '../lib/ValidationResult.js';
6
+
7
+ /**
8
+ * The one door onto the engine: a field's value against its shape, a declaration against the
9
+ * format of its key. The format is DATA, not a TypeScript interface: an interface is erased
10
+ * before a JS caller, a config or a card from another language could be measured against it.
11
+ */
12
+ export class JsonSchemaValidator {
13
+ private static readonly held = new WeakMap<JsonSchema, JsonSchemaValidator>();
14
+
15
+ private first?: Validator;
16
+ private every?: Validator;
17
+
18
+ private constructor(private readonly schema: JsonSchema) {}
19
+
20
+ static of(schema: JsonSchema): JsonSchemaValidator {
21
+ let validator = this.held.get(schema);
22
+
23
+ if (!validator) {
24
+ validator = new JsonSchemaValidator(schema);
25
+ this.held.set(schema, validator);
26
+ }
27
+
28
+ return validator;
29
+ }
30
+
31
+ /** `refusalOf({ update: 'maybe' }, ['lifecycle'])` → `lifecycle.update: Instance does not match any of ["now","forbidden"].` */
32
+ refusalOf(value: unknown, path: readonly string[]): ValidationError | undefined {
33
+ this.first ??= new Validator(this.schema, '2020-12', true);
34
+
35
+ const refused = refusedBy(this.first, value);
36
+
37
+ if (!Array.isArray(refused)) return under(path, refused);
38
+ if (!refused.length) return undefined;
39
+
40
+ const reasons = named(refused);
41
+
42
+ return at(path, reasons.length ? deepestOf(reasons) : refused[0]);
43
+ }
44
+
45
+ /**
46
+ * One refusal per key, so a declaration hears every fault at once. It reads through an engine
47
+ * of its own: the other stops at the first, which is what a single value wants.
48
+ */
49
+ refusalsOf(value: unknown, path: readonly string[]): ValidationError[] {
50
+ this.every ??= new Validator(this.schema, '2020-12', false);
51
+
52
+ const refused = refusedBy(this.every, value);
53
+
54
+ if (!Array.isArray(refused)) return [under(path, refused)];
55
+ if (!refused.length) return [];
56
+
57
+ const faults = [...byKey(named(refused)).values()];
58
+
59
+ return faults.length ? faults.map((units) => at(path, deepestOf(units))) : [at(path, refused[0])];
60
+ }
61
+ }
62
+
63
+ /** What it refused on, or the member JSON cannot hold — the engine throws on one rather than refusing. */
64
+ function refusedBy(engine: Validator, value: unknown): OutputUnit[] | ValidationError {
65
+ const json = stated(value);
66
+
67
+ try {
68
+ const verdict = engine.validate(json);
69
+
70
+ return verdict.valid ? [] : verdict.errors;
71
+ } catch {
72
+ const where = unreadableIn(json) ?? { path: [], value: json };
73
+
74
+ return { path: where.path, message: `Expected a JSON value — got ${typeof where.value}` };
75
+ }
76
+ }
77
+
78
+ /** `False boolean schema` names nothing: the unit above it carries the offending key. */
79
+ const named = (units: readonly OutputUnit[]): OutputUnit[] =>
80
+ units.filter((unit) => unit.keyword !== 'false');
81
+
82
+ /** The engine states its refusals outermost first: the deepest says where, the last one is why. */
83
+ function deepestOf(units: readonly OutputUnit[]): OutputUnit {
84
+ return units.reduce((held, unit) => (depthOf(held) > depthOf(unit) ? held : unit));
85
+ }
86
+
87
+ /**
88
+ * The units of one fault, addressed by the key they happened under. A unit on the value ITSELF
89
+ * points at a key when another one is deeper — `Property "lifecycle" does not match schema.` —
90
+ * so it is kept only when it is all there is.
91
+ */
92
+ function byKey(units: readonly OutputUnit[]): Map<string, OutputUnit[]> {
93
+ const held = new Map<string, OutputUnit[]>();
94
+
95
+ for (const unit of units) {
96
+ const key = locationOf(unit.instanceLocation)[0] ?? '';
97
+ held.set(key, [...(held.get(key) ?? []), unit]);
98
+ }
99
+
100
+ if (held.size > 1) held.delete('');
101
+
102
+ return held;
103
+ }
104
+
105
+ const at = (path: readonly string[], unit: OutputUnit): ValidationError => ({
106
+ path: [...path, ...locationOf(unit.instanceLocation)],
107
+ message: unit.error,
108
+ });
109
+
110
+ const under = (path: readonly string[], refusal: ValidationError): ValidationError => ({
111
+ path: [...path, ...refusal.path],
112
+ message: refusal.message,
113
+ });
114
+
115
+ const depthOf = (unit: OutputUnit): number => locationOf(unit.instanceLocation).length;
116
+
117
+ /** A key set to `undefined` states nothing, as in JSON — and the engine refuses to read one. */
118
+ function stated(value: unknown): unknown {
119
+ if (Array.isArray(value)) return value.map(stated);
120
+
121
+ if (!isObject(value)) return value;
122
+
123
+ const present = Object.entries(value).filter(([, member]) => member !== undefined);
124
+
125
+ return Object.fromEntries(present.map(([key, member]) => [key, stated(member)]));
126
+ }
127
+
128
+ /** Where the engine stopped: a function, a symbol or a bigint is not a value JSON holds. */
129
+ function unreadableIn(
130
+ value: unknown,
131
+ path: readonly string[] = [],
132
+ ): { path: readonly string[]; value: unknown } | undefined {
133
+ if (['function', 'symbol', 'bigint'].includes(typeof value)) return { path, value };
134
+
135
+ if (Array.isArray(value)) {
136
+ return value.flatMap((member, index) => unreadableIn(member, [...path, String(index)]) ?? [])[0];
137
+ }
138
+
139
+ if (!isObject(value)) return undefined;
140
+
141
+ return Object.entries(value).flatMap(([key, member]) => unreadableIn(member, [...path, key]) ?? [])[0];
142
+ }
@@ -1,4 +1,5 @@
1
1
  import { Field } from '../../field/Field.js';
2
+ import { SchemaError } from '../../SchemaError.js';
2
3
 
3
4
  export interface ListOptions {
4
5
  min?: number;
@@ -12,7 +13,7 @@ export interface ListOptions {
12
13
  */
13
14
  export function list<T>(item: Field<T>, opts?: ListOptions): Field<T[]> {
14
15
  if (item.role?.relation)
15
- throw new Error(
16
+ throw new SchemaError(
16
17
  'list() takes a value field (text(), number()…) — a relation has no value shape',
17
18
  );
18
19
  return new Field<T[]>({
@@ -1,8 +1,9 @@
1
1
  import { Field } from '../field/Field.js';
2
- import { EXTENSION_SLOTS } from '../axis/Axis.js';
2
+ import { Axes } from '../axis/Axes.js';
3
3
  import { dequal } from 'dequal';
4
+ import { SchemaError } from '../SchemaError.js';
4
5
 
5
- const MEMBER_SLOTS = [...EXTENSION_SLOTS, 'meta'] as const;
6
+ const memberSlots = (): string[] => [...Axes.names, 'meta'];
6
7
 
7
8
  /**
8
9
  * Builds a `rule/` word, which states members on the field it receives.
@@ -25,12 +26,14 @@ export type FieldWord = (field: Field<any>) => Field<any>;
25
26
  */
26
27
  function merge(name: string, field: Field, given: Partial<Field>): Partial<Field> {
27
28
  const merged: Record<string, unknown> = {};
29
+ const stated = given as Record<string, unknown>;
30
+ const held = field as unknown as Record<string, unknown>;
28
31
  if ('shape' in given) merged.shape = given.shape;
29
32
 
30
- for (const slot of MEMBER_SLOTS) {
31
- const members = given[slot];
33
+ for (const slot of memberSlots()) {
34
+ const members = stated[slot];
32
35
  if (members === undefined) continue;
33
- const already = field[slot] as Record<string, unknown> | undefined;
36
+ const already = held[slot] as Record<string, unknown> | undefined;
34
37
  if (typeof members !== 'object' || members === null || typeof already !== 'object') {
35
38
  merged[slot] = members;
36
39
  continue;
@@ -38,7 +41,7 @@ function merge(name: string, field: Field, given: Partial<Field>): Partial<Field
38
41
  for (const [member, value] of Object.entries(members)) {
39
42
  const previous = already?.[member];
40
43
  if (previous === undefined || dequal(previous, value)) continue;
41
- throw new Error(
44
+ throw new SchemaError(
42
45
  `vocabulary: \`${name}\` states ${slot}.${member} = ${JSON.stringify(value)}, but the ` +
43
46
  `field already states ${JSON.stringify(previous)}. Apply one or the other, not both.`,
44
47
  );
@@ -1,4 +0,0 @@
1
- import type { Fields } from './field/Fields.js';
2
- import type { Values } from './Values.js';
3
- export type PartialValues<TFields extends Fields> = Partial<Values<TFields>>;
4
- //# sourceMappingURL=PartialValues.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"PartialValues.d.ts","sourceRoot":"","sources":["../src/PartialValues.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,MAAM,aAAa,CAAC,OAAO,SAAS,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=PartialValues.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"PartialValues.js","sourceRoot":"","sources":["../src/PartialValues.ts"],"names":[],"mappings":""}
package/dist/Values.d.ts DELETED
@@ -1,6 +0,0 @@
1
- import type { Field } from './field/Field.js';
2
- import type { Fields } from './field/Fields.js';
3
- export type Values<TFields extends Fields> = {
4
- [K in keyof TFields]: TFields[K] extends Field<infer T> ? T : never;
5
- };
6
- //# sourceMappingURL=Values.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Values.d.ts","sourceRoot":"","sources":["../src/Values.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD,MAAM,MAAM,MAAM,CAAC,OAAO,SAAS,MAAM,IAAI;KAC1C,CAAC,IAAI,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK;CACpE,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"Values.js","sourceRoot":"","sources":["../src/Values.ts"],"names":[],"mappings":""}
@@ -1,17 +0,0 @@
1
- import type { Decoder } from './Decoder.js';
2
- import type { Encoder } from './Encoder.js';
3
- import type { BoundaryRules } from './BoundaryRules.js';
4
- import { Registry } from '../../lib/Registry.js';
5
- /**
6
- * `decoders` for a value coming in, `encoders` for one going out, `aliases` for the word
7
- * that names a pair. Three registries, so a codec is never half declared.
8
- * FR : `decoders` à l'entrée, `encoders` à la sortie, `aliases` pour le mot qui nomme la paire.
9
- * `Boundaries.aliases.register('isoDate', { in: { decode: 'isoDate' }, out: { encode: 'isoDate' } })`
10
- * → a field saying `boundary: 'isoDate'` decodes to a `Date` and leaves as a string
11
- */
12
- export declare const Boundaries: {
13
- decoders: Registry<Decoder>;
14
- encoders: Registry<Encoder>;
15
- aliases: Registry<BoundaryRules>;
16
- };
17
- //# sourceMappingURL=Boundaries.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Boundaries.d.ts","sourceRoot":"","sources":["../../../src/axis/boundary/Boundaries.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD;;;;;;GAMG;AACH,eAAO,MAAM,UAAU;IACrB,QAAQ;IAIR,QAAQ;IAIR,OAAO;CACR,CAAC"}
@@ -1,25 +0,0 @@
1
- import { Registry } from '../../lib/Registry.js';
2
- /**
3
- * `decoders` for a value coming in, `encoders` for one going out, `aliases` for the word
4
- * that names a pair. Three registries, so a codec is never half declared.
5
- * FR : `decoders` à l'entrée, `encoders` à la sortie, `aliases` pour le mot qui nomme la paire.
6
- * `Boundaries.aliases.register('isoDate', { in: { decode: 'isoDate' }, out: { encode: 'isoDate' } })`
7
- * → a field saying `boundary: 'isoDate'` decodes to a `Date` and leaves as a string
8
- */
9
- export const Boundaries = {
10
- decoders: new Registry('boundary decoder', 'call Boundaries.decoders.register(name, fn)'),
11
- encoders: new Registry('boundary encoder', 'call Boundaries.encoders.register(name, fn)'),
12
- aliases: new Registry('boundary alias'),
13
- };
14
- Boundaries.decoders.register('isoDate', (value) => {
15
- if (value instanceof Date)
16
- return { value };
17
- if (typeof value === 'string') {
18
- const date = new Date(value);
19
- return Number.isNaN(date.getTime()) ? { error: 'Invalid date' } : { value: date };
20
- }
21
- return { error: 'Expected a date' };
22
- });
23
- Boundaries.encoders.register('isoDate', (value) => value instanceof Date ? value.toISOString() : value);
24
- Boundaries.aliases.register('isoDate', { in: { decode: 'isoDate' }, out: { encode: 'isoDate' } });
25
- //# sourceMappingURL=Boundaries.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Boundaries.js","sourceRoot":"","sources":["../../../src/axis/boundary/Boundaries.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,QAAQ,EAAE,IAAI,QAAQ,CACpB,kBAAkB,EAClB,6CAA6C,CAC9C;IACD,QAAQ,EAAE,IAAI,QAAQ,CACpB,kBAAkB,EAClB,6CAA6C,CAC9C;IACD,OAAO,EAAE,IAAI,QAAQ,CAAgB,gBAAgB,CAAC;CACvD,CAAC;AAEF,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;IAChD,IAAI,KAAK,YAAY,IAAI;QAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC5C,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC;QAC7B,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACpF,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC;AACtC,CAAC,CAAC,CAAC;AACH,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE,CAChD,KAAK,YAAY,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,KAAK,CACpD,CAAC;AACF,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC"}
@@ -1,4 +0,0 @@
1
- import type { Axis } from '../Axis.js';
2
- import type { BoundaryRef } from './BoundaryRef.js';
3
- export declare const boundaryAxis: Axis<BoundaryRef, BoundaryRef>;
4
- //# sourceMappingURL=BoundaryAxis.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BoundaryAxis.d.ts","sourceRoot":"","sources":["../../../src/axis/boundary/BoundaryAxis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAGvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,eAAO,MAAM,YAAY,EAAE,IAAI,CAAC,WAAW,EAAE,WAAW,CA0BvD,CAAC"}
@@ -1,30 +0,0 @@
1
- import { admitWire } from '../../projection/card/admission.js';
2
- import { isObject, shown } from '../../lib/utils.js';
3
- export const boundaryAxis = {
4
- slot: 'boundary',
5
- validator(value, errors) {
6
- if (typeof value === 'string')
7
- return;
8
- if (!isObject(value)) {
9
- errors.push({
10
- path: ['boundary'],
11
- message: `Expected an alias name or { in, out } — got ${shown(value)}`,
12
- });
13
- return;
14
- }
15
- for (const [side, verb] of [['in', 'decode'], ['out', 'encode']]) {
16
- const rule = value[side];
17
- if (rule === undefined || rule === 'closed')
18
- continue;
19
- if (!isObject(rule) || typeof rule[verb] !== 'string') {
20
- errors.push({ path: ['boundary', side], message: `Expected 'closed' or { ${verb}: <name> }` });
21
- }
22
- }
23
- },
24
- describe: (value) => value,
25
- reconstruct: (wire) => {
26
- admitWire(boundaryAxis.validator, wire, 'boundary');
27
- return wire;
28
- },
29
- };
30
- //# sourceMappingURL=BoundaryAxis.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BoundaryAxis.js","sourceRoot":"","sources":["../../../src/axis/boundary/BoundaryAxis.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAGrD,MAAM,CAAC,MAAM,YAAY,GAAmC;IAC1D,IAAI,EAAE,UAAU;IAEhB,SAAS,CAAC,KAAK,EAAE,MAAM;QACrB,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,OAAO;QACtC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACrB,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,CAAC,UAAU,CAAC;gBAClB,OAAO,EAAE,+CAA+C,KAAK,CAAC,KAAK,CAAC,EAAE;aACvE,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAU,EAAE,CAAC;YAC1E,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;YACzB,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,QAAQ;gBAAE,SAAS;YACtD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,QAAQ,EAAE,CAAC;gBACtD,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,0BAA0B,IAAI,YAAY,EAAE,CAAC,CAAC;YACjG,CAAC;QACH,CAAC;IACH,CAAC;IAED,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK;IAC1B,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE;QACpB,SAAS,CAAC,YAAY,CAAC,SAAS,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;QACpD,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAC"}
@@ -1,3 +0,0 @@
1
- import type { BoundaryRules } from './BoundaryRules.js';
2
- export type BoundaryRef = 'isoDate' | (string & {}) | BoundaryRules;
3
- //# sourceMappingURL=BoundaryRef.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BoundaryRef.d.ts","sourceRoot":"","sources":["../../../src/axis/boundary/BoundaryRef.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,GAAG,aAAa,CAAC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=BoundaryRef.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BoundaryRef.js","sourceRoot":"","sources":["../../../src/axis/boundary/BoundaryRef.ts"],"names":[],"mappings":""}
@@ -1,9 +0,0 @@
1
- export interface BoundaryRules {
2
- in?: 'closed' | {
3
- decode: string;
4
- };
5
- out?: 'closed' | {
6
- encode: string;
7
- };
8
- }
9
- //# sourceMappingURL=BoundaryRules.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BoundaryRules.d.ts","sourceRoot":"","sources":["../../../src/axis/boundary/BoundaryRules.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,EAAE,CAAC,EAAE,QAAQ,GAAG;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACnC,GAAG,CAAC,EAAE,QAAQ,GAAG;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CACrC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=BoundaryRules.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BoundaryRules.js","sourceRoot":"","sources":["../../../src/axis/boundary/BoundaryRules.ts"],"names":[],"mappings":""}
@@ -1,18 +0,0 @@
1
- /**
2
- * What "now" means, for the two functions that stamp it.
3
- *
4
- * The ONE place either of them reads the time, which is what makes it substitutable at
5
- * all: `created()`, `updated()` and `create: 'now'` are realized through this and nowhere
6
- * else, so a test that needs a stable instant sets it here instead of intercepting `Date`
7
- * globally — where Rails had to build `travel_to` over the language.
8
- *
9
- * A value rather than a mock: nothing here is a channel, and a frozen clock is a fact
10
- * about the run, not an interception of a call.
11
- */
12
- export declare class Clock {
13
- private static reading;
14
- static now(): number;
15
- /** One substitution moves time for every stamp in the process at once. */
16
- static freeze(at: number | Date): () => void;
17
- }
18
- //# sourceMappingURL=Clock.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Clock.d.ts","sourceRoot":"","sources":["../../../src/axis/lifecycle/Clock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,qBAAa,KAAK;IAChB,OAAO,CAAC,MAAM,CAAC,OAAO,CAA0B;IAEhD,MAAM,CAAC,GAAG,IAAI,MAAM,CAEnB;IAED,0EAA0E;IAC1E,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,IAAI,CAK3C;CACF"}
@@ -1,25 +0,0 @@
1
- /**
2
- * What "now" means, for the two functions that stamp it.
3
- *
4
- * The ONE place either of them reads the time, which is what makes it substitutable at
5
- * all: `created()`, `updated()` and `create: 'now'` are realized through this and nowhere
6
- * else, so a test that needs a stable instant sets it here instead of intercepting `Date`
7
- * globally — where Rails had to build `travel_to` over the language.
8
- *
9
- * A value rather than a mock: nothing here is a channel, and a frozen clock is a fact
10
- * about the run, not an interception of a call.
11
- */
12
- export class Clock {
13
- static reading = Date.now;
14
- static now() {
15
- return this.reading();
16
- }
17
- /** One substitution moves time for every stamp in the process at once. */
18
- static freeze(at) {
19
- const previous = this.reading;
20
- const instant = at instanceof Date ? at.getTime() : at;
21
- this.reading = () => instant;
22
- return () => { this.reading = previous; };
23
- }
24
- }
25
- //# sourceMappingURL=Clock.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Clock.js","sourceRoot":"","sources":["../../../src/axis/lifecycle/Clock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,OAAO,KAAK;IACR,MAAM,CAAC,OAAO,GAAiB,IAAI,CAAC,GAAG,CAAC;IAEhD,MAAM,CAAC,GAAG;QACR,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC;IACxB,CAAC;IAED,0EAA0E;IAC1E,MAAM,CAAC,MAAM,CAAC,EAAiB;QAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC;QAC9B,MAAM,OAAO,GAAG,EAAE,YAAY,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,IAAI,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC;QAC7B,OAAO,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC5C,CAAC;CACF"}
@@ -1,4 +0,0 @@
1
- import type { Axis } from '../Axis.js';
2
- import { type LifecycleRules } from './LifecycleRules.js';
3
- export declare const lifecycleAxis: Axis<LifecycleRules, LifecycleRules>;
4
- //# sourceMappingURL=LifecycleAxis.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"LifecycleAxis.d.ts","sourceRoot":"","sources":["../../../src/axis/lifecycle/LifecycleAxis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAKvC,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,eAAO,MAAM,aAAa,EAAE,IAAI,CAAC,cAAc,EAAE,cAAc,CAsB9D,CAAC"}