@fougere/schema 0.5.0-alpha.1 → 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} +18 -28
- package/dist/Schema.d.ts.map +1 -0
- package/dist/Schema.js +136 -0
- 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/axis/Axis.d.ts +2 -2
- package/dist/axis/Axis.d.ts.map +1 -1
- package/dist/axis/boundary/Boundaries.d.ts +13 -12
- package/dist/axis/boundary/Boundaries.d.ts.map +1 -1
- package/dist/axis/boundary/Boundaries.js +18 -24
- package/dist/axis/boundary/Boundaries.js.map +1 -1
- package/dist/axis/boundary/Boundary.d.ts +3 -1
- package/dist/axis/boundary/Boundary.d.ts.map +1 -1
- package/dist/axis/boundary/Boundary.js +16 -7
- package/dist/axis/boundary/Boundary.js.map +1 -1
- package/dist/axis/boundary/BoundaryAxis.js +4 -4
- package/dist/axis/boundary/BoundaryAxis.js.map +1 -1
- package/dist/axis/lifecycle/Clock.d.ts +1 -1
- package/dist/axis/lifecycle/Clock.d.ts.map +1 -1
- package/dist/axis/lifecycle/Clock.js +1 -1
- package/dist/axis/lifecycle/Clock.js.map +1 -1
- package/dist/axis/lifecycle/Generators.d.ts +6 -14
- package/dist/axis/lifecycle/Generators.d.ts.map +1 -1
- package/dist/axis/lifecycle/Generators.js +10 -28
- package/dist/axis/lifecycle/Generators.js.map +1 -1
- package/dist/axis/lifecycle/LifecycleAxis.js +11 -6
- package/dist/axis/lifecycle/LifecycleAxis.js.map +1 -1
- package/dist/axis/lifecycle/apply.d.ts +14 -5
- package/dist/axis/lifecycle/apply.d.ts.map +1 -1
- package/dist/axis/lifecycle/apply.js +26 -10
- package/dist/axis/lifecycle/apply.js.map +1 -1
- package/dist/axis/role/Relation.d.ts +3 -2
- package/dist/axis/role/Relation.d.ts.map +1 -1
- package/dist/axis/role/Relation.js +6 -5
- package/dist/axis/role/Relation.js.map +1 -1
- package/dist/axis/role/Role.d.ts +6 -6
- package/dist/axis/role/Role.d.ts.map +1 -1
- package/dist/axis/role/Role.js +13 -17
- package/dist/axis/role/Role.js.map +1 -1
- package/dist/axis/role/RoleAxis.d.ts +1 -1
- package/dist/axis/role/RoleAxis.d.ts.map +1 -1
- package/dist/axis/role/RoleAxis.js +28 -37
- package/dist/axis/role/RoleAxis.js.map +1 -1
- package/dist/axis/shape/Formats.d.ts +8 -5
- package/dist/axis/shape/Formats.d.ts.map +1 -1
- package/dist/axis/shape/Formats.js +8 -9
- package/dist/axis/shape/Formats.js.map +1 -1
- package/dist/axis/shape/Shape.d.ts +5 -3
- package/dist/axis/shape/Shape.d.ts.map +1 -1
- package/dist/axis/shape/Shape.js +13 -13
- package/dist/axis/shape/Shape.js.map +1 -1
- 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 +5 -0
- package/dist/entity/EntityAdapters.d.ts.map +1 -0
- package/dist/entity/EntityAdapters.js +2 -0
- package/dist/entity/EntityAdapters.js.map +1 -0
- package/dist/{EntityDeclarations.d.ts → entity/EntityDeclarations.d.ts} +2 -7
- package/dist/entity/EntityDeclarations.d.ts.map +1 -0
- package/dist/entity/EntityDeclarations.js.map +1 -0
- package/dist/entity.d.ts +8 -3
- package/dist/entity.d.ts.map +1 -1
- package/dist/entity.js +6 -1
- package/dist/entity.js.map +1 -1
- package/dist/{fields → field}/Field.d.ts +8 -9
- 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 +24 -28
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -21
- 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/{utils.d.ts → lib/utils.d.ts} +1 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/{utils.js → lib/utils.js} +1 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/projection/Cases.d.ts +39 -0
- package/dist/projection/Cases.d.ts.map +1 -0
- package/dist/projection/Cases.js +146 -0
- package/dist/projection/Cases.js.map +1 -0
- package/dist/projection/Visibility.d.ts +2 -1
- package/dist/projection/Visibility.d.ts.map +1 -1
- package/dist/projection/Visibility.js +1 -0
- package/dist/projection/Visibility.js.map +1 -1
- package/dist/{card → projection/card}/Bundle.d.ts +1 -1
- package/dist/projection/card/Bundle.d.ts.map +1 -0
- package/dist/{card → projection/card}/Bundle.js +7 -7
- package/dist/projection/card/Bundle.js.map +1 -0
- package/dist/projection/card/Card.d.ts +21 -0
- package/dist/projection/card/Card.d.ts.map +1 -0
- package/dist/{card → projection/card}/Card.js +119 -58
- package/dist/projection/card/Card.js.map +1 -0
- package/dist/{card → projection/card}/Descriptor.d.ts +7 -7
- package/dist/projection/card/Descriptor.d.ts.map +1 -0
- package/dist/projection/card/Descriptor.js.map +1 -0
- package/dist/projection/card/admission.d.ts +20 -0
- package/dist/projection/card/admission.d.ts.map +1 -0
- package/dist/projection/card/admission.js +27 -0
- package/dist/projection/card/admission.js.map +1 -0
- package/dist/{card → projection/card}/diff.d.ts +3 -3
- package/dist/projection/card/diff.d.ts.map +1 -0
- package/dist/{card → projection/card}/diff.js.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} +13 -13
- 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} +14 -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} +21 -17
- 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 +6 -1
- 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 +8 -1
- 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 +6 -1
- package/dist/vocabulary/many.d.ts.map +1 -1
- package/dist/vocabulary/many.js +6 -1
- 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 +11 -2
- 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 +10 -3
- package/dist/vocabulary/optional.js.map +1 -1
- package/dist/vocabulary/primary.d.ts +1 -1
- package/dist/vocabulary/primary.d.ts.map +1 -1
- package/dist/vocabulary/primary.js +10 -5
- 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 +5 -0
- package/dist/vocabulary/readOnly.js.map +1 -1
- package/dist/vocabulary/ref.d.ts +6 -1
- package/dist/vocabulary/ref.d.ts.map +1 -1
- package/dist/vocabulary/ref.js +6 -1
- package/dist/vocabulary/ref.js.map +1 -1
- package/dist/vocabulary/text.d.ts +6 -1
- package/dist/vocabulary/text.d.ts.map +1 -1
- package/dist/vocabulary/text.js +13 -2
- 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 +8 -4
- 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 +21 -11
- 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 +5 -0
- package/dist/vocabulary/writeOnly.js.map +1 -1
- package/package.json +1 -1
- package/src/Schema.ts +208 -0
- package/src/SchemaDefinition.ts +257 -0
- package/src/SchemaDerivation.ts +44 -0
- package/src/{schema/SchemaView.ts → SchemaView.ts} +9 -9
- package/src/axis/Axis.ts +2 -2
- package/src/axis/boundary/Boundaries.ts +25 -32
- package/src/axis/boundary/Boundary.ts +23 -10
- package/src/axis/boundary/BoundaryAxis.ts +4 -4
- package/src/axis/lifecycle/Clock.ts +1 -1
- package/src/axis/lifecycle/Generators.ts +12 -29
- package/src/axis/lifecycle/LifecycleAxis.ts +12 -7
- package/src/axis/lifecycle/apply.ts +30 -15
- package/src/axis/role/Relation.ts +6 -5
- package/src/axis/role/Role.ts +16 -20
- package/src/axis/role/RoleAxis.ts +28 -41
- package/src/axis/shape/Formats.ts +9 -11
- package/src/axis/shape/Shape.ts +18 -18
- package/src/entity/EntityAdapterSet.ts +81 -0
- package/src/entity/EntityAdapters.ts +8 -0
- package/src/entity/EntityDeclarations.ts +16 -0
- package/src/entity.ts +8 -3
- package/src/field/Field.ts +61 -0
- package/src/field/FieldSet.ts +75 -0
- package/src/index.ts +50 -28
- package/src/lib/Registry.ts +37 -0
- package/src/{utils.ts → lib/utils.ts} +3 -0
- package/src/projection/Cases.ts +176 -0
- package/src/projection/Visibility.ts +6 -2
- package/src/{card → projection/card}/Bundle.ts +9 -9
- package/src/projection/card/Card.ts +342 -0
- package/src/{card → projection/card}/Descriptor.ts +7 -7
- package/src/projection/card/admission.ts +40 -0
- package/src/{card → projection/card}/diff.ts +3 -3
- package/src/validator/AdapterFieldValidator.ts +40 -0
- package/src/{judge/FieldJudge.ts → validator/FieldDeclarationValidator.ts} +15 -15
- package/src/{judge/ValueJudge.ts → validator/FieldValueValidator.ts} +18 -13
- package/src/{judge/RowRefusal.ts → validator/InputRefusal.ts} +2 -4
- package/src/{judge/RowJudge.ts → validator/InputValidator.ts} +27 -20
- package/src/vocabulary/bool.ts +8 -2
- package/src/vocabulary/created.ts +7 -2
- package/src/vocabulary/date.ts +6 -1
- package/src/vocabulary/email.ts +6 -1
- package/src/vocabulary/immutable.ts +12 -4
- package/src/vocabulary/indexed.ts +9 -2
- package/src/vocabulary/json.ts +13 -6
- package/src/vocabulary/list.ts +10 -2
- package/src/vocabulary/many.ts +9 -2
- package/src/vocabulary/nullable.ts +13 -5
- package/src/vocabulary/number.ts +13 -3
- package/src/vocabulary/oneOf.ts +11 -3
- package/src/vocabulary/optional.ts +16 -6
- package/src/vocabulary/primary.ts +10 -5
- package/src/vocabulary/readOnly.ts +12 -4
- package/src/vocabulary/ref.ts +10 -2
- package/src/vocabulary/text.ts +15 -3
- package/src/vocabulary/unique.ts +10 -9
- package/src/vocabulary/updated.ts +6 -1
- package/src/vocabulary/url.ts +6 -1
- package/src/vocabulary/vocabulary.ts +21 -12
- package/src/vocabulary/writeOnly.ts +12 -4
- package/dist/EntityAdapters.d.ts +0 -28
- package/dist/EntityAdapters.d.ts.map +0 -1
- package/dist/EntityAdapters.js +0 -75
- package/dist/EntityAdapters.js.map +0 -1
- package/dist/EntityDeclarations.d.ts.map +0 -1
- package/dist/EntityDeclarations.js.map +0 -1
- package/dist/card/Bundle.d.ts.map +0 -1
- package/dist/card/Bundle.js.map +0 -1
- package/dist/card/Card.d.ts +0 -27
- package/dist/card/Card.d.ts.map +0 -1
- package/dist/card/Card.js.map +0 -1
- package/dist/card/Descriptor.d.ts.map +0 -1
- package/dist/card/Descriptor.js.map +0 -1
- package/dist/card/EntityTypeSource.d.ts +0 -12
- package/dist/card/EntityTypeSource.d.ts.map +0 -1
- package/dist/card/EntityTypeSource.js +0 -78
- package/dist/card/EntityTypeSource.js.map +0 -1
- package/dist/card/FacadeTypeSource.d.ts +0 -19
- package/dist/card/FacadeTypeSource.d.ts.map +0 -1
- package/dist/card/FacadeTypeSource.js +0 -40
- package/dist/card/FacadeTypeSource.js.map +0 -1
- package/dist/card/admission.d.ts +0 -9
- package/dist/card/admission.d.ts.map +0 -1
- package/dist/card/admission.js +0 -16
- package/dist/card/admission.js.map +0 -1
- package/dist/card/diff.d.ts.map +0 -1
- package/dist/constraint/FieldGroup.d.ts +0 -21
- package/dist/constraint/FieldGroup.d.ts.map +0 -1
- package/dist/constraint/FieldGroup.js +0 -65
- package/dist/constraint/FieldGroup.js.map +0 -1
- package/dist/constraint/Unique.d.ts +0 -4
- package/dist/constraint/Unique.d.ts.map +0 -1
- package/dist/constraint/Unique.js +0 -4
- package/dist/constraint/Unique.js.map +0 -1
- package/dist/fields/Field.d.ts.map +0 -1
- package/dist/fields/Field.js +0 -52
- package/dist/fields/Field.js.map +0 -1
- package/dist/fields/FieldSet.d.ts +0 -28
- package/dist/fields/FieldSet.d.ts.map +0 -1
- package/dist/fields/FieldSet.js +0 -55
- package/dist/fields/FieldSet.js.map +0 -1
- package/dist/judge/Cases.d.ts +0 -50
- package/dist/judge/Cases.d.ts.map +0 -1
- package/dist/judge/Cases.js +0 -108
- package/dist/judge/Cases.js.map +0 -1
- 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/ValueForm.d.ts +0 -3
- package/dist/judge/ValueForm.d.ts.map +0 -1
- package/dist/judge/ValueForm.js +0 -3
- package/dist/judge/ValueForm.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/schema/Schema.d.ts.map +0 -1
- package/dist/schema/Schema.js +0 -150
- 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 -46
- package/dist/schema/SchemaDerivation.js.map +0 -1
- package/dist/schema/SchemaView.d.ts.map +0 -1
- package/dist/utils.d.ts.map +0 -1
- package/dist/utils.js.map +0 -1
- package/src/EntityAdapters.ts +0 -100
- package/src/EntityDeclarations.ts +0 -19
- package/src/card/Card.ts +0 -256
- package/src/card/EntityTypeSource.ts +0 -90
- package/src/card/FacadeTypeSource.ts +0 -55
- package/src/card/admission.ts +0 -25
- package/src/constraint/FieldGroup.ts +0 -91
- package/src/constraint/Unique.ts +0 -3
- package/src/fields/Field.ts +0 -80
- package/src/fields/FieldSet.ts +0 -62
- package/src/judge/Cases.ts +0 -139
- package/src/judge/ValueForm.ts +0 -7
- package/src/judge/options.ts +0 -3
- package/src/projection/SchemaOrCard.ts +0 -18
- package/src/schema/Schema.ts +0 -197
- package/src/schema/SchemaDefinition.ts +0 -120
- package/src/schema/SchemaDerivation.ts +0 -57
- /package/dist/{schema/SchemaView.js → SchemaView.js} +0 -0
- /package/dist/{EntityDeclarations.js → entity/EntityDeclarations.js} +0 -0
- /package/dist/{card → projection/card}/Descriptor.js +0 -0
- /package/dist/{card → projection/card}/diff.js +0 -0
- /package/src/{judge/result.ts → validation.ts} +0 -0
|
@@ -1,31 +1,41 @@
|
|
|
1
1
|
import { EXTENSION_SLOTS } from '../axis/Axis.js';
|
|
2
2
|
import { dequal } from 'dequal';
|
|
3
3
|
const MEMBER_SLOTS = [...EXTENSION_SLOTS, 'meta'];
|
|
4
|
+
/**
|
|
5
|
+
* So a word is one statement about a field, not a rebuilt field.
|
|
6
|
+
* FR : pour qu'un mot soit une affirmation sur un champ, pas un champ reconstruit.
|
|
7
|
+
* `vocabulary('indexed', () => ({ role: { index: true } }))`
|
|
8
|
+
*/
|
|
4
9
|
export function vocabulary(name, states) {
|
|
5
10
|
return (field) => field.with(merge(name, field, states(field)));
|
|
6
11
|
}
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
12
|
+
/**
|
|
13
|
+
* So two words that state the same member differently refuse instead of one winning.
|
|
14
|
+
* FR : pour que deux mots contredisant un même membre refusent, plutôt qu'un l'emporte.
|
|
15
|
+
* `readOnly(writeOnly(text()))` → both close a different side, so both apply
|
|
16
|
+
*/
|
|
17
|
+
function merge(name, field, given) {
|
|
18
|
+
const merged = {};
|
|
19
|
+
if ('shape' in given)
|
|
20
|
+
merged.shape = given.shape;
|
|
11
21
|
for (const slot of MEMBER_SLOTS) {
|
|
12
|
-
const members =
|
|
22
|
+
const members = given[slot];
|
|
13
23
|
if (members === undefined)
|
|
14
24
|
continue;
|
|
15
|
-
const
|
|
16
|
-
if (typeof members !== 'object' || members === null || typeof
|
|
17
|
-
|
|
25
|
+
const already = field[slot];
|
|
26
|
+
if (typeof members !== 'object' || members === null || typeof already !== 'object') {
|
|
27
|
+
merged[slot] = members;
|
|
18
28
|
continue;
|
|
19
29
|
}
|
|
20
30
|
for (const [member, value] of Object.entries(members)) {
|
|
21
|
-
const previous =
|
|
31
|
+
const previous = already?.[member];
|
|
22
32
|
if (previous === undefined || dequal(previous, value))
|
|
23
33
|
continue;
|
|
24
34
|
throw new Error(`vocabulary: \`${name}\` states ${slot}.${member} = ${JSON.stringify(value)}, but the ` +
|
|
25
35
|
`field already states ${JSON.stringify(previous)}. Apply one or the other, not both.`);
|
|
26
36
|
}
|
|
27
|
-
|
|
37
|
+
merged[slot] = { ...already, ...members };
|
|
28
38
|
}
|
|
29
|
-
return
|
|
39
|
+
return merged;
|
|
30
40
|
}
|
|
31
41
|
//# sourceMappingURL=vocabulary.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vocabulary.js","sourceRoot":"","sources":["../../src/vocabulary/vocabulary.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,MAAM,YAAY,GAAG,CAAC,GAAG,eAAe,EAAE,MAAM,CAAU,CAAC;AAE3D,MAAM,UAAU,UAAU,CACxB,IAAY,EACZ,MAAwC;IAExC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC;AAID,SAAS,KAAK,CAAC,IAAY,EAAE,KAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"vocabulary.js","sourceRoot":"","sources":["../../src/vocabulary/vocabulary.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,MAAM,YAAY,GAAG,CAAC,GAAG,eAAe,EAAE,MAAM,CAAU,CAAC;AAE3D;;;;GAIG;AACH,MAAM,UAAU,UAAU,CACxB,IAAY,EACZ,MAAwC;IAExC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC;AAID;;;;GAIG;AACH,SAAS,KAAK,CAAC,IAAY,EAAE,KAAY,EAAE,KAAqB;IAC9D,MAAM,MAAM,GAA4B,EAAE,CAAC;IAC3C,IAAI,OAAO,IAAI,KAAK;QAAE,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IAEjD,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QAC5B,IAAI,OAAO,KAAK,SAAS;YAAE,SAAS;QACpC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAwC,CAAC;QACnE,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YACnF,MAAM,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC;YACvB,SAAS;QACX,CAAC;QACD,KAAK,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YACtD,MAAM,QAAQ,GAAG,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC;YACnC,IAAI,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC;gBAAE,SAAS;YAChE,MAAM,IAAI,KAAK,CACb,iBAAiB,IAAI,aAAa,IAAI,IAAI,MAAM,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,YAAY;gBACrF,wBAAwB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,qCAAqC,CACxF,CAAC;QACJ,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,EAAE,GAAG,OAAO,EAAE,CAAC;IAC5C,CAAC;IACD,OAAO,MAAwB,CAAC;AAClC,CAAC"}
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
-
import { Field } from '../
|
|
1
|
+
import { Field } from '../field/Field.js';
|
|
2
|
+
/**
|
|
3
|
+
* So a secret leaves no response, the dual of `readOnly` on the same axis.
|
|
4
|
+
* FR : pour qu'un secret ne reparte dans aucune réponse, dual de `readOnly`.
|
|
5
|
+
* `writeOnly(text())` → `boundary.out` is `'closed'`
|
|
6
|
+
*/
|
|
2
7
|
export declare const writeOnly: <T>(field: Field<T>) => Field<T>;
|
|
3
8
|
//# sourceMappingURL=writeOnly.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"writeOnly.d.ts","sourceRoot":"","sources":["../../src/vocabulary/writeOnly.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"writeOnly.d.ts","sourceRoot":"","sources":["../../src/vocabulary/writeOnly.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE1C;;;;GAIG;AACH,eAAO,MAAM,SAAS,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAKtD,CAAC"}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { vocabulary } from './vocabulary.js';
|
|
2
2
|
import { Boundary } from '../axis/boundary/Boundary.js';
|
|
3
|
+
/**
|
|
4
|
+
* So a secret leaves no response, the dual of `readOnly` on the same axis.
|
|
5
|
+
* FR : pour qu'un secret ne reparte dans aucune réponse, dual de `readOnly`.
|
|
6
|
+
* `writeOnly(text())` → `boundary.out` is `'closed'`
|
|
7
|
+
*/
|
|
3
8
|
export const writeOnly = vocabulary('writeOnly', (field) => ({
|
|
4
9
|
boundary: Boundary.declared(field).with({ out: 'closed' }),
|
|
5
10
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"writeOnly.js","sourceRoot":"","sources":["../../src/vocabulary/writeOnly.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAGxD,MAAM,CAAC,MAAM,SAAS,GAAqC,UAAU,
|
|
1
|
+
{"version":3,"file":"writeOnly.js","sourceRoot":"","sources":["../../src/vocabulary/writeOnly.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAGxD;;;;GAIG;AACH,MAAM,CAAC,MAAM,SAAS,GAAqC,UAAU,CACnE,WAAW,EACX,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACV,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC;CAC3D,CAAC,CACH,CAAC"}
|
package/package.json
CHANGED
package/src/Schema.ts
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { Boundary } from './axis/boundary/Boundary.js';
|
|
2
|
+
import { type Fields } from './field/Field.js';
|
|
3
|
+
import {
|
|
4
|
+
type CompositeUnique,
|
|
5
|
+
type EntityDeclarations,
|
|
6
|
+
type PreviousNames,
|
|
7
|
+
} from './entity/EntityDeclarations.js';
|
|
8
|
+
import { type EntityAdapters } from './entity/EntityAdapters.js';
|
|
9
|
+
import { InputValidator } from './validator/InputValidator.js';
|
|
10
|
+
import { SchemaDerivation } from './SchemaDerivation.js';
|
|
11
|
+
import { SchemaDefinition, type SchemaConstraints } from './SchemaDefinition.js';
|
|
12
|
+
import { type ValidateOptions } from './validator/InputValidator.js';
|
|
13
|
+
import type { StandardSchemaV1 } from './projection/standard.js';
|
|
14
|
+
import type { PartialValues, Values, SchemaView } from './SchemaView.js';
|
|
15
|
+
|
|
16
|
+
export const ANONYMOUS_SCHEMA_NAME = 'Schema';
|
|
17
|
+
|
|
18
|
+
export interface SchemaConstructor<TFields extends Fields> extends SchemaView<TFields> {
|
|
19
|
+
new (data: PartialValues<TFields>): Values<TFields>;
|
|
20
|
+
readonly '~standard': StandardSchemaV1.Props<Record<string, unknown>, Values<TFields>>;
|
|
21
|
+
readonly derivation?: SchemaDerivation;
|
|
22
|
+
readonly previous?: PreviousNames<TFields>;
|
|
23
|
+
readonly anchored?: boolean;
|
|
24
|
+
from(data: Record<string, unknown>): Values<TFields>;
|
|
25
|
+
pick<K extends string & keyof TFields>(
|
|
26
|
+
...keys: K[]
|
|
27
|
+
): SchemaConstructor<Pick<TFields, K>>;
|
|
28
|
+
omit<K extends string & keyof TFields>(
|
|
29
|
+
...keys: K[]
|
|
30
|
+
): SchemaConstructor<Omit<TFields, K>>;
|
|
31
|
+
partial(): SchemaConstructor<TFields>;
|
|
32
|
+
extend<E extends Fields>(extra: E): SchemaConstructor<TFields & E>;
|
|
33
|
+
declares(declarations: EntityDeclarations<TFields>): SchemaConstructor<TFields>;
|
|
34
|
+
anchor(): SchemaConstructor<TFields>;
|
|
35
|
+
named(name: string): SchemaConstructor<TFields>;
|
|
36
|
+
rename(
|
|
37
|
+
mapping: Partial<Record<string & keyof TFields, string>>,
|
|
38
|
+
): SchemaConstructor<Fields>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export class Schema {
|
|
42
|
+
/** The one place a schema holds what it is. The readings below are its projections. */
|
|
43
|
+
static definition: SchemaDefinition = SchemaDefinition.of({ fields: {} });
|
|
44
|
+
|
|
45
|
+
static get fields(): Fields {
|
|
46
|
+
return this.definition.fields;
|
|
47
|
+
}
|
|
48
|
+
/** An entry survives every derivation that kept its field: `Post.pick('body').adapters`. */
|
|
49
|
+
static get adapters(): EntityAdapters<Fields> {
|
|
50
|
+
return this.definition.adapterSet.adapters;
|
|
51
|
+
}
|
|
52
|
+
static get opts(): ValidateOptions {
|
|
53
|
+
return this.definition.opts;
|
|
54
|
+
}
|
|
55
|
+
static get derivation(): SchemaDerivation | undefined {
|
|
56
|
+
return this.definition.derivation;
|
|
57
|
+
}
|
|
58
|
+
static get previous(): PreviousNames<Fields> | undefined {
|
|
59
|
+
return this.definition.previous;
|
|
60
|
+
}
|
|
61
|
+
/** An anchor holds rows of its own; a derivation borrows them. */
|
|
62
|
+
static get anchored(): boolean {
|
|
63
|
+
return this.definition.anchored;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
constructor(data?: Record<string, unknown>) {
|
|
67
|
+
if (!data) return;
|
|
68
|
+
for (const [key, value] of Object.entries(data)) {
|
|
69
|
+
Object.defineProperty(this, key, {
|
|
70
|
+
value,
|
|
71
|
+
writable: true,
|
|
72
|
+
enumerable: true,
|
|
73
|
+
configurable: true,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
static getFields() {
|
|
79
|
+
return this.fields;
|
|
80
|
+
}
|
|
81
|
+
static getAdapters() {
|
|
82
|
+
return this.adapters;
|
|
83
|
+
}
|
|
84
|
+
static getUnique(): CompositeUnique<Fields> | undefined {
|
|
85
|
+
return this.definition.constraints.unique;
|
|
86
|
+
}
|
|
87
|
+
static getOpts() {
|
|
88
|
+
return this.opts;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
static validate(input: unknown) {
|
|
92
|
+
return InputValidator.of(this.fields, this.opts).validate(input);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
static from(data: Record<string, unknown>) {
|
|
96
|
+
const row: Record<string, unknown> = {};
|
|
97
|
+
for (const [key, field] of Object.entries(this.fields)) {
|
|
98
|
+
if (!(key in data)) continue;
|
|
99
|
+
const value = data[key];
|
|
100
|
+
if (value === null || value === undefined) {
|
|
101
|
+
row[key] = value;
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
const decoded = Boundary.of(field).decode(value);
|
|
105
|
+
row[key] = 'error' in decoded ? value : decoded.value;
|
|
106
|
+
}
|
|
107
|
+
return row;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
static get ['~standard'](): StandardSchemaV1.Props<Record<string, unknown>> {
|
|
111
|
+
const { fields, opts } = this;
|
|
112
|
+
return {
|
|
113
|
+
version: 1,
|
|
114
|
+
vendor: 'fougere',
|
|
115
|
+
validate(value: unknown) {
|
|
116
|
+
const verdict = InputValidator.of(fields, opts).validate(value);
|
|
117
|
+
if (verdict.success) return { value: verdict.data };
|
|
118
|
+
return {
|
|
119
|
+
issues: verdict.errors.map((e) => ({
|
|
120
|
+
message: e.message,
|
|
121
|
+
path: e.path && e.path !== '.' ? [{ key: e.path }] : undefined,
|
|
122
|
+
})),
|
|
123
|
+
};
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
static pick(...keys: string[]) {
|
|
129
|
+
return Schema.subclass(this.definition.pick(keys, this));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
static omit(...keys: string[]) {
|
|
133
|
+
return Schema.subclass(this.definition.omit(keys, this));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
static rename(mapping: Record<string, string>) {
|
|
137
|
+
return Schema.subclass(this.definition.rename(mapping, this));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
static declares(declarations: EntityDeclarations<Fields>) {
|
|
141
|
+
return Schema.subclass(this.definition.declaring(declarations));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
static anchor() {
|
|
145
|
+
return Schema.subclass(this.definition.anchoring());
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
static partial() {
|
|
149
|
+
return Schema.subclass(this.definition.patched(this));
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
static extend(extra: Fields) {
|
|
153
|
+
return Schema.subclass(this.definition.extended(extra, this));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
static named(name: string) {
|
|
157
|
+
if (!/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name)) {
|
|
158
|
+
throw new Error(`named(): \`${name}\` is not a valid class name.`);
|
|
159
|
+
}
|
|
160
|
+
if (this.name !== ANONYMOUS_SCHEMA_NAME) {
|
|
161
|
+
throw new Error(
|
|
162
|
+
`named(): \`${this.name}\` is already named by its class declaration.`,
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
Object.defineProperty(this, 'name', { value: name, configurable: true });
|
|
166
|
+
return this;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
static compose<T extends SchemaView[]>(...sources: T): SchemaConstructor<Merged<T>> {
|
|
170
|
+
return Schema.subclass(
|
|
171
|
+
SchemaDefinition.merged(sources),
|
|
172
|
+
) as unknown as SchemaConstructor<Merged<T>>;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
static of<TFields extends Fields>(declaration: {
|
|
176
|
+
fields: TFields;
|
|
177
|
+
derivation?: SchemaDerivation;
|
|
178
|
+
adapters?: EntityAdapters<TFields>;
|
|
179
|
+
opts?: ValidateOptions;
|
|
180
|
+
previous?: PreviousNames<TFields>;
|
|
181
|
+
anchored?: boolean;
|
|
182
|
+
constraints?: SchemaConstraints;
|
|
183
|
+
}): SchemaConstructor<TFields> {
|
|
184
|
+
return Schema.subclass(
|
|
185
|
+
SchemaDefinition.of(declaration),
|
|
186
|
+
) as unknown as SchemaConstructor<TFields>;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
private static subclass(definition: SchemaDefinition): SchemaConstructor<Fields> {
|
|
190
|
+
class Derived extends Schema {}
|
|
191
|
+
Derived.definition = definition;
|
|
192
|
+
Object.defineProperty(Derived, 'name', {
|
|
193
|
+
value: ANONYMOUS_SCHEMA_NAME,
|
|
194
|
+
configurable: true,
|
|
195
|
+
});
|
|
196
|
+
return Derived as unknown as SchemaConstructor<Fields>;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends (
|
|
201
|
+
k: infer I,
|
|
202
|
+
) => void
|
|
203
|
+
? I
|
|
204
|
+
: never;
|
|
205
|
+
type Merged<T extends SchemaView[]> = UnionToIntersection<
|
|
206
|
+
T[number] extends { getFields(): infer F } ? F : Fields
|
|
207
|
+
> &
|
|
208
|
+
Fields;
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { type Fields } from './field/Field.js';
|
|
2
|
+
import { FieldSet, deduplicated } from './field/FieldSet.js';
|
|
3
|
+
import {
|
|
4
|
+
type CompositeUnique,
|
|
5
|
+
type EntityDeclarations,
|
|
6
|
+
type PreviousNames,
|
|
7
|
+
} from './entity/EntityDeclarations.js';
|
|
8
|
+
import { type EntityAdapters } from './entity/EntityAdapters.js';
|
|
9
|
+
import { EntityAdapterSet } from './entity/EntityAdapterSet.js';
|
|
10
|
+
import { SchemaDerivation } from './SchemaDerivation.js';
|
|
11
|
+
import { type ValidateOptions } from './validator/InputValidator.js';
|
|
12
|
+
import type { SchemaView } from './SchemaView.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* What a schema constrains beyond any single field.
|
|
16
|
+
*
|
|
17
|
+
* `unique` is the one member today. It sits under an owner rather than beside `fields`
|
|
18
|
+
* and `opts` because the next rule spanning two fields — a check, an exclusion — is a
|
|
19
|
+
* member here, not an eighth positional argument in a list that has already lost one.
|
|
20
|
+
*/
|
|
21
|
+
export interface SchemaConstraints<TFields extends Fields = Fields> {
|
|
22
|
+
readonly unique?: CompositeUnique<TFields>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Everything a definition is made of, every member required.
|
|
27
|
+
*
|
|
28
|
+
* A transformation states what it keeps AND what it clears — `previous: undefined` and
|
|
29
|
+
* `anchored: false` are the two a derivation decides, and positionally they were an
|
|
30
|
+
* `undefined` and a `false` a reader had to count arguments to name.
|
|
31
|
+
*/
|
|
32
|
+
interface SchemaState {
|
|
33
|
+
fields: Fields;
|
|
34
|
+
adapterSet: EntityAdapterSet;
|
|
35
|
+
opts: ValidateOptions;
|
|
36
|
+
previous: PreviousNames<Fields> | undefined;
|
|
37
|
+
derivation: SchemaDerivation | undefined;
|
|
38
|
+
anchored: boolean;
|
|
39
|
+
constraints: SchemaConstraints;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** The keys a derivation keeps, in the order it keeps them, under the names they take. */
|
|
43
|
+
type Renaming = ReadonlyMap<string, string>;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Everything a schema IS, apart from being a class whose instances are rows.
|
|
47
|
+
*
|
|
48
|
+
* The members used to be that many statics assigned side by side, and every derivation
|
|
49
|
+
* re-threaded them by hand — which is how one of them came to be dropped from a list
|
|
50
|
+
* without anyone noticing. A transformation here returns a COMPLETE definition or it does
|
|
51
|
+
* not compile, so no gesture can mix the fields of one with the options of another.
|
|
52
|
+
*
|
|
53
|
+
* Internal: it is not exported from the package and never appears on `SchemaConstructor`.
|
|
54
|
+
* A user derives with `Order.pick(…)`, never `Order.definition.pick(…)`.
|
|
55
|
+
*/
|
|
56
|
+
export class SchemaDefinition {
|
|
57
|
+
readonly fields: Fields;
|
|
58
|
+
readonly adapterSet: EntityAdapterSet;
|
|
59
|
+
readonly opts: ValidateOptions;
|
|
60
|
+
readonly previous: PreviousNames<Fields> | undefined;
|
|
61
|
+
readonly derivation: SchemaDerivation | undefined;
|
|
62
|
+
readonly anchored: boolean;
|
|
63
|
+
readonly constraints: SchemaConstraints;
|
|
64
|
+
|
|
65
|
+
private constructor(state: SchemaState) {
|
|
66
|
+
this.fields = state.fields;
|
|
67
|
+
this.adapterSet = state.adapterSet;
|
|
68
|
+
this.opts = state.opts;
|
|
69
|
+
this.previous = state.previous;
|
|
70
|
+
this.derivation = state.derivation;
|
|
71
|
+
this.anchored = state.anchored;
|
|
72
|
+
this.constraints = state.constraints;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Built complete or not at all — no static assigned on the side. */
|
|
76
|
+
static of(declaration: {
|
|
77
|
+
fields: Fields;
|
|
78
|
+
adapters?: EntityAdapters<Fields>;
|
|
79
|
+
opts?: ValidateOptions;
|
|
80
|
+
previous?: PreviousNames<Fields>;
|
|
81
|
+
derivation?: SchemaDerivation;
|
|
82
|
+
anchored?: boolean;
|
|
83
|
+
constraints?: SchemaConstraints;
|
|
84
|
+
}): SchemaDefinition {
|
|
85
|
+
return new SchemaDefinition({
|
|
86
|
+
fields: declaration.fields,
|
|
87
|
+
adapterSet: EntityAdapterSet.of(declaration.adapters),
|
|
88
|
+
opts: declaration.opts ?? {},
|
|
89
|
+
previous: declaration.previous,
|
|
90
|
+
derivation: declaration.derivation,
|
|
91
|
+
anchored: declaration.anchored ?? false,
|
|
92
|
+
constraints: declaration.constraints ?? {},
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
declaring(declarations: EntityDeclarations<Fields>): SchemaDefinition {
|
|
97
|
+
const addressed = EntityAdapterSet.of(declarations.adapters).fieldNames;
|
|
98
|
+
this.assertKnown('declares', [
|
|
99
|
+
...addressed,
|
|
100
|
+
...Object.keys(declarations.previous ?? {}),
|
|
101
|
+
]);
|
|
102
|
+
const declared = FieldSet.declaring(this.fields, declarations.unique);
|
|
103
|
+
|
|
104
|
+
return new SchemaDefinition({
|
|
105
|
+
fields: declared.fields,
|
|
106
|
+
adapterSet: EntityAdapterSet.merged([
|
|
107
|
+
this.adapterSet,
|
|
108
|
+
EntityAdapterSet.of(declarations.adapters),
|
|
109
|
+
]),
|
|
110
|
+
opts: this.opts,
|
|
111
|
+
previous: declarations.previous ?? this.previous,
|
|
112
|
+
derivation: this.derivation,
|
|
113
|
+
anchored: this.anchored,
|
|
114
|
+
constraints:
|
|
115
|
+
declarations.unique === undefined ? this.constraints : { unique: declared.unique },
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
anchoring(): SchemaDefinition {
|
|
120
|
+
return new SchemaDefinition({
|
|
121
|
+
fields: this.fields,
|
|
122
|
+
adapterSet: this.adapterSet,
|
|
123
|
+
opts: this.opts,
|
|
124
|
+
previous: this.previous,
|
|
125
|
+
derivation: this.derivation,
|
|
126
|
+
anchored: true,
|
|
127
|
+
constraints: this.constraints,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
pick(keys: readonly string[], root: SchemaView): SchemaDefinition {
|
|
132
|
+
this.assertKnown('pick', keys);
|
|
133
|
+
|
|
134
|
+
return this.renaming(new Map(keys.map((key) => [key, key])), root);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
omit(keys: readonly string[], root: SchemaView): SchemaDefinition {
|
|
138
|
+
this.assertKnown('omit', keys);
|
|
139
|
+
const kept = Object.keys(this.fields).filter((key) => !keys.includes(key));
|
|
140
|
+
|
|
141
|
+
return this.renaming(new Map(kept.map((key) => [key, key])), root);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
rename(mapping: Record<string, string>, root: SchemaView): SchemaDefinition {
|
|
145
|
+
this.assertKnown('rename', Object.keys(mapping));
|
|
146
|
+
const here = Object.keys(this.fields).map((key) => [key, mapping[key] ?? key] as const);
|
|
147
|
+
|
|
148
|
+
return this.renaming(new Map(here), root);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* `pick`, `omit` and `rename` are one gesture, and the renaming IS that gesture: the
|
|
153
|
+
* fields it keeps and everything else addressed by field name are both read from it.
|
|
154
|
+
*/
|
|
155
|
+
private renaming(kept: Renaming, root: SchemaView): SchemaDefinition {
|
|
156
|
+
const fields: Fields = {};
|
|
157
|
+
for (const [from, to] of kept) {
|
|
158
|
+
const field = this.fields[from];
|
|
159
|
+
if (field) fields[to] = field;
|
|
160
|
+
}
|
|
161
|
+
const nameOf = (key: string) => kept.get(key);
|
|
162
|
+
|
|
163
|
+
return new SchemaDefinition({
|
|
164
|
+
fields,
|
|
165
|
+
adapterSet: this.adapterSet.rename(nameOf),
|
|
166
|
+
opts: this.opts,
|
|
167
|
+
previous: undefined,
|
|
168
|
+
derivation: this.origin(root).rename(nameOf),
|
|
169
|
+
anchored: false,
|
|
170
|
+
constraints: this.constraintsRenamed(nameOf),
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** One member gone and the group is gone: it constrained a pair that no longer exists. */
|
|
175
|
+
private constraintsRenamed(
|
|
176
|
+
transform: (key: string) => string | undefined,
|
|
177
|
+
): SchemaConstraints {
|
|
178
|
+
if (!this.constraints.unique) return this.constraints;
|
|
179
|
+
const kept: string[][] = [];
|
|
180
|
+
for (const group of this.constraints.unique) {
|
|
181
|
+
const renamed = group.map(transform);
|
|
182
|
+
if (renamed.every((key): key is string => key !== undefined)) kept.push(renamed);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return { unique: deduplicated(kept) as CompositeUnique<Fields> | undefined };
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
patched(root: SchemaView): SchemaDefinition {
|
|
189
|
+
return new SchemaDefinition({
|
|
190
|
+
fields: { ...this.fields },
|
|
191
|
+
adapterSet: this.adapterSet,
|
|
192
|
+
opts: { ...this.opts, patch: true },
|
|
193
|
+
previous: undefined,
|
|
194
|
+
derivation: this.origin(root),
|
|
195
|
+
anchored: false,
|
|
196
|
+
constraints: this.constraints,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** An added field does not pretend to come from the root, which never declared it. */
|
|
201
|
+
extended(extra: Fields, root: SchemaView): SchemaDefinition {
|
|
202
|
+
return new SchemaDefinition({
|
|
203
|
+
fields: { ...this.fields, ...extra },
|
|
204
|
+
adapterSet: this.adapterSet,
|
|
205
|
+
opts: this.opts,
|
|
206
|
+
previous: undefined,
|
|
207
|
+
derivation: this.origin(root),
|
|
208
|
+
anchored: false,
|
|
209
|
+
constraints: this.constraints,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/** Several schemas fold into one, which has no single origin to point at. */
|
|
214
|
+
static merged(views: readonly SchemaView[]): SchemaDefinition {
|
|
215
|
+
const fields: Fields = {};
|
|
216
|
+
let opts: ValidateOptions = {};
|
|
217
|
+
const groups: (readonly string[])[] = [];
|
|
218
|
+
for (const view of views) {
|
|
219
|
+
Object.assign(fields, view.getFields());
|
|
220
|
+
opts = { ...opts, ...view.getOpts() };
|
|
221
|
+
groups.push(...(view.getUnique() ?? []));
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return new SchemaDefinition({
|
|
225
|
+
fields,
|
|
226
|
+
adapterSet: EntityAdapterSet.merged(
|
|
227
|
+
views.map((view) => EntityAdapterSet.of(view.getAdapters())),
|
|
228
|
+
),
|
|
229
|
+
opts,
|
|
230
|
+
previous: undefined,
|
|
231
|
+
derivation: undefined,
|
|
232
|
+
anchored: false,
|
|
233
|
+
constraints: { unique: deduplicated(groups) as CompositeUnique<Fields> | undefined },
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* So a gesture naming a field that does not exist says so, and lists what there is.
|
|
239
|
+
* FR : pour qu'un geste nommant un champ inexistant le dise, et énumère ce qui existe.
|
|
240
|
+
* `pick('titel')` → `pick(): unknown field \`titel\`. This schema carries id, title, body.`
|
|
241
|
+
*/
|
|
242
|
+
private assertKnown(operation: string, keys: readonly string[]): void {
|
|
243
|
+
const strangers = keys.filter((key) => !(key in this.fields));
|
|
244
|
+
if (strangers.length === 0) return;
|
|
245
|
+
|
|
246
|
+
throw new Error(
|
|
247
|
+
`${operation}(): unknown field ${strangers.map((s) => `\`${s}\``).join(', ')}. ` +
|
|
248
|
+
`This schema carries ${Object.keys(this.fields).join(', ')}.`,
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
private origin(root: SchemaView): SchemaDerivation {
|
|
253
|
+
if (!this.anchored && this.derivation) return this.derivation;
|
|
254
|
+
|
|
255
|
+
return SchemaDerivation.first(root, this.fields);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type Fields } from './field/Field.js';
|
|
2
|
+
import type { SchemaView } from './SchemaView.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The origin is the ROOT: `Post.pick(a, b).omit(b)` answers `Post`, never the intermediate.
|
|
6
|
+
*/
|
|
7
|
+
export class SchemaDerivation {
|
|
8
|
+
private constructor(
|
|
9
|
+
readonly source: SchemaView,
|
|
10
|
+
readonly nameOf: Readonly<Record<string, string | undefined>>,
|
|
11
|
+
) {}
|
|
12
|
+
|
|
13
|
+
static first(source: SchemaView, fields: Fields): SchemaDerivation {
|
|
14
|
+
return new SchemaDerivation(
|
|
15
|
+
source,
|
|
16
|
+
Object.fromEntries(Object.keys(fields).map((key) => [key, key])),
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
rename(transform: (key: string) => string | undefined): SchemaDerivation {
|
|
21
|
+
return new SchemaDerivation(
|
|
22
|
+
this.source,
|
|
23
|
+
Object.fromEntries(
|
|
24
|
+
Object.entries(this.nameOf).map(([origin, here]) => [
|
|
25
|
+
origin,
|
|
26
|
+
here === undefined ? undefined : transform(here),
|
|
27
|
+
]),
|
|
28
|
+
),
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
get sourceName(): string {
|
|
33
|
+
return this.source.name;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Whose rows this one borrows, however many cuts away: `Post.pick('t').omit('t')` → `Post`. */
|
|
37
|
+
get anchor(): SchemaView {
|
|
38
|
+
const source = this.source;
|
|
39
|
+
|
|
40
|
+
return source.anchored !== undefined || !source.derivation
|
|
41
|
+
? source
|
|
42
|
+
: source.derivation.anchor;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import type { Field, Fields } from '
|
|
2
|
-
import type { CompositeUnique, PreviousNames } from '
|
|
3
|
-
import type { EntityAdapters } from '
|
|
4
|
-
import type { ValidationResult } from '
|
|
5
|
-
import type { ValidateOptions } from '
|
|
1
|
+
import type { Field, Fields } from './field/Field.js';
|
|
2
|
+
import type { CompositeUnique, PreviousNames } from './entity/EntityDeclarations.js';
|
|
3
|
+
import type { EntityAdapters } from './entity/EntityAdapters.js';
|
|
4
|
+
import type { ValidationResult } from './validation.js';
|
|
5
|
+
import type { ValidateOptions } from './validator/InputValidator.js';
|
|
6
6
|
import type { SchemaDerivation } from './SchemaDerivation.js';
|
|
7
7
|
|
|
8
|
-
export type
|
|
8
|
+
export type Values<TFields extends Fields> = {
|
|
9
9
|
[K in keyof TFields]: TFields[K] extends Field<infer T> ? T : never;
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
-
export type
|
|
12
|
+
export type PartialValues<TFields extends Fields> = Partial<Values<TFields>>;
|
|
13
13
|
|
|
14
14
|
export interface SchemaView<TFields extends Fields = Fields> {
|
|
15
15
|
readonly name: string;
|
|
@@ -20,8 +20,8 @@ export interface SchemaView<TFields extends Fields = Fields> {
|
|
|
20
20
|
/** Does it hold rows of its own? False on a derivation means an answer. */
|
|
21
21
|
readonly anchored?: boolean;
|
|
22
22
|
getFields(): TFields;
|
|
23
|
-
getAdapters(): EntityAdapters<TFields
|
|
23
|
+
getAdapters(): EntityAdapters<TFields>;
|
|
24
24
|
getUnique(): CompositeUnique<TFields> | undefined;
|
|
25
25
|
getOpts(): ValidateOptions;
|
|
26
|
-
validate(input: unknown): ValidationResult<
|
|
26
|
+
validate(input: unknown): ValidationResult<Values<TFields>>;
|
|
27
27
|
}
|
package/src/axis/Axis.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { roleAxis } from './role/RoleAxis.js';
|
|
2
2
|
import { lifecycleAxis } from './lifecycle/LifecycleAxis.js';
|
|
3
3
|
import { boundaryAxis } from './boundary/BoundaryAxis.js';
|
|
4
|
-
import type { ValidationError } from '../
|
|
4
|
+
import type { ValidationError } from '../validation.js';
|
|
5
5
|
|
|
6
6
|
export interface Axis<Declared = unknown, Wire = unknown> {
|
|
7
7
|
readonly slot: 'role' | 'lifecycle' | 'boundary';
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
validator(value: unknown, errors: ValidationError[]): void;
|
|
10
10
|
|
|
11
11
|
describe(value: Declared, key: string): Wire | undefined;
|
|
12
12
|
|