@fougere/schema 0.6.0-alpha.0 → 0.8.0-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 (435) hide show
  1. package/README.md +5 -4
  2. package/dist/{schema/Schema.d.ts → Schema.d.ts} +17 -27
  3. package/dist/Schema.d.ts.map +1 -0
  4. package/dist/{schema/Schema.js → Schema.js} +22 -62
  5. package/dist/Schema.js.map +1 -0
  6. package/dist/SchemaDefinition.d.ts +73 -0
  7. package/dist/SchemaDefinition.d.ts.map +1 -0
  8. package/dist/SchemaDefinition.js +184 -0
  9. package/dist/SchemaDefinition.js.map +1 -0
  10. package/dist/SchemaDerivation.d.ts +16 -0
  11. package/dist/SchemaDerivation.d.ts.map +1 -0
  12. package/dist/SchemaDerivation.js +31 -0
  13. package/dist/SchemaDerivation.js.map +1 -0
  14. package/dist/{schema/SchemaView.d.ts → SchemaView.d.ts} +9 -9
  15. package/dist/SchemaView.d.ts.map +1 -0
  16. package/dist/{schema/SchemaView.js.map → SchemaView.js.map} +1 -1
  17. package/dist/{schema/axis → axis}/Axis.d.ts +2 -2
  18. package/dist/axis/Axis.d.ts.map +1 -0
  19. package/dist/axis/Axis.js.map +1 -0
  20. package/dist/axis/Meta.d.ts.map +1 -0
  21. package/dist/{schema/axis → axis}/Meta.js.map +1 -1
  22. package/dist/axis/boundary/Boundaries.d.ts +21 -0
  23. package/dist/axis/boundary/Boundaries.d.ts.map +1 -0
  24. package/dist/axis/boundary/Boundaries.js +25 -0
  25. package/dist/axis/boundary/Boundaries.js.map +1 -0
  26. package/dist/{schema/axis → axis}/boundary/Boundary.d.ts +3 -1
  27. package/dist/axis/boundary/Boundary.d.ts.map +1 -0
  28. package/dist/{schema/axis → axis}/boundary/Boundary.js +8 -6
  29. package/dist/axis/boundary/Boundary.js.map +1 -0
  30. package/dist/axis/boundary/BoundaryAxis.d.ts.map +1 -0
  31. package/dist/{schema/axis → axis}/boundary/BoundaryAxis.js +4 -4
  32. package/dist/axis/boundary/BoundaryAxis.js.map +1 -0
  33. package/dist/{schema/axis → axis}/lifecycle/Clock.d.ts +1 -1
  34. package/dist/axis/lifecycle/Clock.d.ts.map +1 -0
  35. package/dist/{schema/axis → axis}/lifecycle/Clock.js +1 -1
  36. package/dist/axis/lifecycle/Clock.js.map +1 -0
  37. package/dist/axis/lifecycle/Generators.d.ts +10 -0
  38. package/dist/axis/lifecycle/Generators.d.ts.map +1 -0
  39. package/dist/axis/lifecycle/Generators.js +20 -0
  40. package/dist/axis/lifecycle/Generators.js.map +1 -0
  41. package/dist/axis/lifecycle/Lifecycle.d.ts.map +1 -0
  42. package/dist/axis/lifecycle/Lifecycle.js.map +1 -0
  43. package/dist/axis/lifecycle/LifecycleAxis.d.ts.map +1 -0
  44. package/dist/{schema/axis → axis}/lifecycle/LifecycleAxis.js +11 -6
  45. package/dist/axis/lifecycle/LifecycleAxis.js.map +1 -0
  46. package/dist/axis/lifecycle/apply.d.ts +15 -0
  47. package/dist/axis/lifecycle/apply.d.ts.map +1 -0
  48. package/dist/axis/lifecycle/apply.js +50 -0
  49. package/dist/axis/lifecycle/apply.js.map +1 -0
  50. package/dist/{schema/axis → axis}/role/Relation.d.ts +3 -2
  51. package/dist/axis/role/Relation.d.ts.map +1 -0
  52. package/dist/{schema/axis → axis}/role/Relation.js +6 -5
  53. package/dist/axis/role/Relation.js.map +1 -0
  54. package/dist/{schema/axis → axis}/role/Role.d.ts +6 -6
  55. package/dist/axis/role/Role.d.ts.map +1 -0
  56. package/dist/axis/role/Role.js +36 -0
  57. package/dist/axis/role/Role.js.map +1 -0
  58. package/dist/{schema/axis → axis}/role/RoleAxis.d.ts +1 -1
  59. package/dist/axis/role/RoleAxis.d.ts.map +1 -0
  60. package/dist/{schema/axis → axis}/role/RoleAxis.js +28 -36
  61. package/dist/axis/role/RoleAxis.js.map +1 -0
  62. package/dist/axis/shape/Formats.d.ts +11 -0
  63. package/dist/axis/shape/Formats.d.ts.map +1 -0
  64. package/dist/axis/shape/Formats.js +9 -0
  65. package/dist/axis/shape/Formats.js.map +1 -0
  66. package/dist/{schema/axis → axis}/shape/Shape.d.ts +12 -3
  67. package/dist/axis/shape/Shape.d.ts.map +1 -0
  68. package/dist/axis/shape/Shape.js +77 -0
  69. package/dist/axis/shape/Shape.js.map +1 -0
  70. package/dist/entity/EntityAdapterSet.d.ts +22 -0
  71. package/dist/entity/EntityAdapterSet.d.ts.map +1 -0
  72. package/dist/entity/EntityAdapterSet.js +63 -0
  73. package/dist/entity/EntityAdapterSet.js.map +1 -0
  74. package/dist/entity/EntityAdapters.d.ts +1 -24
  75. package/dist/entity/EntityAdapters.d.ts.map +1 -1
  76. package/dist/entity/EntityAdapters.js +1 -74
  77. package/dist/entity/EntityAdapters.js.map +1 -1
  78. package/dist/entity/EntityDeclarations.d.ts +1 -1
  79. package/dist/entity/EntityDeclarations.d.ts.map +1 -1
  80. package/dist/entity.d.ts +7 -2
  81. package/dist/entity.d.ts.map +1 -1
  82. package/dist/entity.js +6 -1
  83. package/dist/entity.js.map +1 -1
  84. package/dist/{schema/fields → field}/Field.d.ts +3 -5
  85. package/dist/field/Field.d.ts.map +1 -0
  86. package/dist/field/Field.js +35 -0
  87. package/dist/field/Field.js.map +1 -0
  88. package/dist/field/FieldSet.d.ts +22 -0
  89. package/dist/field/FieldSet.d.ts.map +1 -0
  90. package/dist/field/FieldSet.js +58 -0
  91. package/dist/field/FieldSet.js.map +1 -0
  92. package/dist/index.d.ts +26 -56
  93. package/dist/index.d.ts.map +1 -1
  94. package/dist/index.js +21 -47
  95. package/dist/index.js.map +1 -1
  96. package/dist/lib/Registry.d.ts +12 -0
  97. package/dist/lib/Registry.d.ts.map +1 -0
  98. package/dist/lib/Registry.js +29 -0
  99. package/dist/lib/Registry.js.map +1 -0
  100. package/dist/lib/index.d.ts +3 -0
  101. package/dist/lib/index.d.ts.map +1 -0
  102. package/dist/lib/index.js +3 -0
  103. package/dist/lib/index.js.map +1 -0
  104. package/dist/lib/utils.d.ts.map +1 -0
  105. package/dist/lib/utils.js.map +1 -0
  106. package/dist/projection/Cases.d.ts +9 -20
  107. package/dist/projection/Cases.d.ts.map +1 -1
  108. package/dist/projection/Cases.js +44 -39
  109. package/dist/projection/Cases.js.map +1 -1
  110. package/dist/projection/Visibility.d.ts +2 -1
  111. package/dist/projection/Visibility.d.ts.map +1 -1
  112. package/dist/projection/Visibility.js +4 -3
  113. package/dist/projection/Visibility.js.map +1 -1
  114. package/dist/projection/card/Bundle.d.ts +1 -1
  115. package/dist/projection/card/Bundle.d.ts.map +1 -1
  116. package/dist/projection/card/Bundle.js +7 -7
  117. package/dist/projection/card/Bundle.js.map +1 -1
  118. package/dist/projection/card/Card.d.ts +7 -13
  119. package/dist/projection/card/Card.d.ts.map +1 -1
  120. package/dist/projection/card/Card.js +101 -70
  121. package/dist/projection/card/Card.js.map +1 -1
  122. package/dist/projection/card/Descriptor.d.ts +7 -7
  123. package/dist/projection/card/Descriptor.d.ts.map +1 -1
  124. package/dist/projection/card/admission.d.ts +21 -5
  125. package/dist/projection/card/admission.d.ts.map +1 -1
  126. package/dist/projection/card/admission.js +33 -5
  127. package/dist/projection/card/admission.js.map +1 -1
  128. package/dist/projection/card/diff.d.ts +2 -2
  129. package/dist/projection/card/diff.d.ts.map +1 -1
  130. package/dist/{judge/result.d.ts → validation.d.ts} +1 -1
  131. package/dist/validation.d.ts.map +1 -0
  132. package/dist/validation.js +2 -0
  133. package/dist/validation.js.map +1 -0
  134. package/dist/validator/AdapterFieldValidator.d.ts +14 -0
  135. package/dist/validator/AdapterFieldValidator.d.ts.map +1 -0
  136. package/dist/validator/AdapterFieldValidator.js +36 -0
  137. package/dist/validator/AdapterFieldValidator.js.map +1 -0
  138. package/dist/validator/FieldDeclarationValidator.d.ts +9 -0
  139. package/dist/validator/FieldDeclarationValidator.d.ts.map +1 -0
  140. package/dist/{judge/FieldJudge.js → validator/FieldDeclarationValidator.js} +8 -8
  141. package/dist/validator/FieldDeclarationValidator.js.map +1 -0
  142. package/dist/validator/FieldValueValidator.d.ts +13 -0
  143. package/dist/validator/FieldValueValidator.d.ts.map +1 -0
  144. package/dist/{judge/ValueJudge.js → validator/FieldValueValidator.js} +12 -11
  145. package/dist/validator/FieldValueValidator.js.map +1 -0
  146. package/dist/validator/InputRefusal.d.ts +8 -0
  147. package/dist/validator/InputRefusal.d.ts.map +1 -0
  148. package/dist/validator/InputRefusal.js +8 -0
  149. package/dist/validator/InputRefusal.js.map +1 -0
  150. package/dist/validator/InputValidator.d.ts +15 -0
  151. package/dist/validator/InputValidator.d.ts.map +1 -0
  152. package/dist/{judge/RowJudge.js → validator/InputValidator.js} +25 -21
  153. package/dist/validator/InputValidator.js.map +1 -0
  154. package/dist/vocabulary/bool.d.ts +6 -1
  155. package/dist/vocabulary/bool.d.ts.map +1 -1
  156. package/dist/vocabulary/bool.js +6 -1
  157. package/dist/vocabulary/bool.js.map +1 -1
  158. package/dist/vocabulary/created.d.ts +6 -1
  159. package/dist/vocabulary/created.d.ts.map +1 -1
  160. package/dist/vocabulary/created.js +5 -0
  161. package/dist/vocabulary/created.js.map +1 -1
  162. package/dist/vocabulary/date.d.ts +6 -1
  163. package/dist/vocabulary/date.d.ts.map +1 -1
  164. package/dist/vocabulary/date.js +6 -1
  165. package/dist/vocabulary/date.js.map +1 -1
  166. package/dist/vocabulary/email.d.ts +6 -1
  167. package/dist/vocabulary/email.d.ts.map +1 -1
  168. package/dist/vocabulary/email.js +5 -0
  169. package/dist/vocabulary/email.js.map +1 -1
  170. package/dist/vocabulary/immutable.d.ts +6 -1
  171. package/dist/vocabulary/immutable.d.ts.map +1 -1
  172. package/dist/vocabulary/immutable.js +5 -0
  173. package/dist/vocabulary/immutable.js.map +1 -1
  174. package/dist/vocabulary/index.d.ts +23 -0
  175. package/dist/vocabulary/index.d.ts.map +1 -0
  176. package/dist/vocabulary/index.js +23 -0
  177. package/dist/vocabulary/index.js.map +1 -0
  178. package/dist/vocabulary/indexed.d.ts +6 -1
  179. package/dist/vocabulary/indexed.d.ts.map +1 -1
  180. package/dist/vocabulary/indexed.js +5 -0
  181. package/dist/vocabulary/indexed.js.map +1 -1
  182. package/dist/vocabulary/json.d.ts +2 -2
  183. package/dist/vocabulary/json.d.ts.map +1 -1
  184. package/dist/vocabulary/json.js +9 -4
  185. package/dist/vocabulary/json.js.map +1 -1
  186. package/dist/vocabulary/list.d.ts +6 -1
  187. package/dist/vocabulary/list.d.ts.map +1 -1
  188. package/dist/vocabulary/list.js +6 -1
  189. package/dist/vocabulary/list.js.map +1 -1
  190. package/dist/vocabulary/many.d.ts +7 -2
  191. package/dist/vocabulary/many.d.ts.map +1 -1
  192. package/dist/vocabulary/many.js +7 -2
  193. package/dist/vocabulary/many.js.map +1 -1
  194. package/dist/vocabulary/nullable.d.ts +6 -1
  195. package/dist/vocabulary/nullable.d.ts.map +1 -1
  196. package/dist/vocabulary/nullable.js +7 -2
  197. package/dist/vocabulary/nullable.js.map +1 -1
  198. package/dist/vocabulary/number.d.ts +6 -1
  199. package/dist/vocabulary/number.d.ts.map +1 -1
  200. package/dist/vocabulary/number.js +6 -1
  201. package/dist/vocabulary/number.js.map +1 -1
  202. package/dist/vocabulary/oneOf.d.ts +1 -1
  203. package/dist/vocabulary/oneOf.d.ts.map +1 -1
  204. package/dist/vocabulary/oneOf.js +6 -1
  205. package/dist/vocabulary/oneOf.js.map +1 -1
  206. package/dist/vocabulary/optional.d.ts +6 -1
  207. package/dist/vocabulary/optional.d.ts.map +1 -1
  208. package/dist/vocabulary/optional.js +7 -2
  209. package/dist/vocabulary/optional.js.map +1 -1
  210. package/dist/vocabulary/primary.d.ts +2 -2
  211. package/dist/vocabulary/primary.d.ts.map +1 -1
  212. package/dist/vocabulary/primary.js +7 -2
  213. package/dist/vocabulary/primary.js.map +1 -1
  214. package/dist/vocabulary/readOnly.d.ts +6 -1
  215. package/dist/vocabulary/readOnly.d.ts.map +1 -1
  216. package/dist/vocabulary/readOnly.js +6 -1
  217. package/dist/vocabulary/readOnly.js.map +1 -1
  218. package/dist/vocabulary/ref.d.ts +7 -2
  219. package/dist/vocabulary/ref.d.ts.map +1 -1
  220. package/dist/vocabulary/ref.js +7 -2
  221. package/dist/vocabulary/ref.js.map +1 -1
  222. package/dist/vocabulary/text.d.ts +7 -2
  223. package/dist/vocabulary/text.d.ts.map +1 -1
  224. package/dist/vocabulary/text.js +6 -1
  225. package/dist/vocabulary/text.js.map +1 -1
  226. package/dist/vocabulary/unique.d.ts +6 -1
  227. package/dist/vocabulary/unique.d.ts.map +1 -1
  228. package/dist/vocabulary/unique.js +7 -3
  229. package/dist/vocabulary/unique.js.map +1 -1
  230. package/dist/vocabulary/updated.d.ts +6 -1
  231. package/dist/vocabulary/updated.d.ts.map +1 -1
  232. package/dist/vocabulary/updated.js +5 -0
  233. package/dist/vocabulary/updated.js.map +1 -1
  234. package/dist/vocabulary/url.d.ts +6 -1
  235. package/dist/vocabulary/url.d.ts.map +1 -1
  236. package/dist/vocabulary/url.js +5 -0
  237. package/dist/vocabulary/url.js.map +1 -1
  238. package/dist/vocabulary/vocabulary.d.ts +6 -1
  239. package/dist/vocabulary/vocabulary.d.ts.map +1 -1
  240. package/dist/vocabulary/vocabulary.js +22 -12
  241. package/dist/vocabulary/vocabulary.js.map +1 -1
  242. package/dist/vocabulary/writeOnly.d.ts +6 -1
  243. package/dist/vocabulary/writeOnly.d.ts.map +1 -1
  244. package/dist/vocabulary/writeOnly.js +6 -1
  245. package/dist/vocabulary/writeOnly.js.map +1 -1
  246. package/package.json +1 -1
  247. package/src/{schema/Schema.ts → Schema.ts} +32 -75
  248. package/src/SchemaDefinition.ts +257 -0
  249. package/src/SchemaDerivation.ts +44 -0
  250. package/src/{schema/SchemaView.ts → SchemaView.ts} +9 -9
  251. package/src/{schema/axis → axis}/Axis.ts +2 -2
  252. package/src/axis/boundary/Boundaries.ts +37 -0
  253. package/src/{schema/axis → axis}/boundary/Boundary.ts +9 -7
  254. package/src/{schema/axis → axis}/boundary/BoundaryAxis.ts +4 -4
  255. package/src/{schema/axis → axis}/lifecycle/Clock.ts +1 -1
  256. package/src/axis/lifecycle/Generators.ts +29 -0
  257. package/src/{schema/axis → axis}/lifecycle/LifecycleAxis.ts +12 -7
  258. package/src/axis/lifecycle/apply.ts +53 -0
  259. package/src/{schema/axis → axis}/role/Relation.ts +6 -5
  260. package/src/axis/role/Role.ts +52 -0
  261. package/src/{schema/axis → axis}/role/RoleAxis.ts +28 -40
  262. package/src/axis/shape/Formats.ts +20 -0
  263. package/src/{schema/axis → axis}/shape/Shape.ts +45 -18
  264. package/src/entity/EntityAdapterSet.ts +81 -0
  265. package/src/entity/EntityAdapters.ts +4 -96
  266. package/src/entity/EntityDeclarations.ts +1 -1
  267. package/src/entity.ts +7 -2
  268. package/src/{schema/fields → field}/Field.ts +8 -28
  269. package/src/field/FieldSet.ts +75 -0
  270. package/src/index.ts +34 -91
  271. package/src/lib/Registry.ts +37 -0
  272. package/src/lib/index.ts +2 -0
  273. package/src/projection/Cases.ts +56 -55
  274. package/src/projection/Visibility.ts +5 -4
  275. package/src/projection/card/Bundle.ts +9 -9
  276. package/src/projection/card/Card.ts +109 -75
  277. package/src/projection/card/Descriptor.ts +7 -7
  278. package/src/projection/card/admission.ts +37 -6
  279. package/src/projection/card/diff.ts +2 -2
  280. package/src/validator/AdapterFieldValidator.ts +40 -0
  281. package/src/{judge/FieldJudge.ts → validator/FieldDeclarationValidator.ts} +10 -10
  282. package/src/{judge/ValueJudge.ts → validator/FieldValueValidator.ts} +14 -13
  283. package/src/validator/InputRefusal.ts +7 -0
  284. package/src/{judge/RowJudge.ts → validator/InputValidator.ts} +31 -24
  285. package/src/vocabulary/bool.ts +6 -1
  286. package/src/vocabulary/created.ts +6 -1
  287. package/src/vocabulary/date.ts +6 -1
  288. package/src/vocabulary/email.ts +6 -1
  289. package/src/vocabulary/immutable.ts +6 -1
  290. package/src/vocabulary/index.ts +22 -0
  291. package/src/vocabulary/indexed.ts +6 -1
  292. package/src/vocabulary/json.ts +10 -5
  293. package/src/vocabulary/list.ts +6 -1
  294. package/src/vocabulary/many.ts +7 -2
  295. package/src/vocabulary/nullable.ts +8 -3
  296. package/src/vocabulary/number.ts +6 -1
  297. package/src/vocabulary/oneOf.ts +6 -1
  298. package/src/vocabulary/optional.ts +8 -3
  299. package/src/vocabulary/primary.ts +7 -2
  300. package/src/vocabulary/readOnly.ts +7 -2
  301. package/src/vocabulary/ref.ts +7 -2
  302. package/src/vocabulary/text.ts +7 -2
  303. package/src/vocabulary/unique.ts +8 -4
  304. package/src/vocabulary/updated.ts +6 -1
  305. package/src/vocabulary/url.ts +6 -1
  306. package/src/vocabulary/vocabulary.ts +22 -12
  307. package/src/vocabulary/writeOnly.ts +7 -2
  308. package/dist/judge/FieldJudge.d.ts +0 -9
  309. package/dist/judge/FieldJudge.d.ts.map +0 -1
  310. package/dist/judge/FieldJudge.js.map +0 -1
  311. package/dist/judge/RowJudge.d.ts +0 -12
  312. package/dist/judge/RowJudge.d.ts.map +0 -1
  313. package/dist/judge/RowJudge.js.map +0 -1
  314. package/dist/judge/RowRefusal.d.ts +0 -17
  315. package/dist/judge/RowRefusal.d.ts.map +0 -1
  316. package/dist/judge/RowRefusal.js +0 -16
  317. package/dist/judge/RowRefusal.js.map +0 -1
  318. package/dist/judge/ValueJudge.d.ts +0 -12
  319. package/dist/judge/ValueJudge.d.ts.map +0 -1
  320. package/dist/judge/ValueJudge.js.map +0 -1
  321. package/dist/judge/options.d.ts +0 -4
  322. package/dist/judge/options.d.ts.map +0 -1
  323. package/dist/judge/options.js +0 -2
  324. package/dist/judge/options.js.map +0 -1
  325. package/dist/judge/result.d.ts.map +0 -1
  326. package/dist/judge/result.js +0 -2
  327. package/dist/judge/result.js.map +0 -1
  328. package/dist/projection/SchemaOrCard.d.ts +0 -7
  329. package/dist/projection/SchemaOrCard.d.ts.map +0 -1
  330. package/dist/projection/SchemaOrCard.js +0 -11
  331. package/dist/projection/SchemaOrCard.js.map +0 -1
  332. package/dist/projection/card/EntityTypeSource.d.ts +0 -12
  333. package/dist/projection/card/EntityTypeSource.d.ts.map +0 -1
  334. package/dist/projection/card/EntityTypeSource.js +0 -78
  335. package/dist/projection/card/EntityTypeSource.js.map +0 -1
  336. package/dist/projection/card/FacadeTypeSource.d.ts +0 -19
  337. package/dist/projection/card/FacadeTypeSource.d.ts.map +0 -1
  338. package/dist/projection/card/FacadeTypeSource.js +0 -40
  339. package/dist/projection/card/FacadeTypeSource.js.map +0 -1
  340. package/dist/schema/Schema.d.ts.map +0 -1
  341. package/dist/schema/Schema.js.map +0 -1
  342. package/dist/schema/SchemaDefinition.d.ts +0 -60
  343. package/dist/schema/SchemaDefinition.d.ts.map +0 -1
  344. package/dist/schema/SchemaDefinition.js +0 -85
  345. package/dist/schema/SchemaDefinition.js.map +0 -1
  346. package/dist/schema/SchemaDerivation.d.ts +0 -34
  347. package/dist/schema/SchemaDerivation.d.ts.map +0 -1
  348. package/dist/schema/SchemaDerivation.js +0 -51
  349. package/dist/schema/SchemaDerivation.js.map +0 -1
  350. package/dist/schema/SchemaView.d.ts.map +0 -1
  351. package/dist/schema/axis/Axis.d.ts.map +0 -1
  352. package/dist/schema/axis/Axis.js.map +0 -1
  353. package/dist/schema/axis/Meta.d.ts.map +0 -1
  354. package/dist/schema/axis/boundary/Boundaries.d.ts +0 -20
  355. package/dist/schema/axis/boundary/Boundaries.d.ts.map +0 -1
  356. package/dist/schema/axis/boundary/Boundaries.js +0 -31
  357. package/dist/schema/axis/boundary/Boundaries.js.map +0 -1
  358. package/dist/schema/axis/boundary/Boundary.d.ts.map +0 -1
  359. package/dist/schema/axis/boundary/Boundary.js.map +0 -1
  360. package/dist/schema/axis/boundary/BoundaryAxis.d.ts.map +0 -1
  361. package/dist/schema/axis/boundary/BoundaryAxis.js.map +0 -1
  362. package/dist/schema/axis/lifecycle/Clock.d.ts.map +0 -1
  363. package/dist/schema/axis/lifecycle/Clock.js.map +0 -1
  364. package/dist/schema/axis/lifecycle/Generators.d.ts +0 -18
  365. package/dist/schema/axis/lifecycle/Generators.d.ts.map +0 -1
  366. package/dist/schema/axis/lifecycle/Generators.js +0 -38
  367. package/dist/schema/axis/lifecycle/Generators.js.map +0 -1
  368. package/dist/schema/axis/lifecycle/Lifecycle.d.ts.map +0 -1
  369. package/dist/schema/axis/lifecycle/Lifecycle.js.map +0 -1
  370. package/dist/schema/axis/lifecycle/LifecycleAxis.d.ts.map +0 -1
  371. package/dist/schema/axis/lifecycle/LifecycleAxis.js.map +0 -1
  372. package/dist/schema/axis/lifecycle/apply.d.ts +0 -6
  373. package/dist/schema/axis/lifecycle/apply.d.ts.map +0 -1
  374. package/dist/schema/axis/lifecycle/apply.js +0 -34
  375. package/dist/schema/axis/lifecycle/apply.js.map +0 -1
  376. package/dist/schema/axis/role/Relation.d.ts.map +0 -1
  377. package/dist/schema/axis/role/Relation.js.map +0 -1
  378. package/dist/schema/axis/role/Role.d.ts.map +0 -1
  379. package/dist/schema/axis/role/Role.js +0 -40
  380. package/dist/schema/axis/role/Role.js.map +0 -1
  381. package/dist/schema/axis/role/RoleAxis.d.ts.map +0 -1
  382. package/dist/schema/axis/role/RoleAxis.js.map +0 -1
  383. package/dist/schema/axis/shape/Formats.d.ts +0 -8
  384. package/dist/schema/axis/shape/Formats.d.ts.map +0 -1
  385. package/dist/schema/axis/shape/Formats.js +0 -10
  386. package/dist/schema/axis/shape/Formats.js.map +0 -1
  387. package/dist/schema/axis/shape/Shape.d.ts.map +0 -1
  388. package/dist/schema/axis/shape/Shape.js +0 -52
  389. package/dist/schema/axis/shape/Shape.js.map +0 -1
  390. package/dist/schema/fields/Field.d.ts.map +0 -1
  391. package/dist/schema/fields/Field.js +0 -52
  392. package/dist/schema/fields/Field.js.map +0 -1
  393. package/dist/schema/fields/FieldSet.d.ts +0 -28
  394. package/dist/schema/fields/FieldSet.d.ts.map +0 -1
  395. package/dist/schema/fields/FieldSet.js +0 -55
  396. package/dist/schema/fields/FieldSet.js.map +0 -1
  397. package/dist/schema/fields/constraint/FieldGroup.d.ts +0 -21
  398. package/dist/schema/fields/constraint/FieldGroup.d.ts.map +0 -1
  399. package/dist/schema/fields/constraint/FieldGroup.js +0 -65
  400. package/dist/schema/fields/constraint/FieldGroup.js.map +0 -1
  401. package/dist/schema/fields/constraint/Unique.d.ts +0 -4
  402. package/dist/schema/fields/constraint/Unique.d.ts.map +0 -1
  403. package/dist/schema/fields/constraint/Unique.js +0 -4
  404. package/dist/schema/fields/constraint/Unique.js.map +0 -1
  405. package/dist/utils.d.ts.map +0 -1
  406. package/dist/utils.js.map +0 -1
  407. package/src/judge/RowRefusal.ts +0 -17
  408. package/src/judge/options.ts +0 -3
  409. package/src/projection/SchemaOrCard.ts +0 -18
  410. package/src/projection/card/EntityTypeSource.ts +0 -90
  411. package/src/projection/card/FacadeTypeSource.ts +0 -55
  412. package/src/schema/SchemaDefinition.ts +0 -150
  413. package/src/schema/SchemaDerivation.ts +0 -65
  414. package/src/schema/axis/boundary/Boundaries.ts +0 -44
  415. package/src/schema/axis/lifecycle/Generators.ts +0 -46
  416. package/src/schema/axis/lifecycle/apply.ts +0 -39
  417. package/src/schema/axis/role/Role.ts +0 -56
  418. package/src/schema/axis/shape/Formats.ts +0 -22
  419. package/src/schema/fields/FieldSet.ts +0 -63
  420. package/src/schema/fields/constraint/FieldGroup.ts +0 -84
  421. package/src/schema/fields/constraint/Unique.ts +0 -3
  422. /package/dist/{schema/SchemaView.js → SchemaView.js} +0 -0
  423. /package/dist/{schema/axis → axis}/Axis.js +0 -0
  424. /package/dist/{schema/axis → axis}/Meta.d.ts +0 -0
  425. /package/dist/{schema/axis → axis}/Meta.js +0 -0
  426. /package/dist/{schema/axis → axis}/boundary/BoundaryAxis.d.ts +0 -0
  427. /package/dist/{schema/axis → axis}/lifecycle/Lifecycle.d.ts +0 -0
  428. /package/dist/{schema/axis → axis}/lifecycle/Lifecycle.js +0 -0
  429. /package/dist/{schema/axis → axis}/lifecycle/LifecycleAxis.d.ts +0 -0
  430. /package/dist/{utils.d.ts → lib/utils.d.ts} +0 -0
  431. /package/dist/{utils.js → lib/utils.js} +0 -0
  432. /package/src/{schema/axis → axis}/Meta.ts +0 -0
  433. /package/src/{schema/axis → axis}/lifecycle/Lifecycle.ts +0 -0
  434. /package/src/{utils.ts → lib/utils.ts} +0 -0
  435. /package/src/{judge/result.ts → validation.ts} +0 -0
@@ -0,0 +1,257 @@
1
+ import { type Fields } from './field/Field.js';
2
+ import { FieldSet, deduplicated } from './field/FieldSet.js';
3
+ import {
4
+ type CompositeUnique,
5
+ type EntityDeclarations,
6
+ type PreviousNames,
7
+ } from './entity/EntityDeclarations.js';
8
+ import { type EntityAdapters } from './entity/EntityAdapters.js';
9
+ import { EntityAdapterSet } from './entity/EntityAdapterSet.js';
10
+ import { SchemaDerivation } from './SchemaDerivation.js';
11
+ import { type ValidateOptions } from './validator/InputValidator.js';
12
+ import type { SchemaView } from './SchemaView.js';
13
+
14
+ /**
15
+ * What a schema constrains beyond any single field.
16
+ *
17
+ * `unique` is the one member today. It sits under an owner rather than beside `fields`
18
+ * and `opts` because the next rule spanning two fields — a check, an exclusion — is a
19
+ * member here, not an eighth positional argument in a list that has already lost one.
20
+ */
21
+ export interface SchemaConstraints<TFields extends Fields = Fields> {
22
+ readonly unique?: CompositeUnique<TFields>;
23
+ }
24
+
25
+ /**
26
+ * Everything a definition is made of, every member required.
27
+ *
28
+ * A transformation states what it keeps AND what it clears — `previous: undefined` and
29
+ * `anchored: false` are the two a derivation decides, and positionally they were an
30
+ * `undefined` and a `false` a reader had to count arguments to name.
31
+ */
32
+ interface SchemaState {
33
+ fields: Fields;
34
+ adapterSet: EntityAdapterSet;
35
+ opts: ValidateOptions;
36
+ previous: PreviousNames<Fields> | undefined;
37
+ derivation: SchemaDerivation | undefined;
38
+ anchored: boolean;
39
+ constraints: SchemaConstraints;
40
+ }
41
+
42
+ /** The keys a derivation keeps, in the order it keeps them, under the names they take. */
43
+ type Renaming = ReadonlyMap<string, string>;
44
+
45
+ /**
46
+ * Everything a schema IS, apart from being a class whose instances are rows.
47
+ *
48
+ * The members used to be that many statics assigned side by side, and every derivation
49
+ * re-threaded them by hand — which is how one of them came to be dropped from a list
50
+ * without anyone noticing. A transformation here returns a COMPLETE definition or it does
51
+ * not compile, so no gesture can mix the fields of one with the options of another.
52
+ *
53
+ * Internal: it is not exported from the package and never appears on `SchemaConstructor`.
54
+ * A user derives with `Order.pick(…)`, never `Order.definition.pick(…)`.
55
+ */
56
+ export class SchemaDefinition {
57
+ readonly fields: Fields;
58
+ readonly adapterSet: EntityAdapterSet;
59
+ readonly opts: ValidateOptions;
60
+ readonly previous: PreviousNames<Fields> | undefined;
61
+ readonly derivation: SchemaDerivation | undefined;
62
+ readonly anchored: boolean;
63
+ readonly constraints: SchemaConstraints;
64
+
65
+ private constructor(state: SchemaState) {
66
+ this.fields = state.fields;
67
+ this.adapterSet = state.adapterSet;
68
+ this.opts = state.opts;
69
+ this.previous = state.previous;
70
+ this.derivation = state.derivation;
71
+ this.anchored = state.anchored;
72
+ this.constraints = state.constraints;
73
+ }
74
+
75
+ /** Built complete or not at all — no static assigned on the side. */
76
+ static of(declaration: {
77
+ fields: Fields;
78
+ adapters?: EntityAdapters<Fields>;
79
+ opts?: ValidateOptions;
80
+ previous?: PreviousNames<Fields>;
81
+ derivation?: SchemaDerivation;
82
+ anchored?: boolean;
83
+ constraints?: SchemaConstraints;
84
+ }): SchemaDefinition {
85
+ return new SchemaDefinition({
86
+ fields: declaration.fields,
87
+ adapterSet: EntityAdapterSet.of(declaration.adapters),
88
+ opts: declaration.opts ?? {},
89
+ previous: declaration.previous,
90
+ derivation: declaration.derivation,
91
+ anchored: declaration.anchored ?? false,
92
+ constraints: declaration.constraints ?? {},
93
+ });
94
+ }
95
+
96
+ declaring(declarations: EntityDeclarations<Fields>): SchemaDefinition {
97
+ const addressed = EntityAdapterSet.of(declarations.adapters).fieldNames;
98
+ this.assertKnown('declares', [
99
+ ...addressed,
100
+ ...Object.keys(declarations.previous ?? {}),
101
+ ]);
102
+ const declared = FieldSet.declaring(this.fields, declarations.unique);
103
+
104
+ return new SchemaDefinition({
105
+ fields: declared.fields,
106
+ adapterSet: EntityAdapterSet.merged([
107
+ this.adapterSet,
108
+ EntityAdapterSet.of(declarations.adapters),
109
+ ]),
110
+ opts: this.opts,
111
+ previous: declarations.previous ?? this.previous,
112
+ derivation: this.derivation,
113
+ anchored: this.anchored,
114
+ constraints:
115
+ declarations.unique === undefined ? this.constraints : { unique: declared.unique },
116
+ });
117
+ }
118
+
119
+ anchoring(): SchemaDefinition {
120
+ return new SchemaDefinition({
121
+ fields: this.fields,
122
+ adapterSet: this.adapterSet,
123
+ opts: this.opts,
124
+ previous: this.previous,
125
+ derivation: this.derivation,
126
+ anchored: true,
127
+ constraints: this.constraints,
128
+ });
129
+ }
130
+
131
+ pick(keys: readonly string[], root: SchemaView): SchemaDefinition {
132
+ this.assertKnown('pick', keys);
133
+
134
+ return this.renaming(new Map(keys.map((key) => [key, key])), root);
135
+ }
136
+
137
+ omit(keys: readonly string[], root: SchemaView): SchemaDefinition {
138
+ this.assertKnown('omit', keys);
139
+ const kept = Object.keys(this.fields).filter((key) => !keys.includes(key));
140
+
141
+ return this.renaming(new Map(kept.map((key) => [key, key])), root);
142
+ }
143
+
144
+ rename(mapping: Record<string, string>, root: SchemaView): SchemaDefinition {
145
+ this.assertKnown('rename', Object.keys(mapping));
146
+ const here = Object.keys(this.fields).map((key) => [key, mapping[key] ?? key] as const);
147
+
148
+ return this.renaming(new Map(here), root);
149
+ }
150
+
151
+ /**
152
+ * `pick`, `omit` and `rename` are one gesture, and the renaming IS that gesture: the
153
+ * fields it keeps and everything else addressed by field name are both read from it.
154
+ */
155
+ private renaming(kept: Renaming, root: SchemaView): SchemaDefinition {
156
+ const fields: Fields = {};
157
+ for (const [from, to] of kept) {
158
+ const field = this.fields[from];
159
+ if (field) fields[to] = field;
160
+ }
161
+ const nameOf = (key: string) => kept.get(key);
162
+
163
+ return new SchemaDefinition({
164
+ fields,
165
+ adapterSet: this.adapterSet.rename(nameOf),
166
+ opts: this.opts,
167
+ previous: undefined,
168
+ derivation: this.origin(root).rename(nameOf),
169
+ anchored: false,
170
+ constraints: this.constraintsRenamed(nameOf),
171
+ });
172
+ }
173
+
174
+ /** One member gone and the group is gone: it constrained a pair that no longer exists. */
175
+ private constraintsRenamed(
176
+ transform: (key: string) => string | undefined,
177
+ ): SchemaConstraints {
178
+ if (!this.constraints.unique) return this.constraints;
179
+ const kept: string[][] = [];
180
+ for (const group of this.constraints.unique) {
181
+ const renamed = group.map(transform);
182
+ if (renamed.every((key): key is string => key !== undefined)) kept.push(renamed);
183
+ }
184
+
185
+ return { unique: deduplicated(kept) as CompositeUnique<Fields> | undefined };
186
+ }
187
+
188
+ patched(root: SchemaView): SchemaDefinition {
189
+ return new SchemaDefinition({
190
+ fields: { ...this.fields },
191
+ adapterSet: this.adapterSet,
192
+ opts: { ...this.opts, patch: true },
193
+ previous: undefined,
194
+ derivation: this.origin(root),
195
+ anchored: false,
196
+ constraints: this.constraints,
197
+ });
198
+ }
199
+
200
+ /** An added field does not pretend to come from the root, which never declared it. */
201
+ extended(extra: Fields, root: SchemaView): SchemaDefinition {
202
+ return new SchemaDefinition({
203
+ fields: { ...this.fields, ...extra },
204
+ adapterSet: this.adapterSet,
205
+ opts: this.opts,
206
+ previous: undefined,
207
+ derivation: this.origin(root),
208
+ anchored: false,
209
+ constraints: this.constraints,
210
+ });
211
+ }
212
+
213
+ /** Several schemas fold into one, which has no single origin to point at. */
214
+ static merged(views: readonly SchemaView[]): SchemaDefinition {
215
+ const fields: Fields = {};
216
+ let opts: ValidateOptions = {};
217
+ const groups: (readonly string[])[] = [];
218
+ for (const view of views) {
219
+ Object.assign(fields, view.getFields());
220
+ opts = { ...opts, ...view.getOpts() };
221
+ groups.push(...(view.getUnique() ?? []));
222
+ }
223
+
224
+ return new SchemaDefinition({
225
+ fields,
226
+ adapterSet: EntityAdapterSet.merged(
227
+ views.map((view) => EntityAdapterSet.of(view.getAdapters())),
228
+ ),
229
+ opts,
230
+ previous: undefined,
231
+ derivation: undefined,
232
+ anchored: false,
233
+ constraints: { unique: deduplicated(groups) as CompositeUnique<Fields> | undefined },
234
+ });
235
+ }
236
+
237
+ /**
238
+ * So a gesture naming a field that does not exist says so, and lists what there is.
239
+ * FR : pour qu'un geste nommant un champ inexistant le dise, et énumère ce qui existe.
240
+ * `pick('titel')` → `pick(): unknown field \`titel\`. This schema carries id, title, body.`
241
+ */
242
+ private assertKnown(operation: string, keys: readonly string[]): void {
243
+ const strangers = keys.filter((key) => !Object.hasOwn(this.fields, key));
244
+ if (strangers.length === 0) return;
245
+
246
+ throw new Error(
247
+ `${operation}(): unknown field ${strangers.map((s) => `\`${s}\``).join(', ')}. ` +
248
+ `This schema carries ${Object.keys(this.fields).join(', ')}.`,
249
+ );
250
+ }
251
+
252
+ private origin(root: SchemaView): SchemaDerivation {
253
+ if (!this.anchored && this.derivation) return this.derivation;
254
+
255
+ return SchemaDerivation.first(root, this.fields);
256
+ }
257
+ }
@@ -0,0 +1,44 @@
1
+ import { type Fields } from './field/Field.js';
2
+ import type { SchemaView } from './SchemaView.js';
3
+
4
+ /**
5
+ * The origin is the ROOT: `Post.pick(a, b).omit(b)` answers `Post`, never the intermediate.
6
+ */
7
+ export class SchemaDerivation {
8
+ private constructor(
9
+ readonly source: SchemaView,
10
+ readonly nameOf: Readonly<Record<string, string | undefined>>,
11
+ ) {}
12
+
13
+ static first(source: SchemaView, fields: Fields): SchemaDerivation {
14
+ return new SchemaDerivation(
15
+ source,
16
+ Object.fromEntries(Object.keys(fields).map((key) => [key, key])),
17
+ );
18
+ }
19
+
20
+ rename(transform: (key: string) => string | undefined): SchemaDerivation {
21
+ return new SchemaDerivation(
22
+ this.source,
23
+ Object.fromEntries(
24
+ Object.entries(this.nameOf).map(([origin, here]) => [
25
+ origin,
26
+ here === undefined ? undefined : transform(here),
27
+ ]),
28
+ ),
29
+ );
30
+ }
31
+
32
+ get sourceName(): string {
33
+ return this.source.name;
34
+ }
35
+
36
+ /** Whose rows this one borrows, however many cuts away: `Post.pick('t').omit('t')` → `Post`. */
37
+ get anchor(): SchemaView {
38
+ const source = this.source;
39
+
40
+ return source.anchored !== undefined || !source.derivation
41
+ ? source
42
+ : source.derivation.anchor;
43
+ }
44
+ }
@@ -1,15 +1,15 @@
1
- import type { Field, Fields } from './fields/Field.js';
2
- import type { CompositeUnique, PreviousNames } from '../entity/EntityDeclarations.js';
3
- import type { EntityAdapters } from '../entity/EntityAdapters.js';
4
- import type { ValidationResult } from '../judge/result.js';
5
- import type { ValidateOptions } from '../judge/options.js';
1
+ import type { Field, Fields } from './field/Field.js';
2
+ import type { CompositeUnique, PreviousNames } from './entity/EntityDeclarations.js';
3
+ import type { EntityAdapters } from './entity/EntityAdapters.js';
4
+ import type { ValidationResult } from './validation.js';
5
+ import type { ValidateOptions } from './validator/InputValidator.js';
6
6
  import type { SchemaDerivation } from './SchemaDerivation.js';
7
7
 
8
- export type Row<TFields extends Fields> = {
8
+ export type Values<TFields extends Fields> = {
9
9
  [K in keyof TFields]: TFields[K] extends Field<infer T> ? T : never;
10
10
  };
11
11
 
12
- export type PartialRow<TFields extends Fields> = Partial<Row<TFields>>;
12
+ export type PartialValues<TFields extends Fields> = Partial<Values<TFields>>;
13
13
 
14
14
  export interface SchemaView<TFields extends Fields = Fields> {
15
15
  readonly name: string;
@@ -20,8 +20,8 @@ export interface SchemaView<TFields extends Fields = Fields> {
20
20
  /** Does it hold rows of its own? False on a derivation means an answer. */
21
21
  readonly anchored?: boolean;
22
22
  getFields(): TFields;
23
- getAdapters(): EntityAdapters<TFields> | undefined;
23
+ getAdapters(): EntityAdapters<TFields>;
24
24
  getUnique(): CompositeUnique<TFields> | undefined;
25
25
  getOpts(): ValidateOptions;
26
- validate(input: unknown): ValidationResult<Row<TFields>>;
26
+ validate(input: unknown): ValidationResult<Values<TFields>>;
27
27
  }
@@ -1,12 +1,12 @@
1
1
  import { roleAxis } from './role/RoleAxis.js';
2
2
  import { lifecycleAxis } from './lifecycle/LifecycleAxis.js';
3
3
  import { boundaryAxis } from './boundary/BoundaryAxis.js';
4
- import type { ValidationError } from '../../judge/result.js';
4
+ import type { ValidationError } from '../validation.js';
5
5
 
6
6
  export interface Axis<Declared = unknown, Wire = unknown> {
7
7
  readonly slot: 'role' | 'lifecycle' | 'boundary';
8
8
 
9
- judge(value: unknown, errors: ValidationError[]): void;
9
+ validator(value: unknown, errors: ValidationError[]): void;
10
10
 
11
11
  describe(value: Declared, key: string): Wire | undefined;
12
12
 
@@ -0,0 +1,37 @@
1
+ import type { BoundaryRules } from './Boundary.js';
2
+ import { Registry } from '../../lib/Registry.js';
3
+
4
+ export type Decoder = (value: unknown) => { value: unknown } | { error: string };
5
+ export type Encoder = (value: unknown) => unknown;
6
+
7
+ /**
8
+ * `decoders` for a value coming in, `encoders` for one going out, `aliases` for the word
9
+ * that names a pair. Three registries, so a codec is never half declared.
10
+ * FR : `decoders` à l'entrée, `encoders` à la sortie, `aliases` pour le mot qui nomme la paire.
11
+ * `Boundaries.aliases.register('isoDate', { in: { decode: 'isoDate' }, out: { encode: 'isoDate' } })`
12
+ * → a field saying `boundary: 'isoDate'` decodes to a `Date` and leaves as a string
13
+ */
14
+ export const Boundaries = {
15
+ decoders: new Registry<Decoder>(
16
+ 'boundary decoder',
17
+ 'call Boundaries.decoders.register(name, fn)',
18
+ ),
19
+ encoders: new Registry<Encoder>(
20
+ 'boundary encoder',
21
+ 'call Boundaries.encoders.register(name, fn)',
22
+ ),
23
+ aliases: new Registry<BoundaryRules>('boundary alias'),
24
+ };
25
+
26
+ Boundaries.decoders.register('isoDate', (value) => {
27
+ if (value instanceof Date) return { value };
28
+ if (typeof value === 'string') {
29
+ const date = new Date(value);
30
+ return Number.isNaN(date.getTime()) ? { error: 'Invalid date' } : { value: date };
31
+ }
32
+ return { error: 'Expected a date' };
33
+ });
34
+ Boundaries.encoders.register('isoDate', (value) =>
35
+ value instanceof Date ? value.toISOString() : value,
36
+ );
37
+ Boundaries.aliases.register('isoDate', { in: { decode: 'isoDate' }, out: { encode: 'isoDate' } });
@@ -1,7 +1,7 @@
1
1
  import type { Decoder, Encoder } from './Boundaries.js';
2
2
  import { Boundaries } from './Boundaries.js';
3
- import type { Field } from '../../fields/Field.js';
4
- import { Anatomy, type Shape } from '../shape/Shape.js';
3
+ import type { Field } from '../../field/Field.js';
4
+ import { Shapes, type Shape } from '../shape/Shape.js';
5
5
 
6
6
  export interface BoundaryRules {
7
7
  in?: 'closed' | { decode: string };
@@ -29,12 +29,13 @@ export class Boundary implements BoundaryRules {
29
29
  this.encode = codecs?.encode ?? identityEncoder;
30
30
  }
31
31
 
32
+ /** An unknown alias stops here. */
32
33
  static declared(field: Field): Boundary {
33
34
  const ref = field.boundary;
34
35
  if (ref === undefined) return new Boundary();
35
36
  if (typeof ref !== 'string') return new Boundary(ref);
36
37
 
37
- const alias = Boundaries.alias(ref);
38
+ const alias = Boundaries.aliases.find(ref);
38
39
  if (!alias) throw new Error(`Unknown boundary alias: '${ref}'`);
39
40
  return new Boundary(alias);
40
41
  }
@@ -49,19 +50,20 @@ export class Boundary implements BoundaryRules {
49
50
  return new Boundary(rules, {
50
51
  decode:
51
52
  typeof rules.in === 'object'
52
- ? Boundaries.decoder(rules.in.decode)
53
+ ? Boundaries.decoders.resolve(rules.in.decode)
53
54
  : identityDecoder,
54
55
  encode:
55
56
  typeof rules.out === 'object'
56
- ? Boundaries.encoder(rules.out.encode)
57
+ ? Boundaries.encoders.resolve(rules.out.encode)
57
58
  : identityEncoder,
58
59
  });
59
60
  }
60
61
 
62
+ /** `date-time` means a `Date` on both sides, without a word in the entity. */
61
63
  static forShape(shape: Shape | undefined): Boundary {
62
- const base = Anatomy.of(shape).base;
64
+ const base = Shapes.of(shape).base;
63
65
  if (base?.type === 'string' && base.format === 'date-time') {
64
- return new Boundary(Boundaries.alias('isoDate')!);
66
+ return new Boundary(Boundaries.aliases.find('isoDate')!);
65
67
  }
66
68
  return new Boundary();
67
69
  }
@@ -1,12 +1,12 @@
1
1
  import type { Axis } from '../Axis.js';
2
- import { admitWire } from '../../../projection/card/admission.js';
3
- import { isObject } from '../../../utils.js';
2
+ import { admitWire } from '../../projection/card/admission.js';
3
+ import { isObject } from '../../lib/utils.js';
4
4
  import type { BoundaryRef } from './Boundary.js';
5
5
 
6
6
  export const boundaryAxis: Axis<BoundaryRef, BoundaryRef> = {
7
7
  slot: 'boundary',
8
8
 
9
- judge(value, errors) {
9
+ validator(value, errors) {
10
10
  if (typeof value === 'string') return;
11
11
  if (!isObject(value)) {
12
12
  errors.push({
@@ -26,7 +26,7 @@ export const boundaryAxis: Axis<BoundaryRef, BoundaryRef> = {
26
26
 
27
27
  describe: (value) => value,
28
28
  reconstruct: (wire) => {
29
- admitWire(boundaryAxis.judge, wire, 'boundary');
29
+ admitWire(boundaryAxis.validator, wire, 'boundary');
30
30
  return wire;
31
31
  },
32
32
  };
@@ -16,7 +16,7 @@ export class Clock {
16
16
  return this.reading();
17
17
  }
18
18
 
19
- /** Freeze the instant this clock reads. Returns the gesture that restores it. */
19
+ /** One substitution moves time for every stamp in the process at once. */
20
20
  static freeze(at: number | Date): () => void {
21
21
  const previous = this.reading;
22
22
  const instant = at instanceof Date ? at.getTime() : at;
@@ -0,0 +1,29 @@
1
+ import { createId } from '@paralleldrive/cuid2';
2
+
3
+ import { Registry } from '../../lib/Registry.js';
4
+
5
+ export type GeneratorRef = 'cuid2' | 'uuid' | 'nanoid' | (string & {});
6
+
7
+ const NANOID_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
8
+
9
+ function nanoid(): string {
10
+ const bytes = new Uint8Array(21);
11
+ globalThis.crypto.getRandomValues(bytes);
12
+ return Array.from(bytes, (byte) => NANOID_ALPHABET[byte & 63]).join('');
13
+ }
14
+
15
+ /**
16
+ * Who answers a `generate:` name. `cuid2`, `uuid` and `nanoid` are registered like any
17
+ * other, so `Generators.resolve('ulid')` is refused here and lists the three.
18
+ * FR : pour qu'un `generate:` soit répondu par un registre, builtins compris.
19
+ * `Generators.register('ulid', ulid)` → `create: { generate: 'ulid' }` now resolves
20
+ */
21
+ export const Generators = new Registry<() => string>(
22
+ 'generator',
23
+ 'call Generators.register(name, fn)',
24
+ [
25
+ ['cuid2', createId],
26
+ ['uuid', () => globalThis.crypto.randomUUID()],
27
+ ['nanoid', nanoid],
28
+ ],
29
+ );
@@ -1,18 +1,18 @@
1
1
  import type { Axis } from '../Axis.js';
2
- import type { ValidationError } from '../../../judge/result.js';
3
- import { admitWire, oneOfTokens } from '../../../projection/card/admission.js';
4
- import { isObject } from '../../../utils.js';
2
+ import type { ValidationError } from '../../validation.js';
3
+ import { admitWire, oneOfTokens } from '../../projection/card/admission.js';
4
+ import { isObject } from '../../lib/utils.js';
5
5
  import { CREATE_TOKENS, UPDATE_TOKENS, type LifecycleRules } from './Lifecycle.js';
6
6
 
7
7
  export const lifecycleAxis: Axis<LifecycleRules, LifecycleRules> = {
8
8
  slot: 'lifecycle',
9
9
 
10
- judge(value, errors) {
10
+ validator(value, errors) {
11
11
  if (!isObject(value)) {
12
12
  errors.push({ path: 'lifecycle', message: `Expected an object — got ${JSON.stringify(value)}` });
13
13
  return;
14
14
  }
15
- if (value.create !== undefined) judgeCreate(value.create, errors);
15
+ if (value.create !== undefined) validateCreate(value.create, errors);
16
16
  if (value.update !== undefined && !oneOfTokens(value.update, UPDATE_TOKENS)) {
17
17
  errors.push({
18
18
  path: 'lifecycle.update',
@@ -23,12 +23,17 @@ export const lifecycleAxis: Axis<LifecycleRules, LifecycleRules> = {
23
23
 
24
24
  describe: (value) => value,
25
25
  reconstruct: (wire) => {
26
- admitWire(lifecycleAxis.judge, wire, 'lifecycle');
26
+ admitWire(lifecycleAxis.validator, wire, 'lifecycle');
27
27
  return wire;
28
28
  },
29
29
  };
30
30
 
31
- function judgeCreate(rule: unknown, errors: ValidationError[]): void {
31
+ /**
32
+ * So the four legal ways to declare a creation are stated once, and anything else names them.
33
+ * FR : pour que les quatre façons de déclarer une création soient dites une fois.
34
+ * `create: 3` → `Expected 'now', 'optional', { value } or { generate } — got 3`
35
+ */
36
+ function validateCreate(rule: unknown, errors: ValidationError[]): void {
32
37
  if (oneOfTokens(rule, CREATE_TOKENS)) return;
33
38
  if (isObject(rule)) {
34
39
  if ('value' in rule) return;
@@ -0,0 +1,53 @@
1
+ import { Lifecycle } from './Lifecycle.js';
2
+ import { Generators } from './Generators.js';
3
+ import { Clock } from './Clock.js';
4
+ import { type Field, type Fields } from '../../field/Field.js';
5
+
6
+ /**
7
+ * So every storage realizes a create the same way.
8
+ * FR : pour que chaque storage réalise une création de la même façon.
9
+ * `applyCreate({ id: primary(), createdAt: created() }, { title: 'a' })`
10
+ * → `id` generated, `createdAt` stamped, `title` untouched
11
+ */
12
+ export function applyCreate(fields: Fields, input: Record<string, unknown>): Record<string, unknown> {
13
+ const values: Record<string, unknown> = { ...input };
14
+ const instant = Clock.now();
15
+
16
+ for (const [name, field] of Object.entries(fields) as [string, Field][]) {
17
+ if (name in values) continue;
18
+ const rule = Lifecycle.of(field);
19
+
20
+ if (rule.create === 'now') values[name] = new Date(instant);
21
+ else if (rule.literal) values[name] = freshValue(rule.literal.value);
22
+ else if (rule.generator) values[name] = Generators.resolve(rule.generator)();
23
+ }
24
+
25
+ return values;
26
+ }
27
+
28
+ /**
29
+ * So two rows created from one declared default never end up sharing the same object.
30
+ * FR : pour que deux lignes nées d'un même défaut ne partagent pas l'objet.
31
+ * `create: { value: [] }` → each instance gets its own array
32
+ */
33
+ function freshValue(value: unknown): unknown {
34
+ if (value === null || typeof value !== 'object') return value;
35
+ return structuredClone(value);
36
+ }
37
+
38
+ /**
39
+ * So `updated()` is stamped by the storage, and no handler has to remember it.
40
+ * FR : pour qu'`updated()` soit estampé par le storage, pas par le handler.
41
+ * `applyUpdate(fields, { title: 'b' })` → `updatedAt` added, nothing else
42
+ */
43
+ export function applyUpdate(fields: Fields, patch: Record<string, unknown>): Record<string, unknown> {
44
+ const values: Record<string, unknown> = { ...patch };
45
+ const instant = Clock.now();
46
+
47
+ for (const [name, field] of Object.entries(fields) as [string, Field][]) {
48
+ if (Lifecycle.of(field).stampedOnUpdate && !(name in values))
49
+ values[name] = new Date(instant);
50
+ }
51
+
52
+ return values;
53
+ }
@@ -10,22 +10,23 @@ export interface Relation {
10
10
  }
11
11
 
12
12
  /**
13
- * How a relation is built — the one place a target becomes a thunk.
13
+ * How a relation is built — the one place a target becomes `() => Entity`.
14
14
  *
15
15
  * A target arrives as the class or as a function returning it, because a cycle between two
16
16
  * entities can only be written the second way. Recognised by FORM, `getFields` on the
17
- * value: a class answers it, a thunk does not.
17
+ * value: a class answers it, `() => Post` does not.
18
18
  */
19
19
  export const Relation = {
20
+ /** `() => Post` so two entities can point at each other. */
20
21
  one(target: EntityConstructor | (() => EntityConstructor), cascade?: boolean): Relation {
21
- return { to: thunk(target), kind: 'one', onDelete: cascade ? 'cascade' : undefined };
22
+ return { to: normalizeTarget(target), kind: 'one', onDelete: cascade ? 'cascade' : undefined };
22
23
  },
23
24
 
24
25
  many(target: EntityConstructor | (() => EntityConstructor)): Relation {
25
- return { to: thunk(target), kind: 'many' };
26
+ return { to: normalizeTarget(target), kind: 'many' };
26
27
  },
27
28
  };
28
29
 
29
- function thunk<E extends EntityConstructor>(target: E | (() => E)): () => E {
30
+ function normalizeTarget<E extends EntityConstructor>(target: E | (() => E)): () => E {
30
31
  return 'getFields' in target ? () => target as E : (target as () => E);
31
32
  }