@fougere/schema 0.6.0-alpha.0 → 0.7.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.
- package/README.md +5 -4
- package/dist/{schema/Schema.d.ts → Schema.d.ts} +17 -27
- package/dist/Schema.d.ts.map +1 -0
- package/dist/{schema/Schema.js → Schema.js} +21 -61
- package/dist/Schema.js.map +1 -0
- package/dist/SchemaDefinition.d.ts +73 -0
- package/dist/SchemaDefinition.d.ts.map +1 -0
- package/dist/SchemaDefinition.js +184 -0
- package/dist/SchemaDefinition.js.map +1 -0
- package/dist/SchemaDerivation.d.ts +16 -0
- package/dist/SchemaDerivation.d.ts.map +1 -0
- package/dist/SchemaDerivation.js +31 -0
- package/dist/SchemaDerivation.js.map +1 -0
- package/dist/{schema/SchemaView.d.ts → SchemaView.d.ts} +9 -9
- package/dist/SchemaView.d.ts.map +1 -0
- package/dist/{schema/SchemaView.js.map → SchemaView.js.map} +1 -1
- package/dist/{schema/axis → axis}/Axis.d.ts +2 -2
- package/dist/axis/Axis.d.ts.map +1 -0
- package/dist/axis/Axis.js.map +1 -0
- package/dist/axis/Meta.d.ts.map +1 -0
- package/dist/{schema/axis → axis}/Meta.js.map +1 -1
- package/dist/axis/boundary/Boundaries.d.ts +21 -0
- package/dist/axis/boundary/Boundaries.d.ts.map +1 -0
- package/dist/axis/boundary/Boundaries.js +25 -0
- package/dist/axis/boundary/Boundaries.js.map +1 -0
- package/dist/{schema/axis → axis}/boundary/Boundary.d.ts +3 -1
- package/dist/axis/boundary/Boundary.d.ts.map +1 -0
- package/dist/{schema/axis → axis}/boundary/Boundary.js +8 -6
- package/dist/axis/boundary/Boundary.js.map +1 -0
- package/dist/axis/boundary/BoundaryAxis.d.ts.map +1 -0
- package/dist/{schema/axis → axis}/boundary/BoundaryAxis.js +4 -4
- package/dist/axis/boundary/BoundaryAxis.js.map +1 -0
- package/dist/{schema/axis → axis}/lifecycle/Clock.d.ts +1 -1
- package/dist/axis/lifecycle/Clock.d.ts.map +1 -0
- package/dist/{schema/axis → axis}/lifecycle/Clock.js +1 -1
- package/dist/axis/lifecycle/Clock.js.map +1 -0
- package/dist/axis/lifecycle/Generators.d.ts +10 -0
- package/dist/axis/lifecycle/Generators.d.ts.map +1 -0
- package/dist/axis/lifecycle/Generators.js +20 -0
- package/dist/axis/lifecycle/Generators.js.map +1 -0
- package/dist/axis/lifecycle/Lifecycle.d.ts.map +1 -0
- package/dist/axis/lifecycle/Lifecycle.js.map +1 -0
- package/dist/axis/lifecycle/LifecycleAxis.d.ts.map +1 -0
- package/dist/{schema/axis → axis}/lifecycle/LifecycleAxis.js +11 -6
- package/dist/axis/lifecycle/LifecycleAxis.js.map +1 -0
- package/dist/axis/lifecycle/apply.d.ts +15 -0
- package/dist/axis/lifecycle/apply.d.ts.map +1 -0
- package/dist/axis/lifecycle/apply.js +50 -0
- package/dist/axis/lifecycle/apply.js.map +1 -0
- package/dist/{schema/axis → axis}/role/Relation.d.ts +3 -2
- package/dist/axis/role/Relation.d.ts.map +1 -0
- package/dist/{schema/axis → axis}/role/Relation.js +6 -5
- package/dist/axis/role/Relation.js.map +1 -0
- package/dist/{schema/axis → axis}/role/Role.d.ts +6 -6
- package/dist/axis/role/Role.d.ts.map +1 -0
- package/dist/axis/role/Role.js +36 -0
- package/dist/axis/role/Role.js.map +1 -0
- package/dist/{schema/axis → axis}/role/RoleAxis.d.ts +1 -1
- package/dist/axis/role/RoleAxis.d.ts.map +1 -0
- package/dist/{schema/axis → axis}/role/RoleAxis.js +28 -36
- package/dist/axis/role/RoleAxis.js.map +1 -0
- package/dist/axis/shape/Formats.d.ts +11 -0
- package/dist/axis/shape/Formats.d.ts.map +1 -0
- package/dist/axis/shape/Formats.js +9 -0
- package/dist/axis/shape/Formats.js.map +1 -0
- package/dist/{schema/axis → axis}/shape/Shape.d.ts +5 -3
- package/dist/axis/shape/Shape.d.ts.map +1 -0
- package/dist/{schema/axis → axis}/shape/Shape.js +13 -13
- package/dist/axis/shape/Shape.js.map +1 -0
- package/dist/entity/EntityAdapterSet.d.ts +22 -0
- package/dist/entity/EntityAdapterSet.d.ts.map +1 -0
- package/dist/entity/EntityAdapterSet.js +63 -0
- package/dist/entity/EntityAdapterSet.js.map +1 -0
- package/dist/entity/EntityAdapters.d.ts +1 -24
- package/dist/entity/EntityAdapters.d.ts.map +1 -1
- package/dist/entity/EntityAdapters.js +1 -74
- package/dist/entity/EntityAdapters.js.map +1 -1
- package/dist/entity/EntityDeclarations.d.ts +1 -1
- package/dist/entity/EntityDeclarations.d.ts.map +1 -1
- package/dist/entity.d.ts +7 -2
- package/dist/entity.d.ts.map +1 -1
- package/dist/entity.js +6 -1
- package/dist/entity.js.map +1 -1
- package/dist/{schema/fields → field}/Field.d.ts +2 -3
- package/dist/field/Field.d.ts.map +1 -0
- package/dist/field/Field.js +35 -0
- package/dist/field/Field.js.map +1 -0
- package/dist/field/FieldSet.d.ts +22 -0
- package/dist/field/FieldSet.d.ts.map +1 -0
- package/dist/field/FieldSet.js +58 -0
- package/dist/field/FieldSet.js.map +1 -0
- package/dist/index.d.ts +27 -30
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -23
- package/dist/index.js.map +1 -1
- package/dist/lib/Registry.d.ts +12 -0
- package/dist/lib/Registry.d.ts.map +1 -0
- package/dist/lib/Registry.js +29 -0
- package/dist/lib/Registry.js.map +1 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/projection/Cases.d.ts +9 -20
- package/dist/projection/Cases.d.ts.map +1 -1
- package/dist/projection/Cases.js +44 -39
- package/dist/projection/Cases.js.map +1 -1
- package/dist/projection/Visibility.d.ts +2 -1
- package/dist/projection/Visibility.d.ts.map +1 -1
- package/dist/projection/Visibility.js +4 -3
- package/dist/projection/Visibility.js.map +1 -1
- package/dist/projection/card/Bundle.d.ts +1 -1
- package/dist/projection/card/Bundle.d.ts.map +1 -1
- package/dist/projection/card/Bundle.js +7 -7
- package/dist/projection/card/Bundle.js.map +1 -1
- package/dist/projection/card/Card.d.ts +7 -13
- package/dist/projection/card/Card.d.ts.map +1 -1
- package/dist/projection/card/Card.js +96 -69
- package/dist/projection/card/Card.js.map +1 -1
- package/dist/projection/card/Descriptor.d.ts +7 -7
- package/dist/projection/card/Descriptor.d.ts.map +1 -1
- package/dist/projection/card/admission.d.ts +15 -5
- package/dist/projection/card/admission.d.ts.map +1 -1
- package/dist/projection/card/admission.js +15 -5
- package/dist/projection/card/admission.js.map +1 -1
- package/dist/projection/card/diff.d.ts +2 -2
- package/dist/projection/card/diff.d.ts.map +1 -1
- package/dist/{judge/result.d.ts → validation.d.ts} +1 -1
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +2 -0
- package/dist/validation.js.map +1 -0
- package/dist/validator/AdapterFieldValidator.d.ts +14 -0
- package/dist/validator/AdapterFieldValidator.d.ts.map +1 -0
- package/dist/validator/AdapterFieldValidator.js +36 -0
- package/dist/validator/AdapterFieldValidator.js.map +1 -0
- package/dist/validator/FieldDeclarationValidator.d.ts +9 -0
- package/dist/validator/FieldDeclarationValidator.d.ts.map +1 -0
- package/dist/{judge/FieldJudge.js → validator/FieldDeclarationValidator.js} +8 -8
- package/dist/validator/FieldDeclarationValidator.js.map +1 -0
- package/dist/validator/FieldValueValidator.d.ts +13 -0
- package/dist/validator/FieldValueValidator.d.ts.map +1 -0
- package/dist/{judge/ValueJudge.js → validator/FieldValueValidator.js} +12 -11
- package/dist/validator/FieldValueValidator.js.map +1 -0
- package/dist/{judge/RowRefusal.d.ts → validator/InputRefusal.d.ts} +3 -4
- package/dist/validator/InputRefusal.d.ts.map +1 -0
- package/dist/{judge/RowRefusal.js → validator/InputRefusal.js} +3 -3
- package/dist/validator/InputRefusal.js.map +1 -0
- package/dist/validator/InputValidator.d.ts +15 -0
- package/dist/validator/InputValidator.d.ts.map +1 -0
- package/dist/{judge/RowJudge.js → validator/InputValidator.js} +24 -20
- package/dist/validator/InputValidator.js.map +1 -0
- package/dist/vocabulary/bool.d.ts +6 -1
- package/dist/vocabulary/bool.d.ts.map +1 -1
- package/dist/vocabulary/bool.js +6 -1
- package/dist/vocabulary/bool.js.map +1 -1
- package/dist/vocabulary/created.d.ts +6 -1
- package/dist/vocabulary/created.d.ts.map +1 -1
- package/dist/vocabulary/created.js +5 -0
- package/dist/vocabulary/created.js.map +1 -1
- package/dist/vocabulary/date.d.ts +6 -1
- package/dist/vocabulary/date.d.ts.map +1 -1
- package/dist/vocabulary/date.js +6 -1
- package/dist/vocabulary/date.js.map +1 -1
- package/dist/vocabulary/email.d.ts +6 -1
- package/dist/vocabulary/email.d.ts.map +1 -1
- package/dist/vocabulary/email.js +5 -0
- package/dist/vocabulary/email.js.map +1 -1
- package/dist/vocabulary/immutable.d.ts +6 -1
- package/dist/vocabulary/immutable.d.ts.map +1 -1
- package/dist/vocabulary/immutable.js +5 -0
- package/dist/vocabulary/immutable.js.map +1 -1
- package/dist/vocabulary/indexed.d.ts +6 -1
- package/dist/vocabulary/indexed.d.ts.map +1 -1
- package/dist/vocabulary/indexed.js +5 -0
- package/dist/vocabulary/indexed.js.map +1 -1
- package/dist/vocabulary/json.d.ts +2 -2
- package/dist/vocabulary/json.d.ts.map +1 -1
- package/dist/vocabulary/json.js +9 -4
- package/dist/vocabulary/json.js.map +1 -1
- package/dist/vocabulary/list.d.ts +6 -1
- package/dist/vocabulary/list.d.ts.map +1 -1
- package/dist/vocabulary/list.js +6 -1
- package/dist/vocabulary/list.js.map +1 -1
- package/dist/vocabulary/many.d.ts +7 -2
- package/dist/vocabulary/many.d.ts.map +1 -1
- package/dist/vocabulary/many.js +7 -2
- package/dist/vocabulary/many.js.map +1 -1
- package/dist/vocabulary/nullable.d.ts +6 -1
- package/dist/vocabulary/nullable.d.ts.map +1 -1
- package/dist/vocabulary/nullable.js +7 -2
- package/dist/vocabulary/nullable.js.map +1 -1
- package/dist/vocabulary/number.d.ts +6 -1
- package/dist/vocabulary/number.d.ts.map +1 -1
- package/dist/vocabulary/number.js +6 -1
- package/dist/vocabulary/number.js.map +1 -1
- package/dist/vocabulary/oneOf.d.ts +1 -1
- package/dist/vocabulary/oneOf.d.ts.map +1 -1
- package/dist/vocabulary/oneOf.js +6 -1
- package/dist/vocabulary/oneOf.js.map +1 -1
- package/dist/vocabulary/optional.d.ts +6 -1
- package/dist/vocabulary/optional.d.ts.map +1 -1
- package/dist/vocabulary/optional.js +7 -2
- package/dist/vocabulary/optional.js.map +1 -1
- package/dist/vocabulary/primary.d.ts +2 -2
- package/dist/vocabulary/primary.d.ts.map +1 -1
- package/dist/vocabulary/primary.js +7 -2
- package/dist/vocabulary/primary.js.map +1 -1
- package/dist/vocabulary/readOnly.d.ts +6 -1
- package/dist/vocabulary/readOnly.d.ts.map +1 -1
- package/dist/vocabulary/readOnly.js +6 -1
- package/dist/vocabulary/readOnly.js.map +1 -1
- package/dist/vocabulary/ref.d.ts +7 -2
- package/dist/vocabulary/ref.d.ts.map +1 -1
- package/dist/vocabulary/ref.js +7 -2
- package/dist/vocabulary/ref.js.map +1 -1
- package/dist/vocabulary/text.d.ts +7 -2
- package/dist/vocabulary/text.d.ts.map +1 -1
- package/dist/vocabulary/text.js +6 -1
- package/dist/vocabulary/text.js.map +1 -1
- package/dist/vocabulary/unique.d.ts +6 -1
- package/dist/vocabulary/unique.d.ts.map +1 -1
- package/dist/vocabulary/unique.js +7 -3
- package/dist/vocabulary/unique.js.map +1 -1
- package/dist/vocabulary/updated.d.ts +6 -1
- package/dist/vocabulary/updated.d.ts.map +1 -1
- package/dist/vocabulary/updated.js +5 -0
- package/dist/vocabulary/updated.js.map +1 -1
- package/dist/vocabulary/url.d.ts +6 -1
- package/dist/vocabulary/url.d.ts.map +1 -1
- package/dist/vocabulary/url.js +5 -0
- package/dist/vocabulary/url.js.map +1 -1
- package/dist/vocabulary/vocabulary.d.ts +6 -1
- package/dist/vocabulary/vocabulary.d.ts.map +1 -1
- package/dist/vocabulary/vocabulary.js +22 -12
- package/dist/vocabulary/vocabulary.js.map +1 -1
- package/dist/vocabulary/writeOnly.d.ts +6 -1
- package/dist/vocabulary/writeOnly.d.ts.map +1 -1
- package/dist/vocabulary/writeOnly.js +6 -1
- package/dist/vocabulary/writeOnly.js.map +1 -1
- package/package.json +1 -1
- package/src/{schema/Schema.ts → Schema.ts} +31 -74
- package/src/SchemaDefinition.ts +257 -0
- package/src/SchemaDerivation.ts +44 -0
- package/src/{schema/SchemaView.ts → SchemaView.ts} +9 -9
- package/src/{schema/axis → axis}/Axis.ts +2 -2
- package/src/axis/boundary/Boundaries.ts +37 -0
- package/src/{schema/axis → axis}/boundary/Boundary.ts +9 -7
- package/src/{schema/axis → axis}/boundary/BoundaryAxis.ts +4 -4
- package/src/{schema/axis → axis}/lifecycle/Clock.ts +1 -1
- package/src/axis/lifecycle/Generators.ts +29 -0
- package/src/{schema/axis → axis}/lifecycle/LifecycleAxis.ts +12 -7
- package/src/axis/lifecycle/apply.ts +53 -0
- package/src/{schema/axis → axis}/role/Relation.ts +6 -5
- package/src/axis/role/Role.ts +52 -0
- package/src/{schema/axis → axis}/role/RoleAxis.ts +28 -40
- package/src/axis/shape/Formats.ts +20 -0
- package/src/{schema/axis → axis}/shape/Shape.ts +18 -18
- package/src/entity/EntityAdapterSet.ts +81 -0
- package/src/entity/EntityAdapters.ts +4 -96
- package/src/entity/EntityDeclarations.ts +1 -1
- package/src/entity.ts +7 -2
- package/src/{schema/fields → field}/Field.ts +8 -26
- package/src/field/FieldSet.ts +75 -0
- package/src/index.ts +29 -44
- package/src/lib/Registry.ts +37 -0
- package/src/projection/Cases.ts +56 -55
- package/src/projection/Visibility.ts +5 -4
- package/src/projection/card/Bundle.ts +9 -9
- package/src/projection/card/Card.ts +101 -74
- package/src/projection/card/Descriptor.ts +7 -7
- package/src/projection/card/admission.ts +16 -6
- package/src/projection/card/diff.ts +2 -2
- package/src/validator/AdapterFieldValidator.ts +40 -0
- package/src/{judge/FieldJudge.ts → validator/FieldDeclarationValidator.ts} +10 -10
- package/src/{judge/ValueJudge.ts → validator/FieldValueValidator.ts} +14 -13
- package/src/{judge/RowRefusal.ts → validator/InputRefusal.ts} +2 -4
- package/src/{judge/RowJudge.ts → validator/InputValidator.ts} +30 -23
- package/src/vocabulary/bool.ts +6 -1
- package/src/vocabulary/created.ts +6 -1
- package/src/vocabulary/date.ts +6 -1
- package/src/vocabulary/email.ts +6 -1
- package/src/vocabulary/immutable.ts +6 -1
- package/src/vocabulary/indexed.ts +6 -1
- package/src/vocabulary/json.ts +10 -5
- package/src/vocabulary/list.ts +6 -1
- package/src/vocabulary/many.ts +7 -2
- package/src/vocabulary/nullable.ts +8 -3
- package/src/vocabulary/number.ts +6 -1
- package/src/vocabulary/oneOf.ts +6 -1
- package/src/vocabulary/optional.ts +8 -3
- package/src/vocabulary/primary.ts +7 -2
- package/src/vocabulary/readOnly.ts +7 -2
- package/src/vocabulary/ref.ts +7 -2
- package/src/vocabulary/text.ts +7 -2
- package/src/vocabulary/unique.ts +8 -4
- package/src/vocabulary/updated.ts +6 -1
- package/src/vocabulary/url.ts +6 -1
- package/src/vocabulary/vocabulary.ts +22 -12
- package/src/vocabulary/writeOnly.ts +7 -2
- package/dist/judge/FieldJudge.d.ts +0 -9
- package/dist/judge/FieldJudge.d.ts.map +0 -1
- package/dist/judge/FieldJudge.js.map +0 -1
- package/dist/judge/RowJudge.d.ts +0 -12
- package/dist/judge/RowJudge.d.ts.map +0 -1
- package/dist/judge/RowJudge.js.map +0 -1
- package/dist/judge/RowRefusal.d.ts.map +0 -1
- package/dist/judge/RowRefusal.js.map +0 -1
- package/dist/judge/ValueJudge.d.ts +0 -12
- package/dist/judge/ValueJudge.d.ts.map +0 -1
- package/dist/judge/ValueJudge.js.map +0 -1
- package/dist/judge/options.d.ts +0 -4
- package/dist/judge/options.d.ts.map +0 -1
- package/dist/judge/options.js +0 -2
- package/dist/judge/options.js.map +0 -1
- package/dist/judge/result.d.ts.map +0 -1
- package/dist/judge/result.js +0 -2
- package/dist/judge/result.js.map +0 -1
- package/dist/projection/SchemaOrCard.d.ts +0 -7
- package/dist/projection/SchemaOrCard.d.ts.map +0 -1
- package/dist/projection/SchemaOrCard.js +0 -11
- package/dist/projection/SchemaOrCard.js.map +0 -1
- package/dist/projection/card/EntityTypeSource.d.ts +0 -12
- package/dist/projection/card/EntityTypeSource.d.ts.map +0 -1
- package/dist/projection/card/EntityTypeSource.js +0 -78
- package/dist/projection/card/EntityTypeSource.js.map +0 -1
- package/dist/projection/card/FacadeTypeSource.d.ts +0 -19
- package/dist/projection/card/FacadeTypeSource.d.ts.map +0 -1
- package/dist/projection/card/FacadeTypeSource.js +0 -40
- package/dist/projection/card/FacadeTypeSource.js.map +0 -1
- package/dist/schema/Schema.d.ts.map +0 -1
- package/dist/schema/Schema.js.map +0 -1
- package/dist/schema/SchemaDefinition.d.ts +0 -60
- package/dist/schema/SchemaDefinition.d.ts.map +0 -1
- package/dist/schema/SchemaDefinition.js +0 -85
- package/dist/schema/SchemaDefinition.js.map +0 -1
- package/dist/schema/SchemaDerivation.d.ts +0 -34
- package/dist/schema/SchemaDerivation.d.ts.map +0 -1
- package/dist/schema/SchemaDerivation.js +0 -51
- package/dist/schema/SchemaDerivation.js.map +0 -1
- package/dist/schema/SchemaView.d.ts.map +0 -1
- package/dist/schema/axis/Axis.d.ts.map +0 -1
- package/dist/schema/axis/Axis.js.map +0 -1
- package/dist/schema/axis/Meta.d.ts.map +0 -1
- package/dist/schema/axis/boundary/Boundaries.d.ts +0 -20
- package/dist/schema/axis/boundary/Boundaries.d.ts.map +0 -1
- package/dist/schema/axis/boundary/Boundaries.js +0 -31
- package/dist/schema/axis/boundary/Boundaries.js.map +0 -1
- package/dist/schema/axis/boundary/Boundary.d.ts.map +0 -1
- package/dist/schema/axis/boundary/Boundary.js.map +0 -1
- package/dist/schema/axis/boundary/BoundaryAxis.d.ts.map +0 -1
- package/dist/schema/axis/boundary/BoundaryAxis.js.map +0 -1
- package/dist/schema/axis/lifecycle/Clock.d.ts.map +0 -1
- package/dist/schema/axis/lifecycle/Clock.js.map +0 -1
- package/dist/schema/axis/lifecycle/Generators.d.ts +0 -18
- package/dist/schema/axis/lifecycle/Generators.d.ts.map +0 -1
- package/dist/schema/axis/lifecycle/Generators.js +0 -38
- package/dist/schema/axis/lifecycle/Generators.js.map +0 -1
- package/dist/schema/axis/lifecycle/Lifecycle.d.ts.map +0 -1
- package/dist/schema/axis/lifecycle/Lifecycle.js.map +0 -1
- package/dist/schema/axis/lifecycle/LifecycleAxis.d.ts.map +0 -1
- package/dist/schema/axis/lifecycle/LifecycleAxis.js.map +0 -1
- package/dist/schema/axis/lifecycle/apply.d.ts +0 -6
- package/dist/schema/axis/lifecycle/apply.d.ts.map +0 -1
- package/dist/schema/axis/lifecycle/apply.js +0 -34
- package/dist/schema/axis/lifecycle/apply.js.map +0 -1
- package/dist/schema/axis/role/Relation.d.ts.map +0 -1
- package/dist/schema/axis/role/Relation.js.map +0 -1
- package/dist/schema/axis/role/Role.d.ts.map +0 -1
- package/dist/schema/axis/role/Role.js +0 -40
- package/dist/schema/axis/role/Role.js.map +0 -1
- package/dist/schema/axis/role/RoleAxis.d.ts.map +0 -1
- package/dist/schema/axis/role/RoleAxis.js.map +0 -1
- package/dist/schema/axis/shape/Formats.d.ts +0 -8
- package/dist/schema/axis/shape/Formats.d.ts.map +0 -1
- package/dist/schema/axis/shape/Formats.js +0 -10
- package/dist/schema/axis/shape/Formats.js.map +0 -1
- package/dist/schema/axis/shape/Shape.d.ts.map +0 -1
- package/dist/schema/axis/shape/Shape.js.map +0 -1
- package/dist/schema/fields/Field.d.ts.map +0 -1
- package/dist/schema/fields/Field.js +0 -52
- package/dist/schema/fields/Field.js.map +0 -1
- package/dist/schema/fields/FieldSet.d.ts +0 -28
- package/dist/schema/fields/FieldSet.d.ts.map +0 -1
- package/dist/schema/fields/FieldSet.js +0 -55
- package/dist/schema/fields/FieldSet.js.map +0 -1
- package/dist/schema/fields/constraint/FieldGroup.d.ts +0 -21
- package/dist/schema/fields/constraint/FieldGroup.d.ts.map +0 -1
- package/dist/schema/fields/constraint/FieldGroup.js +0 -65
- package/dist/schema/fields/constraint/FieldGroup.js.map +0 -1
- package/dist/schema/fields/constraint/Unique.d.ts +0 -4
- package/dist/schema/fields/constraint/Unique.d.ts.map +0 -1
- package/dist/schema/fields/constraint/Unique.js +0 -4
- package/dist/schema/fields/constraint/Unique.js.map +0 -1
- package/dist/utils.d.ts.map +0 -1
- package/dist/utils.js.map +0 -1
- package/src/judge/options.ts +0 -3
- package/src/projection/SchemaOrCard.ts +0 -18
- package/src/projection/card/EntityTypeSource.ts +0 -90
- package/src/projection/card/FacadeTypeSource.ts +0 -55
- package/src/schema/SchemaDefinition.ts +0 -150
- package/src/schema/SchemaDerivation.ts +0 -65
- package/src/schema/axis/boundary/Boundaries.ts +0 -44
- package/src/schema/axis/lifecycle/Generators.ts +0 -46
- package/src/schema/axis/lifecycle/apply.ts +0 -39
- package/src/schema/axis/role/Role.ts +0 -56
- package/src/schema/axis/shape/Formats.ts +0 -22
- package/src/schema/fields/FieldSet.ts +0 -63
- package/src/schema/fields/constraint/FieldGroup.ts +0 -84
- package/src/schema/fields/constraint/Unique.ts +0 -3
- /package/dist/{schema/SchemaView.js → SchemaView.js} +0 -0
- /package/dist/{schema/axis → axis}/Axis.js +0 -0
- /package/dist/{schema/axis → axis}/Meta.d.ts +0 -0
- /package/dist/{schema/axis → axis}/Meta.js +0 -0
- /package/dist/{schema/axis → axis}/boundary/BoundaryAxis.d.ts +0 -0
- /package/dist/{schema/axis → axis}/lifecycle/Lifecycle.d.ts +0 -0
- /package/dist/{schema/axis → axis}/lifecycle/Lifecycle.js +0 -0
- /package/dist/{schema/axis → axis}/lifecycle/LifecycleAxis.d.ts +0 -0
- /package/dist/{utils.d.ts → lib/utils.d.ts} +0 -0
- /package/dist/{utils.js → lib/utils.js} +0 -0
- /package/src/{schema/axis → axis}/Meta.ts +0 -0
- /package/src/{schema/axis → axis}/lifecycle/Lifecycle.ts +0 -0
- /package/src/{utils.ts → lib/utils.ts} +0 -0
- /package/src/{judge/result.ts → validation.ts} +0 -0
|
@@ -1,100 +1,8 @@
|
|
|
1
|
-
import type { FieldName, Fields } from '../
|
|
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<
|
|
8
|
-
|
|
9
|
-
|
|
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
|
+
>;
|
package/src/entity.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import { type Fields } from './
|
|
1
|
+
import { type Fields } from './field/Field.js';
|
|
2
2
|
import { type EntityDeclarations } from './entity/EntityDeclarations.js';
|
|
3
|
-
import { Schema, type SchemaConstructor } from './
|
|
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,18 +1,18 @@
|
|
|
1
1
|
import type { Shape } from '../axis/shape/Shape.js';
|
|
2
|
-
import {
|
|
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 {
|
|
8
|
-
import {
|
|
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
12
|
/** A key of a field set — the name a declaration addresses a field by. */
|
|
13
13
|
export type FieldName<TFields extends Fields> = Extract<keyof TFields, string>;
|
|
14
14
|
|
|
15
|
-
/** The carrier, the three extension axes, the annotation — the five the
|
|
15
|
+
/** The carrier, the three extension axes, the annotation — the five the validator reads. */
|
|
16
16
|
export type FieldDeclaration = Pick<Field, 'shape' | Axis['slot'] | 'meta'>;
|
|
17
17
|
|
|
18
18
|
export class Field<T = unknown> {
|
|
@@ -25,7 +25,7 @@ export class Field<T = unknown> {
|
|
|
25
25
|
declare readonly _type?: T;
|
|
26
26
|
|
|
27
27
|
constructor(init: FieldDeclaration, key?: string) {
|
|
28
|
-
const verdict =
|
|
28
|
+
const verdict = FieldDeclarationValidator.of(init).verdict;
|
|
29
29
|
|
|
30
30
|
if (!verdict.success) {
|
|
31
31
|
throw new Error(
|
|
@@ -35,14 +35,14 @@ export class Field<T = unknown> {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
this.shape = init.shape;
|
|
38
|
-
this.role =
|
|
38
|
+
this.role = init.role;
|
|
39
39
|
this.lifecycle = init.lifecycle;
|
|
40
40
|
this.boundary = init.boundary;
|
|
41
41
|
this.meta = init.meta;
|
|
42
42
|
|
|
43
43
|
const create = this.lifecycle?.create;
|
|
44
44
|
if (typeof create === 'object' && create !== null && 'value' in create) {
|
|
45
|
-
const checked =
|
|
45
|
+
const checked = FieldValueValidator.of(this).validate(create.value);
|
|
46
46
|
if ('error' in checked)
|
|
47
47
|
throw new Error(
|
|
48
48
|
`${key ? `Field '${key}': ` : ''}the declared default ${JSON.stringify(create.value)} ` +
|
|
@@ -52,28 +52,10 @@ export class Field<T = unknown> {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
static is(value: unknown): value is Field {
|
|
55
|
-
return
|
|
55
|
+
return FieldDeclarationValidator.of(value).verdict.success;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
with<U = T>(overrides: Partial<FieldDeclaration>): Field<U> {
|
|
59
59
|
return new Field<U>({ ...this, ...overrides });
|
|
60
60
|
}
|
|
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
61
|
}
|
|
@@ -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) => !(key in fields));
|
|
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
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,42 +1,39 @@
|
|
|
1
|
-
export { Field, type Fields } from './
|
|
2
|
-
export { FieldSet } from './
|
|
3
|
-
export { type Shape,
|
|
1
|
+
export { Field, type Fields } from './field/Field.js';
|
|
2
|
+
export { FieldSet } from './field/FieldSet.js';
|
|
3
|
+
export { type Shape, Shapes } from './axis/shape/Shape.js';
|
|
4
4
|
export {
|
|
5
5
|
type StringFormat,
|
|
6
6
|
type FormatPredicate,
|
|
7
7
|
Formats,
|
|
8
|
-
} from './
|
|
9
|
-
export { Role, type RoleRules } from './
|
|
10
|
-
export { type Relation, type EntityConstructor } from './
|
|
11
|
-
export { Lifecycle, type LifecycleRules } from './
|
|
12
|
-
export { type GeneratorRef, Generators } from './
|
|
13
|
-
export { Clock } from './
|
|
8
|
+
} from './axis/shape/Formats.js';
|
|
9
|
+
export { Role, type RoleRules } from './axis/role/Role.js';
|
|
10
|
+
export { type Relation, type EntityConstructor } from './axis/role/Relation.js';
|
|
11
|
+
export { Lifecycle, type LifecycleRules } from './axis/lifecycle/Lifecycle.js';
|
|
12
|
+
export { type GeneratorRef, Generators } from './axis/lifecycle/Generators.js';
|
|
13
|
+
export { Clock } from './axis/lifecycle/Clock.js';
|
|
14
14
|
export {
|
|
15
15
|
Boundary,
|
|
16
16
|
type BoundaryRules,
|
|
17
17
|
type BoundaryRef,
|
|
18
|
-
} from './
|
|
19
|
-
export { type Decoder, type Encoder, Boundaries } from './
|
|
20
|
-
export { type Meta } from './
|
|
21
|
-
export { FieldGroup } from './schema/fields/constraint/FieldGroup.js';
|
|
22
|
-
export { Unique } from './schema/fields/constraint/Unique.js';
|
|
18
|
+
} from './axis/boundary/Boundary.js';
|
|
19
|
+
export { type Decoder, type Encoder, Boundaries } from './axis/boundary/Boundaries.js';
|
|
20
|
+
export { type Meta } from './axis/Meta.js';
|
|
23
21
|
|
|
22
|
+
export { Schema, ANONYMOUS_SCHEMA_NAME, type SchemaConstructor } from './Schema.js';
|
|
23
|
+
export { SchemaDerivation } from './SchemaDerivation.js';
|
|
24
|
+
export { Cases, type ValidationCase } from './projection/Cases.js';
|
|
25
|
+
export { InputRefusal } from './validator/InputRefusal.js';
|
|
26
|
+
export { type SchemaView, type Values, type PartialValues } from './SchemaView.js';
|
|
24
27
|
export {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
} from './schema/Schema.js';
|
|
29
|
-
export { SchemaDerivation } from './schema/SchemaDerivation.js';
|
|
30
|
-
export { Cases, type Case } from './projection/Cases.js';
|
|
31
|
-
export { RowRefusal } from './judge/RowRefusal.js';
|
|
32
|
-
export { type SchemaView, type Row, type PartialRow } from './schema/SchemaView.js';
|
|
33
|
-
export { type FougereEntityAdapters, type EntityAdapters } from './entity/EntityAdapters.js';
|
|
28
|
+
type FougereEntityAdapters,
|
|
29
|
+
type EntityAdapters,
|
|
30
|
+
} from './entity/EntityAdapters.js';
|
|
34
31
|
export {
|
|
35
32
|
type EntityDeclarations,
|
|
36
33
|
type CompositeUnique,
|
|
37
34
|
type PreviousNames,
|
|
38
35
|
} from './entity/EntityDeclarations.js';
|
|
39
|
-
export { lowerFirst, upperFirst, isObject } from './utils.js';
|
|
36
|
+
export { lowerFirst, upperFirst, isObject } from './lib/utils.js';
|
|
40
37
|
|
|
41
38
|
export { primary } from './vocabulary/primary.js';
|
|
42
39
|
export { text } from './vocabulary/text.js';
|
|
@@ -60,7 +57,7 @@ export { readOnly } from './vocabulary/readOnly.js';
|
|
|
60
57
|
export { writeOnly } from './vocabulary/writeOnly.js';
|
|
61
58
|
export { json } from './vocabulary/json.js';
|
|
62
59
|
|
|
63
|
-
export { applyCreate, applyUpdate } from './
|
|
60
|
+
export { applyCreate, applyUpdate } from './axis/lifecycle/apply.js';
|
|
64
61
|
export { Visibility } from './projection/Visibility.js';
|
|
65
62
|
export { Card } from './projection/card/Card.js';
|
|
66
63
|
export { Bundle } from './projection/card/Bundle.js';
|
|
@@ -73,15 +70,6 @@ export type {
|
|
|
73
70
|
RenameCandidate,
|
|
74
71
|
TypeSet,
|
|
75
72
|
} from './projection/card/diff.js';
|
|
76
|
-
export {
|
|
77
|
-
EntityTypeSource,
|
|
78
|
-
type EntityTypeSourceOptions,
|
|
79
|
-
} from './projection/card/EntityTypeSource.js';
|
|
80
|
-
export {
|
|
81
|
-
FacadeTypeSource,
|
|
82
|
-
type FacadeTypeSourceOptions,
|
|
83
|
-
type OpDescriptor,
|
|
84
|
-
} from './projection/card/FacadeTypeSource.js';
|
|
85
73
|
export {
|
|
86
74
|
type SchemaBundle,
|
|
87
75
|
type SchemaDescriptor,
|
|
@@ -90,17 +78,14 @@ export {
|
|
|
90
78
|
type RoleDescriptor,
|
|
91
79
|
type RelationDescriptor,
|
|
92
80
|
} from './projection/card/Descriptor.js';
|
|
93
|
-
export { type SchemaOrCard, schemaOf, fieldsOf } from './projection/SchemaOrCard.js';
|
|
94
81
|
export type { StandardSchemaV1 } from './projection/standard.js';
|
|
95
82
|
|
|
96
83
|
export { entity } from './entity.js';
|
|
97
84
|
|
|
98
|
-
export {
|
|
99
|
-
export {
|
|
100
|
-
export {
|
|
101
|
-
export {
|
|
102
|
-
export {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
type Checked,
|
|
106
|
-
} from './judge/result.js';
|
|
85
|
+
export { FieldDeclarationValidator } from './validator/FieldDeclarationValidator.js';
|
|
86
|
+
export { FieldValueValidator } from './validator/FieldValueValidator.js';
|
|
87
|
+
export { InputValidator } from './validator/InputValidator.js';
|
|
88
|
+
export { AdapterFieldValidator } from './validator/AdapterFieldValidator.js';
|
|
89
|
+
export { Registry } from './lib/Registry.js';
|
|
90
|
+
export { type ValidateOptions } from './validator/InputValidator.js';
|
|
91
|
+
export { type ValidationError, type ValidationResult, type Checked } from './validation.js';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export class Registry<T> {
|
|
2
|
+
private readonly entries: Map<string, T>;
|
|
3
|
+
|
|
4
|
+
/** `Unknown boundary decoder 'celsius' — call Boundaries.decoders.register(name, fn).` */
|
|
5
|
+
constructor(
|
|
6
|
+
private readonly label: string,
|
|
7
|
+
private readonly hint?: string,
|
|
8
|
+
builtins?: Iterable<readonly [string, T]>,
|
|
9
|
+
) {
|
|
10
|
+
this.entries = new Map(builtins);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
register(name: string, value: T): T {
|
|
14
|
+
this.entries.set(name, value);
|
|
15
|
+
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
find(name: string): T | undefined {
|
|
20
|
+
return this.entries.get(name);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
resolve(name: string, path?: string): T {
|
|
24
|
+
const found = this.find(name);
|
|
25
|
+
|
|
26
|
+
if (found !== undefined) return found;
|
|
27
|
+
|
|
28
|
+
throw new Error(
|
|
29
|
+
`${path ? `${path}: ` : ''}Unknown ${this.label} '${name}'${this.hint ? ` — ${this.hint}` : ''}. ` +
|
|
30
|
+
`This process answers ${this.names.join(', ') || 'nothing yet'}.`,
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
private get names(): string[] {
|
|
35
|
+
return [...this.entries.keys()];
|
|
36
|
+
}
|
|
37
|
+
}
|
package/src/projection/Cases.ts
CHANGED
|
@@ -1,70 +1,74 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Boundary } from '../
|
|
3
|
-
import { Lifecycle } from '../
|
|
4
|
-
import { Role } from '../
|
|
5
|
-
import type { Field } from '../
|
|
6
|
-
import type { SchemaView } from '../
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
1
|
+
import { Shapes } from '../axis/shape/Shape.js';
|
|
2
|
+
import { Boundary } from '../axis/boundary/Boundary.js';
|
|
3
|
+
import { Lifecycle } from '../axis/lifecycle/Lifecycle.js';
|
|
4
|
+
import { Role } from '../axis/role/Role.js';
|
|
5
|
+
import type { Field } from '../field/Field.js';
|
|
6
|
+
import type { SchemaView } from '../SchemaView.js';
|
|
7
|
+
import { InputValidator } from '../validator/InputValidator.js';
|
|
8
|
+
import { InputRefusal } from '../validator/InputRefusal.js';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* One input, and what the
|
|
11
|
+
* One input, and what the validator must answer.
|
|
12
12
|
*
|
|
13
13
|
* `expect` carries the PATH of the field at fault and never the message. We know which
|
|
14
14
|
* field must be refused because we are the ones who broke it; naming the message would
|
|
15
|
-
* make this list a second
|
|
15
|
+
* make this list a second validator, and the two would then have to be kept in step by hand —
|
|
16
16
|
* which is the duplication the whole thing exists to remove.
|
|
17
17
|
*/
|
|
18
|
-
export interface
|
|
18
|
+
export interface ValidationCase {
|
|
19
19
|
/** What this input does, in one clause — carried into the assertion so a failure reads. */
|
|
20
20
|
why: string;
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Judged as an update rather than a creation. The two modes refuse different things:
|
|
24
|
-
* an absence is `Required` on create and legal on patch, an immutable field is legal
|
|
25
|
-
* on create and refused on patch.
|
|
26
|
-
*/
|
|
21
|
+
input: unknown;
|
|
22
|
+
/** Judged as an update rather than a creation. */
|
|
27
23
|
patch: boolean;
|
|
28
24
|
expect: 'accept' | { reject: string };
|
|
29
25
|
}
|
|
30
26
|
|
|
31
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* So every field has at least one case, whatever else it declares.
|
|
29
|
+
* FR : pour que chaque champ ait un cas, quoi qu'il déclare par ailleurs.
|
|
30
|
+
* `text()` → `42`; `number()` → `'not-a-value-of-this-shape'`
|
|
31
|
+
*/
|
|
32
32
|
function wrongTypeFor(field: Field): unknown {
|
|
33
33
|
const declared = (field.shape as { type?: string | readonly string[] }).type;
|
|
34
34
|
const names = Array.isArray(declared) ? declared : [declared];
|
|
35
35
|
return names.includes('string') ? 42 : 'not-a-value-of-this-shape';
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
/**
|
|
38
|
+
/**
|
|
39
|
+
* So a bound stated in a shape produces the case that breaks it, and none is invented.
|
|
40
|
+
* FR : pour qu'une borne énoncée produise le cas qui la casse, et aucun autre.
|
|
41
|
+
* `text({ maxLength: 3 })` → one case with `'xxxx'`; `text()` → no case
|
|
42
|
+
*/
|
|
39
43
|
function outOfBoundsFor(field: Field): { why: string; value: unknown }[] {
|
|
40
|
-
// Through `
|
|
44
|
+
// Through `Shapes`, not a cast: the cast admitted any keyword, and it declared
|
|
41
45
|
// `maxItems` — which no branch below ever produced. In the one function whose job is
|
|
42
46
|
// to be exhaustive, a bound the type does not carry is a case nobody notices missing.
|
|
43
|
-
const shape =
|
|
44
|
-
const
|
|
47
|
+
const shape = Shapes.of(field.shape).base;
|
|
48
|
+
const cases: { why: string; value: unknown }[] = [];
|
|
45
49
|
if (shape?.type === 'string') {
|
|
46
50
|
if (typeof shape.minLength === 'number' && shape.minLength > 0)
|
|
47
|
-
|
|
51
|
+
cases.push({ why: 'shorter than min', value: 'x'.repeat(shape.minLength - 1) });
|
|
48
52
|
if (typeof shape.maxLength === 'number')
|
|
49
|
-
|
|
50
|
-
if (shape.enum)
|
|
53
|
+
cases.push({ why: 'longer than max', value: 'x'.repeat(shape.maxLength + 1) });
|
|
54
|
+
if (shape.enum) cases.push({ why: 'outside the stated set', value: '__not-in-enum__' });
|
|
51
55
|
}
|
|
52
56
|
if (shape?.type === 'number' || shape?.type === 'integer') {
|
|
53
57
|
if (typeof shape.minimum === 'number')
|
|
54
|
-
|
|
58
|
+
cases.push({ why: 'below minimum', value: shape.minimum - 1 });
|
|
55
59
|
if (typeof shape.maximum === 'number')
|
|
56
|
-
|
|
60
|
+
cases.push({ why: 'above maximum', value: shape.maximum + 1 });
|
|
57
61
|
}
|
|
58
62
|
if (shape?.type === 'array') {
|
|
59
63
|
if (typeof shape.minItems === 'number' && shape.minItems > 0)
|
|
60
|
-
|
|
64
|
+
cases.push({ why: 'fewer items than min', value: [] });
|
|
61
65
|
if (typeof shape.maxItems === 'number')
|
|
62
|
-
|
|
66
|
+
cases.push({
|
|
63
67
|
why: 'more items than max',
|
|
64
68
|
value: Array.from({ length: shape.maxItems + 1 }, () => null),
|
|
65
69
|
});
|
|
66
70
|
}
|
|
67
|
-
return
|
|
71
|
+
return cases;
|
|
68
72
|
}
|
|
69
73
|
|
|
70
74
|
/**
|
|
@@ -74,20 +78,14 @@ function outOfBoundsFor(field: Field): { why: string; value: unknown }[] {
|
|
|
74
78
|
* supplies a valid row; generating data belongs to the testing package.
|
|
75
79
|
*/
|
|
76
80
|
export class Cases {
|
|
77
|
-
private constructor(readonly all: readonly
|
|
81
|
+
private constructor(readonly all: readonly ValidationCase[]) {}
|
|
78
82
|
|
|
79
83
|
static of(entity: SchemaView, valid: Record<string, unknown>): Cases {
|
|
80
84
|
return new Cases(enumerate(entity, valid));
|
|
81
85
|
}
|
|
82
86
|
|
|
83
|
-
/**
|
|
84
|
-
* Whether a verdict is the one a case expected.
|
|
85
|
-
*
|
|
86
|
-
* Takes the RESULT rather than the input so the same reader serves the local judge, the
|
|
87
|
-
* façade and a door — the three that have to agree.
|
|
88
|
-
*/
|
|
89
87
|
static holds(
|
|
90
|
-
expected:
|
|
88
|
+
expected: ValidationCase['expect'],
|
|
91
89
|
result: { success: boolean; errors?: { path: string }[] },
|
|
92
90
|
): boolean {
|
|
93
91
|
if (expected === 'accept') return result.success;
|
|
@@ -95,32 +93,35 @@ export class Cases {
|
|
|
95
93
|
return (result.errors ?? []).some((error) => error.path === expected.reject);
|
|
96
94
|
}
|
|
97
95
|
|
|
98
|
-
/** Every way a row is refused for its structure — the closed set this table must cover. */
|
|
99
96
|
static get refusals(): string[] {
|
|
100
|
-
return Object.values(
|
|
97
|
+
return Object.values(InputRefusal);
|
|
101
98
|
}
|
|
102
99
|
|
|
103
|
-
[Symbol.iterator](): Iterator<
|
|
100
|
+
[Symbol.iterator](): Iterator<ValidationCase> {
|
|
104
101
|
return this.all[Symbol.iterator]();
|
|
105
102
|
}
|
|
106
103
|
}
|
|
107
104
|
|
|
108
|
-
|
|
105
|
+
/**
|
|
106
|
+
* So the four axes decide which cases exist, and no list of them is maintained by hand.
|
|
107
|
+
* FR : pour que les axes décident des cas, sans liste tenue à la main.
|
|
108
|
+
*/
|
|
109
|
+
function enumerate(entity: SchemaView, valid: Record<string, unknown>): ValidationCase[] {
|
|
109
110
|
const fields = entity.getFields();
|
|
110
|
-
const
|
|
111
|
-
const cases:
|
|
111
|
+
const validator = InputValidator.of(fields);
|
|
112
|
+
const cases: ValidationCase[] = [];
|
|
112
113
|
const withField = (name: string, value: unknown) => ({ ...valid, [name]: value });
|
|
113
114
|
|
|
114
|
-
cases.push({ why: 'a valid
|
|
115
|
+
cases.push({ why: 'a valid input', input: valid, patch: false, expect: 'accept' });
|
|
115
116
|
cases.push({
|
|
116
117
|
why: 'a key outside the contract',
|
|
117
|
-
|
|
118
|
+
input: { ...valid, __unknown__: 'x' },
|
|
118
119
|
patch: false,
|
|
119
120
|
expect: { reject: '__unknown__' },
|
|
120
121
|
});
|
|
121
122
|
cases.push({
|
|
122
123
|
why: 'not an object at all',
|
|
123
|
-
|
|
124
|
+
input: 'a string',
|
|
124
125
|
patch: false,
|
|
125
126
|
expect: { reject: '.' },
|
|
126
127
|
});
|
|
@@ -130,16 +131,16 @@ function enumerate(entity: SchemaView, valid: Record<string, unknown>): Case[] {
|
|
|
130
131
|
// get to invent a second one, so the only case we can state about it is the bound one.
|
|
131
132
|
const isRef = Role.of(field).isReference;
|
|
132
133
|
|
|
133
|
-
if (
|
|
134
|
-
const
|
|
135
|
-
delete
|
|
136
|
-
cases.push({ why: `${name} absent`,
|
|
134
|
+
if (validator.onAbsent(field) === null && name in valid) {
|
|
135
|
+
const input = { ...valid };
|
|
136
|
+
delete input[name];
|
|
137
|
+
cases.push({ why: `${name} absent`, input, patch: false, expect: { reject: name } });
|
|
137
138
|
}
|
|
138
139
|
|
|
139
140
|
if (Boundary.of(field).readOnly) {
|
|
140
141
|
cases.push({
|
|
141
142
|
why: `${name} supplied although read-only`,
|
|
142
|
-
|
|
143
|
+
input: withField(name, wrongTypeFor(field)),
|
|
143
144
|
patch: false,
|
|
144
145
|
expect: { reject: name },
|
|
145
146
|
});
|
|
@@ -148,7 +149,7 @@ function enumerate(entity: SchemaView, valid: Record<string, unknown>): Case[] {
|
|
|
148
149
|
if (Lifecycle.of(field).immutable && !Role.of(field).isPrimary) {
|
|
149
150
|
cases.push({
|
|
150
151
|
why: `${name} supplied on an update`,
|
|
151
|
-
|
|
152
|
+
input: { [name]: valid[name] ?? wrongTypeFor(field) },
|
|
152
153
|
patch: true,
|
|
153
154
|
expect: { reject: name },
|
|
154
155
|
});
|
|
@@ -157,14 +158,14 @@ function enumerate(entity: SchemaView, valid: Record<string, unknown>): Case[] {
|
|
|
157
158
|
if (name in valid && !isRef) {
|
|
158
159
|
cases.push({
|
|
159
160
|
why: `${name} of the wrong type`,
|
|
160
|
-
|
|
161
|
+
input: withField(name, wrongTypeFor(field)),
|
|
161
162
|
patch: false,
|
|
162
163
|
expect: { reject: name },
|
|
163
164
|
});
|
|
164
165
|
for (const { why, value } of outOfBoundsFor(field))
|
|
165
166
|
cases.push({
|
|
166
167
|
why: `${name} ${why}`,
|
|
167
|
-
|
|
168
|
+
input: withField(name, value),
|
|
168
169
|
patch: false,
|
|
169
170
|
expect: { reject: name },
|
|
170
171
|
});
|