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