@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
@@ -1,11 +1,12 @@
1
- import { EXTENSION_AXES, EXTENSION_SLOTS, type Resolver } from '../../schema/axis/Axis.js';
1
+ import { EXTENSION_AXES, EXTENSION_SLOTS, type Resolver } from '../../axis/Axis.js';
2
2
  import { dequal } from 'dequal';
3
- import { clean, isObject } from '../../utils.js';
4
- import { Field, type Fields } from '../../schema/fields/Field.js';
5
- import { RowJudge } from '../../judge/RowJudge.js';
6
- import { Schema, type SchemaConstructor } from '../../schema/Schema.js';
7
- import type { Row, SchemaView } from '../../schema/SchemaView.js';
8
- import { refuse } from './admission.js';
3
+ import { clean, isObject } from '../../lib/utils.js';
4
+ import { Field, type Fields } from '../../field/Field.js';
5
+ import { deduplicated } from '../../field/FieldSet.js';
6
+ import { InputValidator } from '../../validator/InputValidator.js';
7
+ import { Schema, type SchemaConstructor } from '../../Schema.js';
8
+ import type { Values, SchemaView } from '../../SchemaView.js';
9
+ import { admitPatterns, refuse } from './admission.js';
9
10
  import type {
10
11
  DerivedFrom,
11
12
  FieldDescriptor,
@@ -17,21 +18,23 @@ import type { Change, Diff, DiffOptions, RenameCandidate, TypeSet } from './diff
17
18
  type FieldsOf<T> = { [K in keyof T]-?: Field<T[K]> };
18
19
 
19
20
  /** One portable schema description and every decision made about that description. */
20
- export class Card<T = Row<Fields>> {
21
+ export class Card<T = Values<Fields>> {
21
22
  private constructor(readonly descriptor: SchemaDescriptor) {}
22
23
 
23
24
  static fromSchema<TFields extends Fields>(
24
25
  schema: SchemaView<TFields>,
25
26
  name?: string,
26
- ): Card<Row<TFields>> {
27
+ ): Card<Values<TFields>> {
27
28
  const fields = schema.getFields();
28
- const judge = RowJudge.of(fields);
29
+ const validator = InputValidator.of(fields);
29
30
  const properties: Record<string, FieldDescriptor> = {};
30
31
  const required: string[] = [];
31
32
  for (const [key, field] of Object.entries(fields)) {
32
33
  properties[key] = describeField(field, key);
33
- if (judge.onAbsent(field) === null) required.push(key);
34
+ if (validator.onAbsent(field) === null) required.push(key);
34
35
  }
36
+ for (const group of schema.getUnique() ?? [])
37
+ for (const member of group) carryGroup(properties[member], group);
35
38
 
36
39
  const descriptor: SchemaDescriptor = {
37
40
  type: 'object',
@@ -45,53 +48,56 @@ export class Card<T = Row<Fields>> {
45
48
 
46
49
  const origin = originOf(schema);
47
50
  if (origin) descriptor['x-fougere-derived'] = origin;
48
- return new Card<Row<TFields>>(descriptor);
51
+ return new Card<Values<TFields>>(descriptor);
49
52
  }
50
53
 
51
- static fromDescriptor<T = Row<Fields>>(descriptor: SchemaDescriptor): Card<T> {
54
+ static fromDescriptor<T = Values<Fields>>(descriptor: SchemaDescriptor): Card<T> {
52
55
  return new Card<T>(descriptor);
53
56
  }
54
57
 
55
- /** The root derivation recorded by this card, when its schema was cut from another. */
56
58
  get origin(): DerivedFrom | undefined {
57
59
  return this.descriptor['x-fougere-derived'];
58
60
  }
59
61
 
60
- /**
61
- * Rebuild the live schema. A bundle supplies `resolve` so relation thunks can find the
62
- * other reconstructed cards; a lone card deliberately falls back to a name stand-in.
63
- */
64
62
  toSchema(resolve?: Resolver, name?: string): SchemaConstructor<FieldsOf<T>> {
65
63
  const descriptor = this.descriptor;
66
- const where = name ? `schema '${name}'` : 'this schema';
64
+ const subject = name ? `schema '${name}'` : 'this schema';
67
65
  if (!isObject(descriptor))
68
- refuse(`${where} is not an object`, 'A card carries one JSON Schema per door.');
66
+ refuse(`${subject} is not an object`, 'A card carries one JSON Schema per door.');
69
67
  const version = descriptor['x-fougere-version'];
70
68
  if (version !== 1) {
71
69
  refuse(
72
- `${where} states \`x-fougere-version: ${JSON.stringify(version)}\` and this reader speaks 1`,
70
+ `${subject} states \`x-fougere-version: ${JSON.stringify(version)}\` and this reader speaks 1`,
73
71
  'A producer and its readers move together: re-sync the consumer, or serve the version it speaks.',
74
72
  );
75
73
  }
76
74
  if (!isObject(descriptor.properties)) {
77
75
  refuse(
78
- `${where} carries no \`properties\` object`,
76
+ `${subject} carries no \`properties\` object`,
79
77
  'A schema is its fields; there is nothing to rebuild.',
80
78
  );
81
79
  }
82
80
 
83
81
  const fields: Fields = {};
82
+ const groups: string[][] = [];
84
83
  for (const [key, property] of Object.entries(descriptor.properties)) {
84
+ if (!isObject(property)) {
85
+ refuse(
86
+ `${subject} states \`${key}\` as ${JSON.stringify(property)}`,
87
+ 'A field is one JSON Schema object, and there is nothing to rebuild from that.',
88
+ );
89
+ }
85
90
  fields[key] = reconstructField(property, key, resolve);
91
+ for (const group of property['x-fougere']?.role?.unique ?? [])
92
+ if (group.length > 1) groups.push([...group]);
86
93
  }
87
- const schema = Schema.of({ fields });
94
+ const schema = Schema.of({ fields, constraints: { unique: deduplicated(groups) } });
88
95
  const title = name ?? descriptor.title;
89
96
  if (title)
90
97
  Object.defineProperty(schema, 'name', { value: title, configurable: true });
91
98
  return schema as unknown as SchemaConstructor<FieldsOf<T>>;
92
99
  }
93
100
 
94
- /** What must change to turn this card into `other`. */
95
101
  diff(other: Card, options: DiffOptions = {}): Diff {
96
102
  const changes: Change[] = [];
97
103
  const renamed = options.renamed ?? {};
@@ -155,6 +161,11 @@ export class Card<T = Row<Fields>> {
155
161
  }
156
162
  }
157
163
 
164
+ /**
165
+ * So the three axes write themselves under `x-fougere`, each by its own hand.
166
+ * FR : pour que les trois axes s'écrivent sous `x-fougere`, chacun de sa main.
167
+ * `ref(User)` → `{ role: { relation: { to: 'user', kind: 'one' } } }`
168
+ */
158
169
  function describeExtension(field: Field, key: string): FieldExtension | undefined {
159
170
  const extension: Record<string, unknown> = {};
160
171
  for (const axis of EXTENSION_AXES) {
@@ -167,72 +178,57 @@ function describeExtension(field: Field, key: string): FieldExtension | undefine
167
178
  return Object.keys(extension).length ? (extension as FieldExtension) : undefined;
168
179
  }
169
180
 
181
+ /**
182
+ * So the shape stays plain JSON Schema, and what is ours sits under one key.
183
+ * FR : pour que la forme reste du JSON Schema, ce qui est à nous tenant sous une clé.
184
+ * `text({ max: 200 })` → `{ type: 'string', maxLength: 200 }`
185
+ */
170
186
  function describeField(field: Field, key: string): FieldDescriptor {
171
- const descriptor: FieldDescriptor = {};
172
- for (const [shapeKey, value] of Object.entries(field.shape)) {
173
- if (value !== undefined) (descriptor as Record<string, unknown>)[shapeKey] = value;
174
- }
187
+ // The shape IS JSON Schema, so it lands whole rather than key by key — which is what let
188
+ // it be copied under a computed key into a type that names its own.
189
+ const descriptor: FieldDescriptor = clean({ ...field.shape }) as FieldDescriptor;
175
190
  if (field.meta?.description) descriptor.description = field.meta.description;
176
191
  const extension = describeExtension(field, key);
177
192
  if (extension) descriptor['x-fougere'] = extension;
178
193
  return descriptor;
179
194
  }
180
195
 
196
+ /**
197
+ * So a derived card names its root and what became of each field.
198
+ * FR : pour qu'une carte dérivée nomme sa racine et le sort de chaque champ.
199
+ * `Post.pick('title')` → `{ from: 'Post', nameOf: { title: 'title' } }`
200
+ */
181
201
  function originOf(schema: SchemaView): DerivedFrom | undefined {
182
202
  const { derivation } = schema;
183
203
  if (!derivation) return undefined;
184
- const survived = Object.fromEntries(
185
- Object.entries(derivation.survived).map(([key, value]) => [key, value ?? null]),
204
+ const nameOf = Object.fromEntries(
205
+ Object.entries(derivation.nameOf).map(([key, value]) => [key, value ?? null]),
186
206
  );
187
- return { from: derivation.sourceName, survived };
207
+ return { from: derivation.sourceName, nameOf };
188
208
  }
189
209
 
210
+ /**
211
+ * So a shape read back is the shape that was written, and an unknown type is refused.
212
+ * FR : pour qu'une forme relue soit celle qui a été écrite, un type inconnu étant refusé.
213
+ * `{ type: 'string', maxLength: 200 }` → the same shape a `text({ max: 200 })` states
214
+ */
190
215
  function reconstructShape(property: FieldDescriptor): Field['shape'] | undefined {
191
- const types = Array.isArray(property.type)
192
- ? property.type
193
- : property.type
194
- ? [property.type]
195
- : [];
196
- const base = types.find((type) => type !== 'null');
197
- if (base === undefined) return undefined;
198
- const type = property.type as Field['shape']['type'];
199
- if (base === 'array') {
200
- const items = property.items ? reconstructShape(property.items) : undefined;
201
- return clean({
202
- type,
203
- items,
204
- minItems: property.minItems,
205
- maxItems: property.maxItems,
206
- }) as Field['shape'];
207
- }
208
- switch (base) {
209
- case 'string':
210
- return clean({
211
- type,
212
- minLength: property.minLength,
213
- maxLength: property.maxLength,
214
- pattern: property.pattern,
215
- enum: property.enum,
216
- format: property.format,
217
- }) as Field['shape'];
218
- case 'number':
219
- case 'integer':
220
- return clean({
221
- type,
222
- minimum: property.minimum,
223
- maximum: property.maximum,
224
- }) as Field['shape'];
225
- case 'boolean':
226
- return { type } as Field['shape'];
227
- default:
228
- return clean({
229
- type,
230
- properties: property.properties,
231
- required: property.required,
232
- }) as Field['shape'];
233
- }
216
+ const types = Array.isArray(property.type) ? property.type : property.type ? [property.type] : [];
217
+ if (!types.some((type) => type !== 'null')) return undefined;
218
+
219
+ // `describeField` writes the shape whole, so it is read whole: a list of keywords here
220
+ // would be a second inventory, and the one that forgets a keyword loses it in silence.
221
+ const { 'x-fougere': _extension, description: _description, ...shape } = property;
222
+ if (shape.items) shape.items = reconstructShape(shape.items) as FieldDescriptor;
223
+
224
+ return clean(shape) as Field['shape'];
234
225
  }
235
226
 
227
+ /**
228
+ * So a field read back carries its axes, rebuilt by the axes themselves.
229
+ * FR : pour qu'un champ relu porte ses axes, reconstruits par les axes eux-mêmes.
230
+ * `{ 'x-fougere': { lifecycle: { create: 'now' } } }` → a field stamped at create
231
+ */
236
232
  function reconstructField(
237
233
  property: FieldDescriptor,
238
234
  key: string,
@@ -245,6 +241,7 @@ function reconstructField(
245
241
  'A field always states one.',
246
242
  );
247
243
  }
244
+ admitPatterns(shape, `Field '${key}'`);
248
245
  const extension = property['x-fougere'];
249
246
  const axes: Record<string, unknown> = {};
250
247
  for (const axis of EXTENSION_AXES) {
@@ -261,6 +258,11 @@ function reconstructField(
261
258
  } as never);
262
259
  }
263
260
 
261
+ /**
262
+ * So an axis that changed is one named difference, not a whole field marked dirty.
263
+ * FR : pour qu'un axe modifié soit une différence nommée, pas un champ entier marqué.
264
+ * `{ kind: 'restated', field: 'body', axis: 'boundary', … }`
265
+ */
264
266
  function restated(
265
267
  field: string,
266
268
  before: FieldExtension | undefined,
@@ -278,22 +280,42 @@ function restated(
278
280
  );
279
281
  }
280
282
 
283
+ /**
284
+ * So two shapes are compared without what is not shape getting in the way.
285
+ * FR : pour que deux formes se comparent sans que le reste s'en mêle.
286
+ * `{ type: 'string', description: 'x' }` → `{ type: 'string' }`
287
+ */
281
288
  function shapeOf(descriptor: FieldDescriptor): Record<string, unknown> {
282
- const { 'x-fougere': _extension, ...shape } = descriptor;
289
+ const { 'x-fougere': _extension, description: _description, ...shape } = descriptor;
283
290
  return shape as Record<string, unknown>;
284
291
  }
285
292
 
293
+ /**
294
+ * So `['string','null']` and `['null','string']` are the same type, not a change.
295
+ * FR : pour que `['string','null']` et `['null','string']` soient un même type.
296
+ * `typesOf({ type: ['null', 'string'] })` → `['null', 'string']`
297
+ */
286
298
  function typesOf(descriptor: FieldDescriptor): TypeSet {
287
299
  const type = descriptor.type;
288
300
  if (type === undefined) return [];
289
301
  return (Array.isArray(type) ? [...type] : [type]).sort();
290
302
  }
291
303
 
304
+ /**
305
+ * So a bound that moved is a `reshaped`, told apart from a type that changed.
306
+ * FR : pour qu'une borne déplacée soit un `reshaped`, distinct d'un type changé.
307
+ * `maxLength: 200` → `maxLength: 100` → one `reshaped`, never a `retyped`
308
+ */
292
309
  function boundsOf(descriptor: FieldDescriptor): Record<string, unknown> {
293
310
  const { type: _type, ...rest } = shapeOf(descriptor);
294
311
  return rest;
295
312
  }
296
313
 
314
+ /**
315
+ * So a removal plus an addition of the same shape is a question, never a guess.
316
+ * FR : pour qu'une suppression plus un ajout de même forme soit une question, pas un pari.
317
+ * `body` gone, `content` appeared → `ambiguous: [{ removed: 'body', added: 'content' }]`
318
+ */
297
319
  function candidates(
298
320
  removed: string[],
299
321
  added: string[],
@@ -313,3 +335,15 @@ function candidates(
313
335
  Math.abs(now.indexOf(appeared) - was.indexOf(gone));
314
336
  return found.sort((a, b) => apart(a) - apart(b));
315
337
  }
338
+
339
+ /**
340
+ * So a group spanning several fields reaches a reader that only ever sees one field.
341
+ * FR : pour qu'un groupe couvrant plusieurs champs atteigne un lecteur qui n'en voit qu'un.
342
+ * `carryGroup(properties.listId, ['listId', 'docId'])` → the pair lands under its `role`
343
+ */
344
+ function carryGroup(property: FieldDescriptor | undefined, group: readonly string[]): void {
345
+ if (!property) return;
346
+ const extension = (property['x-fougere'] ??= {}) as { role?: { unique?: string[][] } };
347
+ const role = (extension.role ??= {});
348
+ (role.unique ??= []).push([...group]);
349
+ }
@@ -1,8 +1,8 @@
1
- import type { BoundaryRef } from '../../schema/axis/boundary/Boundary.js';
2
- import type { LifecycleRules } from '../../schema/axis/lifecycle/Lifecycle.js';
3
- import type { Relation } from '../../schema/axis/role/Relation.js';
4
- import type { RoleRules } from '../../schema/axis/role/Role.js';
5
- import type { Shape } from '../../schema/axis/shape/Shape.js';
1
+ import type { BoundaryRef } from '../../axis/boundary/Boundary.js';
2
+ import type { LifecycleRules } from '../../axis/lifecycle/Lifecycle.js';
3
+ import type { Relation } from '../../axis/role/Relation.js';
4
+ import type { RoleRules } from '../../axis/role/Role.js';
5
+ import type { Shape } from '../../axis/shape/Shape.js';
6
6
 
7
7
  type JsonSchemaType =
8
8
  | 'string'
@@ -40,7 +40,7 @@ export type RoleDescriptor = Pick<RoleRules, 'primary' | 'index'> & {
40
40
  export type RelationDescriptor = Pick<Relation, 'kind' | 'onDelete'> & { to: string };
41
41
 
42
42
  /**
43
- * What a derivation was cut from, and what the cut left — `survived` keyed by the
43
+ * What a derivation was cut from, and what the cut left — `nameOf` keyed by the
44
44
  * ORIGIN's field names. Absent on a declaration that derives from nothing.
45
45
  *
46
46
  * A dropped field is `null` and never `undefined`: JSON.stringify erases the second,
@@ -48,7 +48,7 @@ export type RelationDescriptor = Pick<Relation, 'kind' | 'onDelete'> & { to: str
48
48
  */
49
49
  export interface DerivedFrom {
50
50
  from: string;
51
- survived: Record<string, string | null>;
51
+ nameOf: Record<string, string | null>;
52
52
  }
53
53
 
54
54
  export interface SchemaDescriptor {
@@ -1,21 +1,27 @@
1
- import type { ValidationError } from '../../judge/result.js';
1
+ import type { ValidationError } from '../../validation.js';
2
+ import { Shapes } from '../../axis/shape/Shape.js';
2
3
 
3
- /** A card is refused by naming what is wrong AND the remedy — never by a bare throw. */
4
+ /**
5
+ * So a card that cannot be read says what is wrong and what to write instead.
6
+ * FR : pour qu'une carte illisible dise ce qui cloche et quoi écrire.
7
+ * `refuse('role.relation.kind is "maybe"', 'Expected one of one, many.')`
8
+ */
4
9
  export function refuse(what: string, fix: string): never {
5
10
  throw new Error(`This card cannot be read: ${what}.\n ${fix}`);
6
11
  }
7
12
 
8
13
  /**
9
- * A wire value admitted by the axis's OWN judge — legal only where its declared and wire
10
- * forms are the same value, which `describe: v => v` states.
14
+ * So a card's axis passes the same validator as a hand-written one, and no second validator exists.
15
+ * FR : pour qu'un axe d'une carte passe le juge des autres, sans second juge.
16
+ * `{ update: 'maybe' }` on a card → `lifecycle is malformed — lifecycle.update: Expected 'now' or 'forbidden'`
11
17
  */
12
18
  export function admitWire(
13
- judge: (value: unknown, errors: ValidationError[]) => void,
19
+ validator: (value: unknown, errors: ValidationError[]) => void,
14
20
  value: unknown,
15
21
  slot: string,
16
22
  ): void {
17
23
  const errors: ValidationError[] = [];
18
- judge(value, errors);
24
+ validator(value, errors);
19
25
  if (errors.length) {
20
26
  refuse(
21
27
  `${slot} is malformed — ${errors.map((e) => `${e.path}: ${e.message}`).join('; ')}`,
@@ -24,7 +30,32 @@ export function admitWire(
24
30
  }
25
31
  }
26
32
 
33
+ /**
34
+ * So a closed set is checked against the list that declares it, never against a copy.
35
+ * FR : pour qu'un ensemble fermé soit vérifié contre la liste qui le déclare.
36
+ * `oneOfTokens('many', RELATION_KINDS)` → `true`
37
+ */
27
38
  export const oneOfTokens = <T extends readonly string[]>(
28
39
  value: unknown,
29
40
  tokens: T,
30
41
  ): value is T[number] => typeof value === 'string' && (tokens as readonly string[]).includes(value);
42
+
43
+ /**
44
+ * So a `pattern` the engine cannot compile is refused where the card is read, not at the first row.
45
+ * FR : pour qu'un `pattern` incompilable soit refusé à la lecture de la carte, pas au premier row.
46
+ * `{ type: 'string', pattern: '(' }` → Field 'code' states `pattern: "("`, which is not a regular expression
47
+ */
48
+ export function admitPatterns(shape: unknown, subject: string): void {
49
+ for (const pattern of Shapes.patterns(shape)) {
50
+ try {
51
+ // The engine compiles it with `u` and only when a row arrives, so nothing but this
52
+ // reads it early enough to name the card it came from.
53
+ new RegExp(pattern, 'u');
54
+ } catch (error) {
55
+ refuse(
56
+ `${subject} states \`pattern: ${JSON.stringify(pattern)}\`, which is not a regular expression`,
57
+ (error as Error).message,
58
+ );
59
+ }
60
+ }
61
+ }
@@ -1,5 +1,5 @@
1
- import type { BoundaryRef } from '../../schema/axis/boundary/Boundary.js';
2
- import type { LifecycleRules } from '../../schema/axis/lifecycle/Lifecycle.js';
1
+ import type { BoundaryRef } from '../../axis/boundary/Boundary.js';
2
+ import type { LifecycleRules } from '../../axis/lifecycle/Lifecycle.js';
3
3
  import type { FieldDescriptor, RoleDescriptor } from './Descriptor.js';
4
4
 
5
5
  /** One named difference, at one place. Each kind exists because a reader asks for it. */
@@ -0,0 +1,40 @@
1
+ import { Validator } from '@cfworker/json-schema';
2
+ import type { Shape } from '../axis/shape/Shape.js';
3
+ import { isObject } from '../lib/utils.js';
4
+
5
+ /**
6
+ * The format is DATA, not a TypeScript interface: an interface is erased before a JS
7
+ * caller, a config or a card from another language could be measured against it.
8
+ */
9
+ export class AdapterFieldValidator {
10
+ private constructor(private readonly validator: Validator) {}
11
+
12
+ /** Compiled once, at the adapter's own module load. */
13
+ static of(format: Shape): AdapterFieldValidator {
14
+ return new AdapterFieldValidator(new Validator(format as object, '2020-12', true));
15
+ }
16
+
17
+ /** `Post.adapters.sql.body.columnType: Property "postgre" does not match …` */
18
+ assert(entries: unknown, path: string): void {
19
+ if (entries === undefined) return;
20
+
21
+ if (!isObject(entries)) {
22
+ throw new Error(
23
+ `${path}: expected an object keyed by field name, got ${typeof entries}.`,
24
+ );
25
+ }
26
+
27
+ for (const [field, entry] of Object.entries(entries)) {
28
+ const verdict = this.validator.validate(entry);
29
+ if (verdict.valid) continue;
30
+
31
+ // The engine reports outermost first and ends on `False boolean schema`, which names
32
+ // nothing. The last unit above that one is the one carrying the offending key.
33
+ const units = verdict.errors.filter((unit) => unit.keyword !== 'false');
34
+ const failure = units[units.length - 1] ?? verdict.errors[0];
35
+ const nested = (failure?.instanceLocation ?? '#').slice(1).replaceAll('/', '.');
36
+
37
+ throw new Error(`${path}.${field}${nested}: ${failure?.error ?? 'does not match the format'}`);
38
+ }
39
+ }
40
+ }
@@ -1,14 +1,14 @@
1
- import { EXTENSION_AXES } from '../schema/axis/Axis.js';
2
- import { Anatomy } from '../schema/axis/shape/Shape.js';
3
- import type { Field } from '../schema/fields/Field.js';
4
- import { isObject } from '../utils.js';
5
- import type { ValidationError, ValidationResult } from './result.js';
1
+ import { EXTENSION_AXES } from '../axis/Axis.js';
2
+ import { Shapes } from '../axis/shape/Shape.js';
3
+ import type { Field } from '../field/Field.js';
4
+ import { isObject } from '../lib/utils.js';
5
+ import type { ValidationError, ValidationResult } from '../validation.js';
6
6
 
7
- export class FieldJudge {
7
+ export class FieldDeclarationValidator {
8
8
  private constructor(private readonly declaration: unknown) {}
9
9
 
10
- static of(declaration: unknown): FieldJudge {
11
- return new FieldJudge(declaration);
10
+ static of(declaration: unknown): FieldDeclarationValidator {
11
+ return new FieldDeclarationValidator(declaration);
12
12
  }
13
13
 
14
14
  get verdict(): ValidationResult<Field> {
@@ -28,7 +28,7 @@ export class FieldJudge {
28
28
 
29
29
  const errors: ValidationError[] = [];
30
30
 
31
- if (!Anatomy.is(declaration.shape)) {
31
+ if (!Shapes.is(declaration.shape)) {
32
32
  errors.push({
33
33
  path: 'shape',
34
34
  message: `Every field states a shape — got ${JSON.stringify(declaration.shape)}`,
@@ -37,7 +37,7 @@ export class FieldJudge {
37
37
 
38
38
  for (const axis of EXTENSION_AXES) {
39
39
  const declared = declaration[axis.slot];
40
- if (declared !== undefined) axis.judge(declared, errors);
40
+ if (declared !== undefined) axis.validator(declared, errors);
41
41
  }
42
42
 
43
43
  if (declaration.meta !== undefined) {
@@ -1,8 +1,8 @@
1
1
  import { Validator, format as engineFormats } from '@cfworker/json-schema';
2
- import { Formats, type FormatPredicate } from '../schema/axis/shape/Formats.js';
3
- import { Anatomy, type Shape } from '../schema/axis/shape/Shape.js';
4
- import type { Field } from '../schema/fields/Field.js';
5
- import type { Checked } from './result.js';
2
+ import { Formats, type FormatPredicate } from '../axis/shape/Formats.js';
3
+ import { Shapes, type Shape } from '../axis/shape/Shape.js';
4
+ import type { Field } from '../field/Field.js';
5
+ import type { Checked } from '../validation.js';
6
6
 
7
7
  interface ShapePlan {
8
8
  validator: Validator;
@@ -10,18 +10,19 @@ interface ShapePlan {
10
10
  formatName?: string;
11
11
  }
12
12
 
13
- export class ValueJudge {
13
+ export class FieldValueValidator {
14
14
  private static readonly plans = new WeakMap<object, ShapePlan>();
15
15
 
16
16
  private constructor(private readonly field: Field) {}
17
17
 
18
- static of(field: Field): ValueJudge {
19
- return new ValueJudge(field);
18
+ /** The shape is compiled once and reused, not rebuilt per value. */
19
+ static of(field: Field): FieldValueValidator {
20
+ return new FieldValueValidator(field);
20
21
  }
21
22
 
22
- check(value: unknown): Checked {
23
+ validate(value: unknown): Checked {
23
24
  const shape = this.field.shape;
24
- const base = Anatomy.of(shape).base;
25
+ const base = Shapes.of(shape).base;
25
26
  if (value !== null) {
26
27
  if (base?.type === 'object' && !base.properties) return { value };
27
28
  if (
@@ -39,7 +40,7 @@ export class ValueJudge {
39
40
  return { error: 'Expected a number' };
40
41
  }
41
42
  }
42
- const plan = ValueJudge.planFor(shape);
43
+ const plan = FieldValueValidator.planFor(shape);
43
44
  const result = plan.validator.validate(value);
44
45
  if (!result.valid) return { error: result.errors[0]?.error ?? 'Invalid value' };
45
46
  if (plan.custom && typeof value === 'string' && !plan.custom(value)) {
@@ -51,7 +52,7 @@ export class ValueJudge {
51
52
  private static planFor(shape: Shape): ShapePlan {
52
53
  let plan = this.plans.get(shape);
53
54
  if (!plan) {
54
- const base = Anatomy.of(shape).base;
55
+ const base = Shapes.of(shape).base;
55
56
  const formatName = base?.type === 'string' ? base.format : undefined;
56
57
  plan = {
57
58
  validator: new Validator(shape as object, '2020-12', true),
@@ -64,11 +65,11 @@ export class ValueJudge {
64
65
  }
65
66
 
66
67
  private static customFormatOf(name: string): FormatPredicate | undefined {
67
- const custom = Formats.resolve(name);
68
+ const custom = Formats.find(name);
68
69
  if (!custom && !(name in engineFormats)) {
69
70
  throw new Error(
70
71
  `Unknown format: '${name}'. Register it with Formats.register('${name}', …) — ` +
71
- `the engine judges ${Object.keys(engineFormats).length} formats natively and this is not one of them.`,
72
+ `the engine validates ${Object.keys(engineFormats).length} formats natively and this is not one of them.`,
72
73
  );
73
74
  }
74
75
  return custom;
@@ -0,0 +1,7 @@
1
+ export const InputRefusal = {
2
+ notAnObject: 'Expected an object',
3
+ unknownField: 'Unknown field',
4
+ required: 'Required',
5
+ readOnly: 'Read-only',
6
+ immutable: 'Immutable',
7
+ } as const;