@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,52 @@
1
+ import type { EntityConstructor, Relation } from './Relation.js';
2
+
3
+ export interface RoleRules {
4
+ primary?: boolean;
5
+ index?: boolean;
6
+ unique?: boolean;
7
+ relation?: Relation;
8
+ }
9
+
10
+ export class Role implements RoleRules {
11
+ readonly primary?: boolean;
12
+ readonly index?: boolean;
13
+ readonly unique?: boolean;
14
+ readonly relation?: Relation;
15
+
16
+ private constructor(rules: RoleRules = {}) {
17
+ this.primary = rules.primary;
18
+ this.index = rules.index;
19
+ this.unique = rules.unique;
20
+ this.relation = rules.relation;
21
+ }
22
+
23
+ static of(field: { role?: RoleRules }): Role {
24
+ return new Role(field.role);
25
+ }
26
+
27
+ get isPrimary(): boolean {
28
+ return this.primary === true;
29
+ }
30
+
31
+ get isIndexed(): boolean {
32
+ return this.index === true;
33
+ }
34
+
35
+ /** A field unique on its own. A group spanning several belongs to the schema. */
36
+ get isUnique(): boolean {
37
+ return this.unique === true;
38
+ }
39
+
40
+ get isCollection(): boolean {
41
+ return this.relation?.kind === 'many';
42
+ }
43
+
44
+ get isReference(): boolean {
45
+ return this.relation?.kind === 'one';
46
+ }
47
+
48
+ /** Calls `() => Post` so no caller has to. */
49
+ get target(): EntityConstructor | undefined {
50
+ return this.relation?.to();
51
+ }
52
+ }
@@ -1,22 +1,20 @@
1
1
  import type { Axis, Resolver } from '../Axis.js';
2
- import { refuse, oneOfTokens } from '../../../projection/card/admission.js';
3
- import { isObject, lowerFirst } from '../../../utils.js';
4
- import type { ValidationError } from '../../../judge/result.js';
2
+ import { refuse, oneOfTokens } from '../../projection/card/admission.js';
3
+ import { isObject, lowerFirst } from '../../lib/utils.js';
4
+ import type { ValidationError } from '../../validation.js';
5
5
  import { ON_DELETE, RELATION_KINDS, type EntityConstructor, type Relation } from './Relation.js';
6
6
  import { type RoleRules } from './Role.js';
7
- import { FieldGroup } from '../../fields/constraint/FieldGroup.js';
8
- import { Unique } from '../../fields/constraint/Unique.js';
9
- import type { RoleDescriptor } from '../../../projection/card/Descriptor.js';
7
+ import type { RoleDescriptor } from '../../projection/card/Descriptor.js';
10
8
 
11
9
  export const roleAxis: Axis<RoleRules, RoleDescriptor> = {
12
10
  slot: 'role',
13
11
 
14
- judge(value, errors) {
12
+ validator(value, errors) {
15
13
  if (!isObject(value)) {
16
14
  errors.push({ path: 'role', message: `Expected an object — got ${JSON.stringify(value)}` });
17
15
  return;
18
16
  }
19
- for (const flag of ['primary', 'index'] as const) {
17
+ for (const flag of ['primary', 'index', 'unique'] as const) {
20
18
  if (value[flag] !== undefined && typeof value[flag] !== 'boolean') {
21
19
  errors.push({
22
20
  path: `role.${flag}`,
@@ -24,48 +22,33 @@ export const roleAxis: Axis<RoleRules, RoleDescriptor> = {
24
22
  });
25
23
  }
26
24
  }
27
- if (value.rules !== undefined) {
28
- const legal =
29
- Array.isArray(value.rules) &&
30
- value.rules.every(
31
- (rule) =>
32
- rule instanceof FieldGroup ||
33
- (Array.isArray(rule) && rule.every((member) => typeof member === 'string')),
34
- );
35
- if (!legal) {
36
- errors.push({
37
- path: 'role.rules',
38
- message: 'Expected field groups, or the member lists they denote — string[][]',
39
- });
40
- }
41
- }
42
- if (value.relation !== undefined) judgeRelation(value.relation, errors);
25
+ if (value.relation !== undefined) validateRelation(value.relation, errors);
43
26
  },
44
27
 
28
+ /** A card carries the target's NAME: a class cannot cross a process boundary. */
45
29
  describe(role, key) {
46
- const out: Mutable<RoleDescriptor> = {};
47
- if (role.primary) out.primary = true;
48
- const unique = (role.rules ?? []).filter((rule) => rule instanceof Unique);
49
- if (unique.length) out.unique = unique.map((rule) => [...rule.resolvedOn(key).members]);
50
- if (role.index) out.index = true;
30
+ const descriptor: Mutable<RoleDescriptor> = {};
31
+ if (role.primary) descriptor.primary = true;
32
+ if (role.unique) descriptor.unique = [[key]];
33
+ if (role.index) descriptor.index = true;
51
34
  if (role.relation) {
52
35
  const target = role.relation.to() as { name?: string };
53
- out.relation = {
36
+ descriptor.relation = {
54
37
  to: lowerFirst(target.name ?? ''),
55
38
  kind: role.relation.kind,
56
39
  ...(role.relation.onDelete ? { onDelete: role.relation.onDelete } : {}),
57
40
  };
58
41
  }
59
- return Object.keys(out).length ? out : undefined;
42
+ return Object.keys(descriptor).length ? descriptor : undefined;
60
43
  },
61
44
 
62
45
  reconstruct(wire, resolve?: Resolver) {
63
- const out: RoleRules = {};
64
- if (wire.primary) out.primary = true;
65
- if (wire.unique?.length) out.rules = wire.unique.map((group) => new Unique(group));
66
- if (wire.index) out.index = true;
46
+ const rules: RoleRules = {};
47
+ if (wire.primary) rules.primary = true;
48
+ if (wire.unique?.some((group) => group.length === 1)) rules.unique = true;
49
+ if (wire.index) rules.index = true;
67
50
  if (wire.relation) {
68
- // `judge` cannot serve here: it demands a thunk where a card carries a name.
51
+ // `validator` cannot serve here: it demands `() => Post` where a card carries a name.
69
52
  if (!oneOfTokens(wire.relation.kind, RELATION_KINDS)) {
70
53
  refuse(
71
54
  `role.relation.kind is ${JSON.stringify(wire.relation.kind)}`,
@@ -79,17 +62,22 @@ export const roleAxis: Axis<RoleRules, RoleDescriptor> = {
79
62
  );
80
63
  }
81
64
  const name = wire.relation.to;
82
- out.relation = {
65
+ rules.relation = {
83
66
  to: () => (resolve?.(name) ?? ({ name } as unknown)) as EntityConstructor,
84
67
  kind: wire.relation.kind as Relation['kind'],
85
68
  ...(wire.relation.onDelete ? { onDelete: wire.relation.onDelete as Relation['onDelete'] } : {}),
86
69
  } as RoleRules['relation'];
87
70
  }
88
- return out;
71
+ return rules;
89
72
  },
90
73
  };
91
74
 
92
- function judgeRelation(relation: unknown, errors: ValidationError[]): void {
75
+ /**
76
+ * So a relation is validated where `() => Post` is required — a card carries a name.
77
+ * FR : pour qu'une relation soit jugée là où `() => Post` est exigé, contrairement à une carte.
78
+ * `{ to: User, kind: 'one' }` → error `Expected a function returning the target entity, such as () => Post`
79
+ */
80
+ function validateRelation(relation: unknown, errors: ValidationError[]): void {
93
81
  if (!isObject(relation)) {
94
82
  errors.push({ path: 'role.relation', message: `Expected an object — got ${JSON.stringify(relation)}` });
95
83
  return;
@@ -101,7 +89,7 @@ function judgeRelation(relation: unknown, errors: ValidationError[]): void {
101
89
  });
102
90
  }
103
91
  if (typeof relation.to !== 'function') {
104
- errors.push({ path: 'role.relation.to', message: 'Expected a thunk returning the target entity' });
92
+ errors.push({ path: 'role.relation.to', message: 'Expected a function returning the target entity, such as () => Post' });
105
93
  }
106
94
  if (relation.onDelete !== undefined && !oneOfTokens(relation.onDelete, ON_DELETE)) {
107
95
  errors.push({
@@ -0,0 +1,20 @@
1
+ import { Registry } from '../../lib/Registry.js';
2
+
3
+ export type StringFormat =
4
+ | 'date-time'
5
+ | 'date'
6
+ | 'time'
7
+ | 'email'
8
+ | 'uuid'
9
+ | 'uri'
10
+ | (string & {});
11
+
12
+ export type FormatPredicate = (value: string) => boolean;
13
+
14
+ /**
15
+ * String formats the JSON Schema engine does not know. `find` answers `undefined` for
16
+ * `email` or `uuid`, which it validates on its own.
17
+ * FR : les formats de chaîne que le moteur ignore ; `find` rend `undefined` pour les siens.
18
+ * `Formats.register('siret', (v) => /^\d{14}$/.test(v))`
19
+ */
20
+ export const Formats = new Registry<FormatPredicate>('format');
@@ -6,7 +6,7 @@ type Nullably<T extends string> = T | readonly [T, 'null'];
6
6
  interface StringConstraints { minLength?: number; maxLength?: number; pattern?: string; enum?: readonly (string | null)[]; format?: StringFormat }
7
7
  interface NumericConstraints { minimum?: number; maximum?: number }
8
8
  interface ArrayConstraints { items?: Shape; minItems?: number; maxItems?: number }
9
- interface ObjectConstraints { properties?: Record<string, unknown>; required?: readonly string[] }
9
+ interface ObjectConstraints { properties?: Record<string, unknown>; required?: readonly string[]; additionalProperties?: boolean | Shape; propertyNames?: Shape }
10
10
 
11
11
  export type Shape =
12
12
  | ({ type: Nullably<'string'> } & StringConstraints)
@@ -19,8 +19,8 @@ const SHAPE_TYPES = ['string', 'number', 'integer', 'boolean', 'array', 'object'
19
19
 
20
20
  function isShapeImpl(value: unknown): value is Shape {
21
21
  if (typeof value !== 'object' || value === null) return false;
22
- const declared = (value as Shape).type;
23
- const names = Array.isArray(declared) ? declared : [declared];
22
+ const type = (value as Shape).type;
23
+ const names = Array.isArray(type) ? type : [type];
24
24
  return (
25
25
  names.some((name) => (SHAPE_TYPES as readonly unknown[]).includes(name)) &&
26
26
  names.every((name) => name === 'null' || (SHAPE_TYPES as readonly unknown[]).includes(name))
@@ -36,47 +36,74 @@ type BaseShape =
36
36
 
37
37
  function nullableShapeImpl(shape: Shape): Shape {
38
38
  if (Array.isArray(shape.type)) return shape;
39
- const out = { ...shape, type: [shape.type, 'null'] } as unknown as Shape;
40
- if ('enum' in out && out.enum && !out.enum.includes(null)) {
41
- (out as { enum: readonly (string | null)[] }).enum = [...out.enum, null];
39
+ const nullable = { ...shape, type: [shape.type, 'null'] } as unknown as Shape;
40
+ if ('enum' in nullable && nullable.enum && !nullable.enum.includes(null)) {
41
+ (nullable as { enum: readonly (string | null)[] }).enum = [...nullable.enum, null];
42
42
  }
43
- return out;
43
+ return nullable;
44
44
  }
45
45
 
46
- interface ShapeAnatomy {
46
+ interface ShapeParts {
47
47
  base?: BaseShape;
48
48
  nullable: boolean;
49
49
  }
50
50
 
51
- export class Anatomy {
51
+ function collectPatterns(value: unknown, found: string[]): void {
52
+ if (Array.isArray(value)) {
53
+ for (const member of value) collectPatterns(member, found);
54
+
55
+ return;
56
+ }
57
+ if (typeof value !== 'object' || value === null) return;
58
+
59
+ const { pattern } = value as { pattern?: unknown };
60
+ if (typeof pattern === 'string') found.push(pattern);
61
+
62
+ for (const member of Object.values(value)) collectPatterns(member, found);
63
+ }
64
+
65
+ export class Shapes {
52
66
  static is(value: unknown): value is Shape {
53
67
  return isShapeImpl(value);
54
68
  }
55
69
 
70
+ /**
71
+ * Every `pattern` a shape states, the nested ones included — `items`, `properties`.
72
+ *
73
+ * Two readers ask two questions of the same list: the card door asks whether each one
74
+ * compiles, `fougere check` whether each one backtracks. Neither owns the walk.
75
+ */
76
+ static patterns(shape: unknown): string[] {
77
+ const found: string[] = [];
78
+ collectPatterns(shape, found);
79
+
80
+ return found;
81
+ }
82
+
56
83
  static nullable(shape: Shape): Shape {
57
84
  return nullableShapeImpl(shape);
58
85
  }
59
86
 
60
- private static readonly cache = new WeakMap<object, ShapeAnatomy>();
61
- private static readonly none: ShapeAnatomy = { base: undefined, nullable: false };
87
+ private static readonly cache = new WeakMap<object, ShapeParts>();
88
+ private static readonly none: ShapeParts = { base: undefined, nullable: false };
62
89
 
63
- static of(shape?: Shape): ShapeAnatomy {
90
+ static of(shape?: Shape): ShapeParts {
64
91
  if (!shape) return this.none;
65
- let a = this.cache.get(shape);
66
- if (!a) {
92
+ let parts = this.cache.get(shape);
93
+ if (!parts) {
67
94
  if (Array.isArray(shape.type)) {
68
95
  const baseType = shape.type.find((t) => t !== 'null');
69
96
  const base = { ...shape, type: baseType } as BaseShape;
70
97
  if ('enum' in base && base.enum) {
71
98
  (base as { enum: readonly (string | null)[] }).enum = base.enum.filter((v) => v !== null);
72
99
  }
73
- a = { base, nullable: true };
100
+ parts = { base, nullable: true };
74
101
  } else {
75
- a = { base: shape as BaseShape, nullable: false };
102
+ parts = { base: shape as BaseShape, nullable: false };
76
103
  }
77
- this.cache.set(shape, a);
104
+ this.cache.set(shape, parts);
78
105
  }
79
- return a;
106
+ return parts;
80
107
  }
81
108
 
82
109
  static isNullable(shape?: Shape): boolean {
@@ -0,0 +1,81 @@
1
+ import type { Fields } from '../field/Field.js';
2
+ import { isObject } from '../lib/utils.js';
3
+ import type { EntityAdapters } from './EntityAdapters.js';
4
+
5
+ type AdapterConfiguration = Record<string, unknown>;
6
+ type AdapterConfigurations = Record<string, AdapterConfiguration>;
7
+
8
+ export class EntityAdapterSet {
9
+ /**
10
+ * `{ sql: { body: { columnType: { pg: 'tsvector' } } } }`
11
+ */
12
+ private constructor(readonly adapters: EntityAdapters<Fields>) {}
13
+
14
+ /**
15
+ * Stops a malformed declaration from propagating, by checking its two levels.
16
+ * `of({ sql: { body: 3 } })` → passes; `of({ sql: 'oops' })` → throws, naming `adapters.sql`
17
+ */
18
+ static of(adapters?: EntityAdapters<Fields>): EntityAdapterSet {
19
+ if (!adapters) return new EntityAdapterSet({});
20
+
21
+ if (!isObject(adapters)) {
22
+ throw new Error(
23
+ `adapters: expected an object keyed by adapter name, got ${typeof adapters}.`,
24
+ );
25
+ }
26
+
27
+ for (const [adapter, fields] of Object.entries(adapters)) {
28
+ if (!isObject(fields)) {
29
+ throw new Error(
30
+ `adapters.${adapter}: expected an object keyed by field name, got ${typeof fields}. ` +
31
+ `What an adapter is handed is addressed by the field it applies to.`,
32
+ );
33
+ }
34
+ }
35
+
36
+ return new EntityAdapterSet(adapters);
37
+ }
38
+
39
+ /** Folds several into one, a later field entry replacing the earlier. Takes sets only, so */
40
+ static merged(adapterSets: readonly EntityAdapterSet[]): EntityAdapterSet {
41
+ const configurations: AdapterConfigurations = {};
42
+
43
+ for (const adapterSet of adapterSets)
44
+ for (const [adapter, configuration] of adapterSet.entries)
45
+ configurations[adapter] = { ...configurations[adapter], ...configuration };
46
+
47
+ return new EntityAdapterSet(configurations);
48
+ }
49
+
50
+ private get entries(): [string, AdapterConfiguration][] {
51
+ return Object.entries(this.adapters);
52
+ }
53
+
54
+ /** Collects every field addressed, so a declaration aimed at a missing field is caught. */
55
+ get fieldNames(): string[] {
56
+ return [
57
+ ...new Set(this.entries.flatMap(([, configuration]) => Object.keys(configuration))),
58
+ ];
59
+ }
60
+
61
+ /** Follows a derivation — `pick`, `omit` and `rename` are one gesture: what remains, and */
62
+ rename(transform: (key: string) => string | undefined): EntityAdapterSet {
63
+ const renamed: AdapterConfigurations = {};
64
+
65
+ for (const [adapter, configuration] of this.entries) {
66
+ const mapped: AdapterConfiguration = {};
67
+
68
+ for (const [key, entry] of Object.entries(configuration)) {
69
+ const newName = transform(key);
70
+
71
+ if (newName !== undefined) mapped[newName] = entry;
72
+ }
73
+
74
+ // Drop an adapter left with no field. `Post.pick('id')` would otherwise answer
75
+ // `{ sql: {} }` — a line the entity never wrote.
76
+ if (Object.keys(mapped).length) renamed[adapter] = mapped;
77
+ }
78
+
79
+ return new EntityAdapterSet(renamed);
80
+ }
81
+ }
@@ -1,100 +1,8 @@
1
- import type { FieldName, Fields } from '../schema/fields/Field.js';
2
- import { isObject } from '../utils.js';
1
+ import type { FieldName, Fields } from '../field/Field.js';
3
2
 
4
3
  // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-object-type
5
4
  export interface FougereEntityAdapters<K extends string> {}
6
5
 
7
- export type EntityAdapters<TFields extends Fields> = Readonly<Partial<FougereEntityAdapters<FieldName<TFields>>>>;
8
-
9
- /** What `cut` REQUIRES of an augmentation, and the open registry cannot state: addressed by field. */
10
- type FieldEntries = Record<FieldName<Fields>, unknown>;
11
-
12
- type AdapterEntries = Record<string, FieldEntries>;
13
-
14
- /**
15
- * What one schema states per adapter: an adapter name, a field name, then that adapter's own value.
16
- */
17
- export class EntityAdapterSet {
18
- private constructor(private readonly byAdapter: AdapterEntries) {}
19
-
20
- static of(declared: EntityAdapters<Fields> | undefined): EntityAdapterSet | undefined {
21
- if (declared === undefined) return undefined;
22
-
23
- if (!isObject(declared)) {
24
- throw new Error(
25
- `adapters: expected an object keyed by adapter name, got ${typeof declared}.`,
26
- );
27
- }
28
-
29
- const byAdapter: AdapterEntries = {};
30
-
31
- for (const [adapter, perField] of Object.entries(declared as AdapterEntries)) {
32
- if (perField === undefined) continue;
33
-
34
- if (!isObject(perField)) {
35
- throw new Error(
36
- `adapters.${adapter}: expected an object keyed by field name, got ${typeof perField}. ` +
37
- `What an adapter is handed is addressed by the field it applies to.`,
38
- );
39
- }
40
-
41
- if (Object.keys(perField).length) byAdapter[adapter] = perField;
42
- }
43
-
44
- return EntityAdapterSet.made(byAdapter);
45
- }
46
-
47
- /** Several schemas folded into one set; a later source wins, per adapter and per field. */
48
- static merged(sources: readonly (EntityAdapters<Fields> | undefined)[]): EntityAdapterSet | undefined {
49
- const out: AdapterEntries = {};
50
-
51
- for (const source of sources) {
52
- const set = EntityAdapterSet.of(source);
53
- if (!set) continue;
54
-
55
- for (const [adapter, perField] of Object.entries(set.byAdapter)) {
56
- out[adapter] = { ...out[adapter], ...perField };
57
- }
58
- }
59
-
60
- return EntityAdapterSet.made(out);
61
- }
62
-
63
- /** Every field name these entries address — what a caller checks against its own shape. */
64
- get fieldNames(): string[] {
65
- return [...new Set(Object.values(this.byAdapter).flatMap((perField) => Object.keys(perField)))];
66
- }
67
-
68
- /** The plain object, which is what a reader outside this package receives. */
69
- get stated(): EntityAdapters<Fields> {
70
- return this.byAdapter as EntityAdapters<Fields>;
71
- }
72
-
73
- /**
74
- * The entries whose field survives a cut, re-addressed by that field's new name.
75
- *
76
- * The adapter name is not a field and does not move; only the level below it does. An
77
- * entry left on the old name is not an error anywhere downstream — `adapter/sql` looks
78
- * it up by the field it is iterating and simply finds nothing.
79
- */
80
- cut(survives: (key: string) => string | undefined): EntityAdapterSet | undefined {
81
- const out: AdapterEntries = {};
82
-
83
- for (const [adapter, perField] of Object.entries(this.byAdapter)) {
84
- const mapped: FieldEntries = {};
85
-
86
- for (const [key, entry] of Object.entries(perField)) {
87
- const next = survives(key);
88
- if (next !== undefined) mapped[next] = entry;
89
- }
90
-
91
- if (Object.keys(mapped).length) out[adapter] = mapped;
92
- }
93
-
94
- return EntityAdapterSet.made(out);
95
- }
96
-
97
- private static made(byAdapter: AdapterEntries): EntityAdapterSet | undefined {
98
- return Object.keys(byAdapter).length ? new EntityAdapterSet(byAdapter) : undefined;
99
- }
100
- }
6
+ export type EntityAdapters<TFields extends Fields> = Readonly<
7
+ Partial<FougereEntityAdapters<FieldName<TFields>>>
8
+ >;
@@ -1,4 +1,4 @@
1
- import type { FieldName, Fields } from '../schema/fields/Field.js';
1
+ import type { FieldName, Fields } from '../field/Field.js';
2
2
  import type { EntityAdapters } from './EntityAdapters.js';
3
3
 
4
4
  // Ex: [['title', 'name'], ['id']]
package/src/entity.ts CHANGED
@@ -1,7 +1,12 @@
1
- import { type Fields } from './schema/fields/Field.js';
1
+ import { type Fields } from './field/Field.js';
2
2
  import { type EntityDeclarations } from './entity/EntityDeclarations.js';
3
- import { Schema, type SchemaConstructor } from './schema/Schema.js';
3
+ import { Schema, type SchemaConstructor } from './Schema.js';
4
4
 
5
+ /**
6
+ * So the whole framework starts from one call: fields, and what they say about themselves.
7
+ * FR : pour que tout parte d'un appel : les champs, et ce qu'ils disent d'eux-mêmes.
8
+ * `class Post extends entity({ id: primary(), title: text() }, { unique: [['title']] }) {}`
9
+ */
5
10
  export function entity<TFields extends Fields>(
6
11
  fields: TFields,
7
12
  declarations: EntityDeclarations<TFields> = {},
@@ -1,19 +1,17 @@
1
1
  import type { Shape } from '../axis/shape/Shape.js';
2
- import { Role, type RoleRules } from '../axis/role/Role.js';
2
+ import type { RoleRules } from '../axis/role/Role.js';
3
3
  import type { LifecycleRules } from '../axis/lifecycle/Lifecycle.js';
4
4
  import type { BoundaryRef } from '../axis/boundary/Boundary.js';
5
5
  import type { Meta } from '../axis/Meta.js';
6
6
  import type { Axis } from '../axis/Axis.js';
7
- import { FieldJudge } from '../../judge/FieldJudge.js';
8
- import { ValueJudge } from '../../judge/ValueJudge.js';
7
+ import { FieldDeclarationValidator } from '../validator/FieldDeclarationValidator.js';
8
+ import { FieldValueValidator } from '../validator/FieldValueValidator.js';
9
9
 
10
10
  export type Fields = Record<string, Field>;
11
11
 
12
- /** A key of a field set — the name a declaration addresses a field by. */
13
12
  export type FieldName<TFields extends Fields> = Extract<keyof TFields, string>;
14
13
 
15
- /** The carrier, the three extension axes, the annotation — the five the judge reads. */
16
- export type FieldDeclaration = Pick<Field, 'shape' | Axis['slot'] | 'meta'>;
14
+ type FieldDeclaration = Pick<Field, 'shape' | Axis['slot'] | 'meta'>;
17
15
 
18
16
  export class Field<T = unknown> {
19
17
  readonly shape: Shape;
@@ -25,7 +23,7 @@ export class Field<T = unknown> {
25
23
  declare readonly _type?: T;
26
24
 
27
25
  constructor(init: FieldDeclaration, key?: string) {
28
- const verdict = FieldJudge.of(init).verdict;
26
+ const verdict = FieldDeclarationValidator.of(init).verdict;
29
27
 
30
28
  if (!verdict.success) {
31
29
  throw new Error(
@@ -35,14 +33,14 @@ export class Field<T = unknown> {
35
33
  }
36
34
 
37
35
  this.shape = init.shape;
38
- this.role = Role.resolvedOn(init.role, key);
36
+ this.role = init.role;
39
37
  this.lifecycle = init.lifecycle;
40
38
  this.boundary = init.boundary;
41
39
  this.meta = init.meta;
42
40
 
43
41
  const create = this.lifecycle?.create;
44
42
  if (typeof create === 'object' && create !== null && 'value' in create) {
45
- const checked = ValueJudge.of(this).check(create.value);
43
+ const checked = FieldValueValidator.of(this).validate(create.value);
46
44
  if ('error' in checked)
47
45
  throw new Error(
48
46
  `${key ? `Field '${key}': ` : ''}the declared default ${JSON.stringify(create.value)} ` +
@@ -52,28 +50,10 @@ export class Field<T = unknown> {
52
50
  }
53
51
 
54
52
  static is(value: unknown): value is Field {
55
- return FieldJudge.of(value).verdict.success;
53
+ return FieldDeclarationValidator.of(value).verdict.success;
56
54
  }
57
55
 
58
56
  with<U = T>(overrides: Partial<FieldDeclaration>): Field<U> {
59
57
  return new Field<U>({ ...this, ...overrides });
60
58
  }
61
-
62
- rename(map: (key: string) => string | undefined): Field<T> {
63
- const rules = this.role?.rules;
64
- if (!rules?.length) return this;
65
-
66
- const carried = rules
67
- .map((group) => group.rename(map))
68
- .filter((group) => group !== null);
69
- const unchanged =
70
- carried.length === rules.length &&
71
- carried.every((group, i) => group.equals(rules[i]!));
72
- if (unchanged) return this;
73
-
74
- const { rules: _dropped, ...rest } = this.role!;
75
- return this.with({
76
- role: carried.length ? { ...rest, rules: carried } : rest,
77
- });
78
- }
79
59
  }
@@ -0,0 +1,75 @@
1
+ import { Role } from '../axis/role/Role.js';
2
+ import type { CompositeUnique } from '../entity/EntityDeclarations.js';
3
+ import { Field, type FieldName, type Fields } from './Field.js';
4
+
5
+ export class FieldSet<TFields extends Fields = Fields> {
6
+ private constructor(private readonly fields: TFields) {}
7
+
8
+ static of<TFields extends Fields>(fields: TFields): FieldSet<TFields> {
9
+ return new FieldSet(fields);
10
+ }
11
+
12
+ /**
13
+ * So a declared unique lands where it belongs: on the field, or on the schema.
14
+ * FR : pour qu'une unicité déclarée atterrisse sur le champ ou sur le schéma.
15
+ * `declaring(fields, [['email'], ['listId', 'docId']])`
16
+ * → `email` carries `role.unique`, the pair becomes a schema constraint
17
+ */
18
+ static declaring<TFields extends Fields>(
19
+ declared: TFields,
20
+ unique?: CompositeUnique<TFields>,
21
+ ): { fields: TFields; unique: CompositeUnique<TFields> | undefined } {
22
+ const fields: Fields = {};
23
+ for (const [key, field] of Object.entries(declared))
24
+ fields[key] = new Field(field, key);
25
+
26
+ const composite: string[][] = [];
27
+ for (const group of unique ?? []) {
28
+ const missing = group.filter((key) => !Object.hasOwn(fields, key));
29
+ if (missing.length)
30
+ throw new Error(
31
+ `unique: [${group.join(', ')}] names ` +
32
+ `${missing.map((key) => `'${key}'`).join(', ')}, which the entity does not declare.`,
33
+ );
34
+
35
+ if (group.length === 1) {
36
+ const key = group[0]!;
37
+ fields[key] = fields[key]!.with({ role: { ...fields[key]!.role, unique: true } });
38
+ continue;
39
+ }
40
+ composite.push([...group]);
41
+ }
42
+
43
+ return {
44
+ fields: fields as TFields,
45
+ unique: deduplicated(composite) as CompositeUnique<TFields> | undefined,
46
+ };
47
+ }
48
+
49
+ /** A second `primary` is refused, naming both, rather than the first winning silently. */
50
+ get primary(): FieldName<TFields> | undefined {
51
+ const primaries = Object.entries(this.fields)
52
+ .filter(([, field]) => Role.of(field).isPrimary)
53
+ .map(([name]) => name);
54
+
55
+ if (primaries.length > 1) {
56
+ throw new Error(
57
+ `FieldSet.primary: ${primaries.map((name) => JSON.stringify(name)).join(', ')} all declare ` +
58
+ '`primary`; a field set can have only one primary field.',
59
+ );
60
+ }
61
+
62
+ return primaries[0] as FieldName<TFields> | undefined;
63
+ }
64
+
65
+ }
66
+
67
+ /** The order is part of a group: `['a','b']` and `['b','a']` are two constraints. */
68
+ export function deduplicated(
69
+ groups: readonly (readonly string[])[],
70
+ ): readonly (readonly string[])[] | undefined {
71
+ const seen = new Map<string, readonly string[]>();
72
+ for (const group of groups) seen.set(JSON.stringify(group), group);
73
+
74
+ return seen.size ? [...seen.values()] : undefined;
75
+ }