@fougere/schema 0.6.0-alpha.0 → 0.8.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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} +22 -62
- 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 +12 -3
- package/dist/axis/shape/Shape.d.ts.map +1 -0
- package/dist/axis/shape/Shape.js +77 -0
- 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 +3 -5
- 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 +26 -56
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -47
- 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/index.d.ts +3 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +3 -0
- package/dist/lib/index.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 +101 -70
- 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 +21 -5
- package/dist/projection/card/admission.d.ts.map +1 -1
- package/dist/projection/card/admission.js +33 -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/validator/InputRefusal.d.ts +8 -0
- package/dist/validator/InputRefusal.d.ts.map +1 -0
- package/dist/validator/InputRefusal.js +8 -0
- 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} +25 -21
- 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/index.d.ts +23 -0
- package/dist/vocabulary/index.d.ts.map +1 -0
- package/dist/vocabulary/index.js +23 -0
- package/dist/vocabulary/index.js.map +1 -0
- 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} +32 -75
- 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 +45 -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 -28
- package/src/field/FieldSet.ts +75 -0
- package/src/index.ts +34 -91
- package/src/lib/Registry.ts +37 -0
- package/src/lib/index.ts +2 -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 +109 -75
- package/src/projection/card/Descriptor.ts +7 -7
- package/src/projection/card/admission.ts +37 -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/validator/InputRefusal.ts +7 -0
- package/src/{judge/RowJudge.ts → validator/InputValidator.ts} +31 -24
- 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/index.ts +22 -0
- 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 +0 -17
- package/dist/judge/RowRefusal.d.ts.map +0 -1
- package/dist/judge/RowRefusal.js +0 -16
- 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 +0 -52
- 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/RowRefusal.ts +0 -17
- 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,11 +1,12 @@
|
|
|
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
|
|
8
|
-
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';
|
|
9
|
+
import { admitPatterns, refuse } from './admission.js';
|
|
9
10
|
import type {
|
|
10
11
|
DerivedFrom,
|
|
11
12
|
FieldDescriptor,
|
|
@@ -17,21 +18,23 @@ import type { Change, Diff, DiffOptions, RenameCandidate, TypeSet } from './diff
|
|
|
17
18
|
type FieldsOf<T> = { [K in keyof T]-?: Field<T[K]> };
|
|
18
19
|
|
|
19
20
|
/** One portable schema description and every decision made about that description. */
|
|
20
|
-
export class Card<T =
|
|
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,56 @@ export class Card<T = Row<Fields>> {
|
|
|
45
48
|
|
|
46
49
|
const origin = originOf(schema);
|
|
47
50
|
if (origin) descriptor['x-fougere-derived'] = origin;
|
|
48
|
-
return new Card<
|
|
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)) {
|
|
84
|
+
if (!isObject(property)) {
|
|
85
|
+
refuse(
|
|
86
|
+
`${subject} states \`${key}\` as ${JSON.stringify(property)}`,
|
|
87
|
+
'A field is one JSON Schema object, and there is nothing to rebuild from that.',
|
|
88
|
+
);
|
|
89
|
+
}
|
|
85
90
|
fields[key] = reconstructField(property, key, resolve);
|
|
91
|
+
for (const group of property['x-fougere']?.role?.unique ?? [])
|
|
92
|
+
if (group.length > 1) groups.push([...group]);
|
|
86
93
|
}
|
|
87
|
-
const schema = Schema.of({ fields });
|
|
94
|
+
const schema = Schema.of({ fields, constraints: { unique: deduplicated(groups) } });
|
|
88
95
|
const title = name ?? descriptor.title;
|
|
89
96
|
if (title)
|
|
90
97
|
Object.defineProperty(schema, 'name', { value: title, configurable: true });
|
|
91
98
|
return schema as unknown as SchemaConstructor<FieldsOf<T>>;
|
|
92
99
|
}
|
|
93
100
|
|
|
94
|
-
/** What must change to turn this card into `other`. */
|
|
95
101
|
diff(other: Card, options: DiffOptions = {}): Diff {
|
|
96
102
|
const changes: Change[] = [];
|
|
97
103
|
const renamed = options.renamed ?? {};
|
|
@@ -155,6 +161,11 @@ export class Card<T = Row<Fields>> {
|
|
|
155
161
|
}
|
|
156
162
|
}
|
|
157
163
|
|
|
164
|
+
/**
|
|
165
|
+
* So the three axes write themselves under `x-fougere`, each by its own hand.
|
|
166
|
+
* FR : pour que les trois axes s'écrivent sous `x-fougere`, chacun de sa main.
|
|
167
|
+
* `ref(User)` → `{ role: { relation: { to: 'user', kind: 'one' } } }`
|
|
168
|
+
*/
|
|
158
169
|
function describeExtension(field: Field, key: string): FieldExtension | undefined {
|
|
159
170
|
const extension: Record<string, unknown> = {};
|
|
160
171
|
for (const axis of EXTENSION_AXES) {
|
|
@@ -167,72 +178,57 @@ function describeExtension(field: Field, key: string): FieldExtension | undefine
|
|
|
167
178
|
return Object.keys(extension).length ? (extension as FieldExtension) : undefined;
|
|
168
179
|
}
|
|
169
180
|
|
|
181
|
+
/**
|
|
182
|
+
* So the shape stays plain JSON Schema, and what is ours sits under one key.
|
|
183
|
+
* FR : pour que la forme reste du JSON Schema, ce qui est à nous tenant sous une clé.
|
|
184
|
+
* `text({ max: 200 })` → `{ type: 'string', maxLength: 200 }`
|
|
185
|
+
*/
|
|
170
186
|
function describeField(field: Field, key: string): FieldDescriptor {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
187
|
+
// The shape IS JSON Schema, so it lands whole rather than key by key — which is what let
|
|
188
|
+
// it be copied under a computed key into a type that names its own.
|
|
189
|
+
const descriptor: FieldDescriptor = clean({ ...field.shape }) as FieldDescriptor;
|
|
175
190
|
if (field.meta?.description) descriptor.description = field.meta.description;
|
|
176
191
|
const extension = describeExtension(field, key);
|
|
177
192
|
if (extension) descriptor['x-fougere'] = extension;
|
|
178
193
|
return descriptor;
|
|
179
194
|
}
|
|
180
195
|
|
|
196
|
+
/**
|
|
197
|
+
* So a derived card names its root and what became of each field.
|
|
198
|
+
* FR : pour qu'une carte dérivée nomme sa racine et le sort de chaque champ.
|
|
199
|
+
* `Post.pick('title')` → `{ from: 'Post', nameOf: { title: 'title' } }`
|
|
200
|
+
*/
|
|
181
201
|
function originOf(schema: SchemaView): DerivedFrom | undefined {
|
|
182
202
|
const { derivation } = schema;
|
|
183
203
|
if (!derivation) return undefined;
|
|
184
|
-
const
|
|
185
|
-
Object.entries(derivation.
|
|
204
|
+
const nameOf = Object.fromEntries(
|
|
205
|
+
Object.entries(derivation.nameOf).map(([key, value]) => [key, value ?? null]),
|
|
186
206
|
);
|
|
187
|
-
return { from: derivation.sourceName,
|
|
207
|
+
return { from: derivation.sourceName, nameOf };
|
|
188
208
|
}
|
|
189
209
|
|
|
210
|
+
/**
|
|
211
|
+
* So a shape read back is the shape that was written, and an unknown type is refused.
|
|
212
|
+
* FR : pour qu'une forme relue soit celle qui a été écrite, un type inconnu étant refusé.
|
|
213
|
+
* `{ type: 'string', maxLength: 200 }` → the same shape a `text({ max: 200 })` states
|
|
214
|
+
*/
|
|
190
215
|
function reconstructShape(property: FieldDescriptor): Field['shape'] | undefined {
|
|
191
|
-
const types = Array.isArray(property.type)
|
|
192
|
-
|
|
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
|
-
}
|
|
216
|
+
const types = Array.isArray(property.type) ? property.type : property.type ? [property.type] : [];
|
|
217
|
+
if (!types.some((type) => type !== 'null')) return undefined;
|
|
218
|
+
|
|
219
|
+
// `describeField` writes the shape whole, so it is read whole: a list of keywords here
|
|
220
|
+
// would be a second inventory, and the one that forgets a keyword loses it in silence.
|
|
221
|
+
const { 'x-fougere': _extension, description: _description, ...shape } = property;
|
|
222
|
+
if (shape.items) shape.items = reconstructShape(shape.items) as FieldDescriptor;
|
|
223
|
+
|
|
224
|
+
return clean(shape) as Field['shape'];
|
|
234
225
|
}
|
|
235
226
|
|
|
227
|
+
/**
|
|
228
|
+
* So a field read back carries its axes, rebuilt by the axes themselves.
|
|
229
|
+
* FR : pour qu'un champ relu porte ses axes, reconstruits par les axes eux-mêmes.
|
|
230
|
+
* `{ 'x-fougere': { lifecycle: { create: 'now' } } }` → a field stamped at create
|
|
231
|
+
*/
|
|
236
232
|
function reconstructField(
|
|
237
233
|
property: FieldDescriptor,
|
|
238
234
|
key: string,
|
|
@@ -245,6 +241,7 @@ function reconstructField(
|
|
|
245
241
|
'A field always states one.',
|
|
246
242
|
);
|
|
247
243
|
}
|
|
244
|
+
admitPatterns(shape, `Field '${key}'`);
|
|
248
245
|
const extension = property['x-fougere'];
|
|
249
246
|
const axes: Record<string, unknown> = {};
|
|
250
247
|
for (const axis of EXTENSION_AXES) {
|
|
@@ -261,6 +258,11 @@ function reconstructField(
|
|
|
261
258
|
} as never);
|
|
262
259
|
}
|
|
263
260
|
|
|
261
|
+
/**
|
|
262
|
+
* So an axis that changed is one named difference, not a whole field marked dirty.
|
|
263
|
+
* FR : pour qu'un axe modifié soit une différence nommée, pas un champ entier marqué.
|
|
264
|
+
* `{ kind: 'restated', field: 'body', axis: 'boundary', … }`
|
|
265
|
+
*/
|
|
264
266
|
function restated(
|
|
265
267
|
field: string,
|
|
266
268
|
before: FieldExtension | undefined,
|
|
@@ -278,22 +280,42 @@ function restated(
|
|
|
278
280
|
);
|
|
279
281
|
}
|
|
280
282
|
|
|
283
|
+
/**
|
|
284
|
+
* So two shapes are compared without what is not shape getting in the way.
|
|
285
|
+
* FR : pour que deux formes se comparent sans que le reste s'en mêle.
|
|
286
|
+
* `{ type: 'string', description: 'x' }` → `{ type: 'string' }`
|
|
287
|
+
*/
|
|
281
288
|
function shapeOf(descriptor: FieldDescriptor): Record<string, unknown> {
|
|
282
|
-
const { 'x-fougere': _extension, ...shape } = descriptor;
|
|
289
|
+
const { 'x-fougere': _extension, description: _description, ...shape } = descriptor;
|
|
283
290
|
return shape as Record<string, unknown>;
|
|
284
291
|
}
|
|
285
292
|
|
|
293
|
+
/**
|
|
294
|
+
* So `['string','null']` and `['null','string']` are the same type, not a change.
|
|
295
|
+
* FR : pour que `['string','null']` et `['null','string']` soient un même type.
|
|
296
|
+
* `typesOf({ type: ['null', 'string'] })` → `['null', 'string']`
|
|
297
|
+
*/
|
|
286
298
|
function typesOf(descriptor: FieldDescriptor): TypeSet {
|
|
287
299
|
const type = descriptor.type;
|
|
288
300
|
if (type === undefined) return [];
|
|
289
301
|
return (Array.isArray(type) ? [...type] : [type]).sort();
|
|
290
302
|
}
|
|
291
303
|
|
|
304
|
+
/**
|
|
305
|
+
* So a bound that moved is a `reshaped`, told apart from a type that changed.
|
|
306
|
+
* FR : pour qu'une borne déplacée soit un `reshaped`, distinct d'un type changé.
|
|
307
|
+
* `maxLength: 200` → `maxLength: 100` → one `reshaped`, never a `retyped`
|
|
308
|
+
*/
|
|
292
309
|
function boundsOf(descriptor: FieldDescriptor): Record<string, unknown> {
|
|
293
310
|
const { type: _type, ...rest } = shapeOf(descriptor);
|
|
294
311
|
return rest;
|
|
295
312
|
}
|
|
296
313
|
|
|
314
|
+
/**
|
|
315
|
+
* So a removal plus an addition of the same shape is a question, never a guess.
|
|
316
|
+
* FR : pour qu'une suppression plus un ajout de même forme soit une question, pas un pari.
|
|
317
|
+
* `body` gone, `content` appeared → `ambiguous: [{ removed: 'body', added: 'content' }]`
|
|
318
|
+
*/
|
|
297
319
|
function candidates(
|
|
298
320
|
removed: string[],
|
|
299
321
|
added: string[],
|
|
@@ -313,3 +335,15 @@ function candidates(
|
|
|
313
335
|
Math.abs(now.indexOf(appeared) - was.indexOf(gone));
|
|
314
336
|
return found.sort((a, b) => apart(a) - apart(b));
|
|
315
337
|
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* So a group spanning several fields reaches a reader that only ever sees one field.
|
|
341
|
+
* FR : pour qu'un groupe couvrant plusieurs champs atteigne un lecteur qui n'en voit qu'un.
|
|
342
|
+
* `carryGroup(properties.listId, ['listId', 'docId'])` → the pair lands under its `role`
|
|
343
|
+
*/
|
|
344
|
+
function carryGroup(property: FieldDescriptor | undefined, group: readonly string[]): void {
|
|
345
|
+
if (!property) return;
|
|
346
|
+
const extension = (property['x-fougere'] ??= {}) as { role?: { unique?: string[][] } };
|
|
347
|
+
const role = (extension.role ??= {});
|
|
348
|
+
(role.unique ??= []).push([...group]);
|
|
349
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { BoundaryRef } from '../../
|
|
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,27 @@
|
|
|
1
|
-
import type { ValidationError } from '../../
|
|
1
|
+
import type { ValidationError } from '../../validation.js';
|
|
2
|
+
import { Shapes } from '../../axis/shape/Shape.js';
|
|
2
3
|
|
|
3
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* So a card that cannot be read says what is wrong and what to write instead.
|
|
6
|
+
* FR : pour qu'une carte illisible dise ce qui cloche et quoi écrire.
|
|
7
|
+
* `refuse('role.relation.kind is "maybe"', 'Expected one of one, many.')`
|
|
8
|
+
*/
|
|
4
9
|
export function refuse(what: string, fix: string): never {
|
|
5
10
|
throw new Error(`This card cannot be read: ${what}.\n ${fix}`);
|
|
6
11
|
}
|
|
7
12
|
|
|
8
13
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
14
|
+
* So a card's axis passes the same validator as a hand-written one, and no second validator exists.
|
|
15
|
+
* FR : pour qu'un axe d'une carte passe le juge des autres, sans second juge.
|
|
16
|
+
* `{ update: 'maybe' }` on a card → `lifecycle is malformed — lifecycle.update: Expected 'now' or 'forbidden'`
|
|
11
17
|
*/
|
|
12
18
|
export function admitWire(
|
|
13
|
-
|
|
19
|
+
validator: (value: unknown, errors: ValidationError[]) => void,
|
|
14
20
|
value: unknown,
|
|
15
21
|
slot: string,
|
|
16
22
|
): void {
|
|
17
23
|
const errors: ValidationError[] = [];
|
|
18
|
-
|
|
24
|
+
validator(value, errors);
|
|
19
25
|
if (errors.length) {
|
|
20
26
|
refuse(
|
|
21
27
|
`${slot} is malformed — ${errors.map((e) => `${e.path}: ${e.message}`).join('; ')}`,
|
|
@@ -24,7 +30,32 @@ export function admitWire(
|
|
|
24
30
|
}
|
|
25
31
|
}
|
|
26
32
|
|
|
33
|
+
/**
|
|
34
|
+
* So a closed set is checked against the list that declares it, never against a copy.
|
|
35
|
+
* FR : pour qu'un ensemble fermé soit vérifié contre la liste qui le déclare.
|
|
36
|
+
* `oneOfTokens('many', RELATION_KINDS)` → `true`
|
|
37
|
+
*/
|
|
27
38
|
export const oneOfTokens = <T extends readonly string[]>(
|
|
28
39
|
value: unknown,
|
|
29
40
|
tokens: T,
|
|
30
41
|
): value is T[number] => typeof value === 'string' && (tokens as readonly string[]).includes(value);
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* So a `pattern` the engine cannot compile is refused where the card is read, not at the first row.
|
|
45
|
+
* FR : pour qu'un `pattern` incompilable soit refusé à la lecture de la carte, pas au premier row.
|
|
46
|
+
* `{ type: 'string', pattern: '(' }` → Field 'code' states `pattern: "("`, which is not a regular expression
|
|
47
|
+
*/
|
|
48
|
+
export function admitPatterns(shape: unknown, subject: string): void {
|
|
49
|
+
for (const pattern of Shapes.patterns(shape)) {
|
|
50
|
+
try {
|
|
51
|
+
// The engine compiles it with `u` and only when a row arrives, so nothing but this
|
|
52
|
+
// reads it early enough to name the card it came from.
|
|
53
|
+
new RegExp(pattern, 'u');
|
|
54
|
+
} catch (error) {
|
|
55
|
+
refuse(
|
|
56
|
+
`${subject} states \`pattern: ${JSON.stringify(pattern)}\`, which is not a regular expression`,
|
|
57
|
+
(error as Error).message,
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { BoundaryRef } from '../../
|
|
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;
|