@fougere/schema 0.8.2-alpha.0 → 0.8.4-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/dist/Schema.d.ts +3 -6
- package/dist/Schema.d.ts.map +1 -1
- package/dist/Schema.js +9 -17
- package/dist/Schema.js.map +1 -1
- package/dist/SchemaDefinition.d.ts +24 -6
- package/dist/SchemaDefinition.d.ts.map +1 -1
- package/dist/SchemaDefinition.js +76 -44
- package/dist/SchemaDefinition.js.map +1 -1
- package/dist/SchemaView.d.ts +1 -1
- package/dist/SchemaView.d.ts.map +1 -1
- package/dist/axis/Axis.d.ts +1 -1
- package/dist/axis/Axis.d.ts.map +1 -1
- package/dist/axis/boundary/Boundaries.d.ts +5 -0
- package/dist/axis/boundary/Boundaries.d.ts.map +1 -1
- package/dist/axis/boundary/Boundaries.js.map +1 -1
- package/dist/axis/boundary/Boundary.d.ts +5 -4
- package/dist/axis/boundary/Boundary.d.ts.map +1 -1
- package/dist/axis/boundary/Boundary.js +4 -5
- package/dist/axis/boundary/Boundary.js.map +1 -1
- package/dist/axis/boundary/BoundaryAxis.js +2 -2
- package/dist/axis/boundary/BoundaryAxis.js.map +1 -1
- package/dist/axis/lifecycle/Lifecycle.d.ts +5 -3
- package/dist/axis/lifecycle/Lifecycle.d.ts.map +1 -1
- package/dist/axis/lifecycle/Lifecycle.js +5 -1
- package/dist/axis/lifecycle/Lifecycle.js.map +1 -1
- package/dist/axis/lifecycle/LifecycleAxis.js +6 -6
- package/dist/axis/lifecycle/LifecycleAxis.js.map +1 -1
- package/dist/axis/lifecycle/apply.d.ts +6 -6
- package/dist/axis/lifecycle/apply.d.ts.map +1 -1
- package/dist/axis/lifecycle/apply.js +10 -9
- package/dist/axis/lifecycle/apply.js.map +1 -1
- package/dist/axis/role/Role.d.ts +8 -5
- package/dist/axis/role/Role.d.ts.map +1 -1
- package/dist/axis/role/Role.js +7 -0
- package/dist/axis/role/Role.js.map +1 -1
- package/dist/axis/role/RoleAxis.js +9 -9
- package/dist/axis/role/RoleAxis.js.map +1 -1
- package/dist/axis/shape/Shape.d.ts +14 -0
- package/dist/axis/shape/Shape.d.ts.map +1 -1
- package/dist/axis/shape/Shape.js +43 -34
- package/dist/axis/shape/Shape.js.map +1 -1
- package/dist/entity/EntityAdapterSet.d.ts +2 -2
- package/dist/entity/EntityAdapterSet.d.ts.map +1 -1
- package/dist/entity/EntityAdapterSet.js +2 -2
- package/dist/entity/EntityAdapterSet.js.map +1 -1
- package/dist/entity.d.ts +2 -2
- package/dist/entity.js +2 -2
- package/dist/field/Field.d.ts.map +1 -1
- package/dist/field/Field.js +2 -1
- package/dist/field/Field.js.map +1 -1
- package/dist/field/FieldSet.d.ts +4 -7
- package/dist/field/FieldSet.d.ts.map +1 -1
- package/dist/field/FieldSet.js +4 -15
- package/dist/field/FieldSet.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/validation.d.ts +32 -0
- package/dist/lib/validation.d.ts.map +1 -0
- package/dist/lib/validation.js +6 -0
- package/dist/lib/validation.js.map +1 -0
- package/dist/projection/Cases.d.ts +1 -1
- package/dist/projection/Cases.d.ts.map +1 -1
- package/dist/projection/Cases.js +11 -7
- package/dist/projection/Cases.js.map +1 -1
- package/dist/projection/Visibility.js +1 -1
- package/dist/projection/Visibility.js.map +1 -1
- package/dist/projection/card/Bundle.d.ts.map +1 -1
- package/dist/projection/card/Bundle.js +1 -4
- package/dist/projection/card/Bundle.js.map +1 -1
- package/dist/projection/card/Card.d.ts +7 -1
- package/dist/projection/card/Card.d.ts.map +1 -1
- package/dist/projection/card/Card.js +25 -133
- package/dist/projection/card/Card.js.map +1 -1
- package/dist/projection/card/Descriptor.d.ts +2 -2
- package/dist/projection/card/Descriptor.d.ts.map +1 -1
- package/dist/projection/card/admission.d.ts +12 -11
- package/dist/projection/card/admission.d.ts.map +1 -1
- package/dist/projection/card/admission.js +13 -11
- package/dist/projection/card/admission.js.map +1 -1
- package/dist/projection/card/diff.d.ts +7 -1
- package/dist/projection/card/diff.d.ts.map +1 -1
- package/dist/projection/card/diff.js +111 -1
- package/dist/projection/card/diff.js.map +1 -1
- package/dist/validator/FieldDeclarationValidator.d.ts +1 -1
- package/dist/validator/FieldDeclarationValidator.d.ts.map +1 -1
- package/dist/validator/FieldDeclarationValidator.js +4 -4
- package/dist/validator/FieldDeclarationValidator.js.map +1 -1
- package/dist/validator/FieldValueValidator.d.ts +6 -1
- package/dist/validator/FieldValueValidator.d.ts.map +1 -1
- package/dist/validator/FieldValueValidator.js +36 -7
- package/dist/validator/FieldValueValidator.js.map +1 -1
- package/dist/validator/InputValidator.d.ts +1 -1
- package/dist/validator/InputValidator.d.ts.map +1 -1
- package/dist/validator/InputValidator.js +8 -18
- package/dist/validator/InputValidator.js.map +1 -1
- package/dist/vocabulary/preset/created.d.ts +0 -5
- package/dist/vocabulary/preset/created.d.ts.map +1 -1
- package/dist/vocabulary/preset/created.js +0 -5
- package/dist/vocabulary/preset/created.js.map +1 -1
- package/dist/vocabulary/preset/email.d.ts +0 -5
- package/dist/vocabulary/preset/email.d.ts.map +1 -1
- package/dist/vocabulary/preset/email.js +0 -5
- package/dist/vocabulary/preset/email.js.map +1 -1
- package/dist/vocabulary/preset/updated.d.ts +0 -5
- package/dist/vocabulary/preset/updated.d.ts.map +1 -1
- package/dist/vocabulary/preset/updated.js +0 -5
- package/dist/vocabulary/preset/updated.js.map +1 -1
- package/dist/vocabulary/preset/url.d.ts +0 -5
- package/dist/vocabulary/preset/url.d.ts.map +1 -1
- package/dist/vocabulary/preset/url.js +0 -5
- package/dist/vocabulary/preset/url.js.map +1 -1
- package/dist/vocabulary/primitive/bool.d.ts +0 -5
- package/dist/vocabulary/primitive/bool.d.ts.map +1 -1
- package/dist/vocabulary/primitive/bool.js +0 -5
- package/dist/vocabulary/primitive/bool.js.map +1 -1
- package/dist/vocabulary/primitive/date.d.ts +3 -3
- package/dist/vocabulary/primitive/date.js +3 -3
- package/dist/vocabulary/primitive/json.js +3 -3
- package/dist/vocabulary/primitive/list.d.ts +3 -3
- package/dist/vocabulary/primitive/list.js +3 -3
- package/dist/vocabulary/primitive/many.d.ts +3 -3
- package/dist/vocabulary/primitive/many.js +3 -3
- package/dist/vocabulary/primitive/number.d.ts +0 -5
- package/dist/vocabulary/primitive/number.d.ts.map +1 -1
- package/dist/vocabulary/primitive/number.js +0 -5
- package/dist/vocabulary/primitive/number.js.map +1 -1
- package/dist/vocabulary/primitive/oneOf.js +3 -3
- package/dist/vocabulary/primitive/primary.js +3 -3
- package/dist/vocabulary/primitive/ref.d.ts +0 -5
- package/dist/vocabulary/primitive/ref.d.ts.map +1 -1
- package/dist/vocabulary/primitive/ref.js +0 -5
- package/dist/vocabulary/primitive/ref.js.map +1 -1
- package/dist/vocabulary/primitive/text.d.ts +0 -5
- package/dist/vocabulary/primitive/text.d.ts.map +1 -1
- package/dist/vocabulary/primitive/text.js +0 -5
- package/dist/vocabulary/primitive/text.js.map +1 -1
- package/dist/vocabulary/rule/immutable.d.ts +0 -5
- package/dist/vocabulary/rule/immutable.d.ts.map +1 -1
- package/dist/vocabulary/rule/immutable.js +0 -5
- package/dist/vocabulary/rule/immutable.js.map +1 -1
- package/dist/vocabulary/rule/indexed.d.ts +0 -5
- package/dist/vocabulary/rule/indexed.d.ts.map +1 -1
- package/dist/vocabulary/rule/indexed.js +0 -5
- package/dist/vocabulary/rule/indexed.js.map +1 -1
- package/dist/vocabulary/rule/nullable.d.ts +3 -3
- package/dist/vocabulary/rule/nullable.js +3 -3
- package/dist/vocabulary/rule/optional.d.ts +3 -3
- package/dist/vocabulary/rule/optional.js +3 -3
- package/dist/vocabulary/rule/readOnly.d.ts +3 -3
- package/dist/vocabulary/rule/readOnly.js +4 -4
- package/dist/vocabulary/rule/readOnly.js.map +1 -1
- package/dist/vocabulary/rule/unique.d.ts +0 -5
- package/dist/vocabulary/rule/unique.d.ts.map +1 -1
- package/dist/vocabulary/rule/unique.js +0 -5
- package/dist/vocabulary/rule/unique.js.map +1 -1
- package/dist/vocabulary/rule/writeOnly.d.ts +2 -2
- package/dist/vocabulary/rule/writeOnly.js +3 -3
- package/dist/vocabulary/rule/writeOnly.js.map +1 -1
- package/dist/vocabulary/vocabulary.d.ts +2 -2
- package/dist/vocabulary/vocabulary.js +5 -5
- package/package.json +1 -1
- package/src/Schema.ts +14 -20
- package/src/SchemaDefinition.ts +74 -48
- package/src/SchemaView.ts +1 -1
- package/src/axis/Axis.ts +1 -1
- package/src/axis/boundary/Boundaries.ts +5 -0
- package/src/axis/boundary/Boundary.ts +7 -9
- package/src/axis/boundary/BoundaryAxis.ts +2 -2
- package/src/axis/lifecycle/Lifecycle.ts +9 -4
- package/src/axis/lifecycle/LifecycleAxis.ts +7 -7
- package/src/axis/lifecycle/apply.ts +10 -9
- package/src/axis/role/Role.ts +14 -5
- package/src/axis/role/RoleAxis.ts +10 -10
- package/src/axis/shape/Shape.ts +61 -37
- package/src/entity/EntityAdapterSet.ts +2 -2
- package/src/entity.ts +2 -2
- package/src/field/Field.ts +2 -1
- package/src/field/FieldSet.ts +6 -20
- package/src/index.ts +2 -2
- package/src/lib/validation.ts +25 -0
- package/src/projection/Cases.ts +13 -8
- package/src/projection/Visibility.ts +1 -1
- package/src/projection/card/Bundle.ts +1 -4
- package/src/projection/card/Card.ts +26 -159
- package/src/projection/card/Descriptor.ts +2 -10
- package/src/projection/card/admission.ts +14 -12
- package/src/projection/card/diff.ts +142 -1
- package/src/validator/FieldDeclarationValidator.ts +5 -5
- package/src/validator/FieldValueValidator.ts +45 -12
- package/src/validator/InputValidator.ts +8 -18
- package/src/vocabulary/preset/created.ts +0 -5
- package/src/vocabulary/preset/email.ts +0 -5
- package/src/vocabulary/preset/updated.ts +0 -5
- package/src/vocabulary/preset/url.ts +0 -5
- package/src/vocabulary/primitive/bool.ts +0 -5
- package/src/vocabulary/primitive/date.ts +3 -3
- package/src/vocabulary/primitive/json.ts +3 -3
- package/src/vocabulary/primitive/list.ts +3 -3
- package/src/vocabulary/primitive/many.ts +3 -3
- package/src/vocabulary/primitive/number.ts +0 -5
- package/src/vocabulary/primitive/oneOf.ts +3 -3
- package/src/vocabulary/primitive/primary.ts +3 -3
- package/src/vocabulary/primitive/ref.ts +0 -5
- package/src/vocabulary/primitive/text.ts +0 -5
- package/src/vocabulary/rule/immutable.ts +0 -5
- package/src/vocabulary/rule/indexed.ts +0 -5
- package/src/vocabulary/rule/nullable.ts +3 -3
- package/src/vocabulary/rule/optional.ts +3 -3
- package/src/vocabulary/rule/readOnly.ts +4 -4
- package/src/vocabulary/rule/unique.ts +0 -5
- package/src/vocabulary/rule/writeOnly.ts +3 -3
- package/src/vocabulary/vocabulary.ts +5 -5
- package/dist/validation.d.ts +0 -17
- package/dist/validation.d.ts.map +0 -1
- package/dist/validation.js +0 -2
- package/dist/validation.js.map +0 -1
- package/src/validation.ts +0 -10
|
@@ -2,7 +2,7 @@ import { Boundary } from '../axis/boundary/Boundary.js';
|
|
|
2
2
|
import { Lifecycle } from '../axis/lifecycle/Lifecycle.js';
|
|
3
3
|
import { Role } from '../axis/role/Role.js';
|
|
4
4
|
import type { Field, Fields } from '../field/Field.js';
|
|
5
|
-
import type { ValidationError, ValidationResult } from '../validation.js';
|
|
5
|
+
import type { ValidationError, ValidationResult } from '../lib/validation.js';
|
|
6
6
|
import { FieldValueValidator } from './FieldValueValidator.js';
|
|
7
7
|
import { InputRefusal } from './InputRefusal.js';
|
|
8
8
|
|
|
@@ -32,7 +32,7 @@ export class InputValidator {
|
|
|
32
32
|
if (typeof input !== 'object' || input === null) {
|
|
33
33
|
return {
|
|
34
34
|
success: false,
|
|
35
|
-
errors: [{ path:
|
|
35
|
+
errors: [{ path: [], message: InputRefusal.notAnObject }],
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
38
|
|
|
@@ -42,12 +42,12 @@ export class InputValidator {
|
|
|
42
42
|
|
|
43
43
|
for (const key of Object.keys(data)) {
|
|
44
44
|
if (!Object.hasOwn(this.fields, key)) {
|
|
45
|
-
errors.push({ path: key, message: InputRefusal.unknownField });
|
|
45
|
+
errors.push({ path: [key], message: InputRefusal.unknownField });
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
for (const [key, field] of Object.entries(this.fields)) {
|
|
50
|
-
const path = key;
|
|
50
|
+
const path = [key];
|
|
51
51
|
const value = data[key];
|
|
52
52
|
|
|
53
53
|
if (value === undefined) {
|
|
@@ -61,8 +61,7 @@ export class InputValidator {
|
|
|
61
61
|
continue;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
if (boundary.readOnly) {
|
|
64
|
+
if (Boundary.of(field).readOnly) {
|
|
66
65
|
errors.push({ path, message: InputRefusal.readOnly });
|
|
67
66
|
continue;
|
|
68
67
|
}
|
|
@@ -71,18 +70,9 @@ export class InputValidator {
|
|
|
71
70
|
continue;
|
|
72
71
|
}
|
|
73
72
|
|
|
74
|
-
const
|
|
75
|
-
if ('error' in
|
|
76
|
-
|
|
77
|
-
continue;
|
|
78
|
-
}
|
|
79
|
-
if (checked.value === null) {
|
|
80
|
-
row[key] = null;
|
|
81
|
-
continue;
|
|
82
|
-
}
|
|
83
|
-
const decoded = boundary.decode(checked.value);
|
|
84
|
-
if ('error' in decoded) errors.push({ path, message: decoded.error });
|
|
85
|
-
else row[key] = decoded.value;
|
|
73
|
+
const parsed = FieldValueValidator.of(field).parse(value);
|
|
74
|
+
if ('error' in parsed) errors.push({ path: [...path, ...parsed.path ?? []], message: parsed.error });
|
|
75
|
+
else row[key] = parsed.value;
|
|
86
76
|
}
|
|
87
77
|
|
|
88
78
|
if (errors.length > 0) return { success: false, errors };
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import { Field } from '../../field/Field.js';
|
|
2
2
|
import { date } from '../primitive/date.js';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* So a creation stamp is written by the storage and refused from a client.
|
|
6
|
-
* FR : pour qu'un horodatage de création soit écrit par le storage et refusé au client.
|
|
7
|
-
* `created()` → `create: 'now'`, `update: 'forbidden'`
|
|
8
|
-
*/
|
|
9
4
|
export function created(): Field<Date> {
|
|
10
5
|
return date().with({
|
|
11
6
|
lifecycle: { create: 'now', update: 'forbidden' },
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import { text, type TextOptions } from '../primitive/text.js';
|
|
2
2
|
import type { Field } from '../../field/Field.js';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* So the format is stated once, where everyone would otherwise write the same regex.
|
|
6
|
-
* FR : pour que le format soit énoncé une fois, là où chacun réécrirait la même regex.
|
|
7
|
-
* `email({ max: 254 })`
|
|
8
|
-
*/
|
|
9
4
|
export function email(opts?: Omit<TextOptions, 'format'>): Field<string> {
|
|
10
5
|
return text({ ...opts, format: 'email' });
|
|
11
6
|
}
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import { created } from './created.js';
|
|
2
2
|
import { Field } from '../../field/Field.js';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* So the dual of `created()` is re-stamped at every write, by the same hand.
|
|
6
|
-
* FR : pour que le dual de `created()` soit ré-estampé à chaque écriture, par la même main.
|
|
7
|
-
* `updated()` → `create: 'now'`, `update: 'now'`
|
|
8
|
-
*/
|
|
9
4
|
export function updated(): Field<Date> {
|
|
10
5
|
const base = created();
|
|
11
6
|
return base.with({ lifecycle: { ...base.lifecycle, update: 'now' } });
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import { text, type TextOptions } from '../primitive/text.js';
|
|
2
2
|
import type { Field } from '../../field/Field.js';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* So a URL is a text with a stated format, not a type of its own.
|
|
6
|
-
* FR : pour qu'une URL soit un texte au format énoncé, pas un type à part.
|
|
7
|
-
* `url()` → `{ type: 'string', format: 'uri' }`
|
|
8
|
-
*/
|
|
9
4
|
export function url(opts?: Omit<TextOptions, 'format'>): Field<string> {
|
|
10
5
|
return text({ ...opts, format: 'uri' });
|
|
11
6
|
}
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import { Field } from '../../field/Field.js';
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* So a default is a lifecycle rule, not a value the handler remembers to set.
|
|
5
|
-
* FR : pour qu'un défaut soit une règle de cycle de vie, pas un oubli possible du handler.
|
|
6
|
-
* `bool({ default: false })`
|
|
7
|
-
*/
|
|
8
3
|
export function bool(opts?: { default?: boolean; description?: string }): Field<boolean> {
|
|
9
4
|
return new Field<boolean>({
|
|
10
5
|
shape: { type: 'boolean' },
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Field } from '../../field/Field.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
* FR :
|
|
6
|
-
* `date()` → `{ type: 'string', format: 'date-time' }
|
|
4
|
+
* A `Date` in a handler, an ISO string on the wire — the `isoDate` boundary converts.
|
|
5
|
+
* FR : un `Date` dans un handler, une chaîne ISO sur le fil — `isoDate` convertit.
|
|
6
|
+
* `date()` → `{ type: 'string', format: 'date-time' }`
|
|
7
7
|
*/
|
|
8
8
|
export function date(): Field<Date> {
|
|
9
9
|
return new Field<Date>({ shape: { type: 'string', format: 'date-time' } });
|
|
@@ -7,9 +7,9 @@ export function json<E extends SchemaView & (new (...args: any[]) => any)>(
|
|
|
7
7
|
of: E,
|
|
8
8
|
): Field<InstanceType<E>>;
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
11
|
-
* FR :
|
|
12
|
-
* `json(Address)` → the
|
|
10
|
+
* `json(Address)` where the object has a shape; `json()` alone admits any shape forever.
|
|
11
|
+
* FR : `json(Address)` quand l'objet a une forme ; `json()` seul admet tout, à jamais.
|
|
12
|
+
* `json(Address)` → the entity's properties, and its required keys
|
|
13
13
|
*/
|
|
14
14
|
export function json(of?: SchemaView): Field<unknown> {
|
|
15
15
|
if (!of) return new Field({ shape: { type: 'object' } });
|
|
@@ -6,9 +6,9 @@ export interface ListOptions {
|
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
10
|
-
* FR :
|
|
11
|
-
* `list(text(), { max: 5 })
|
|
9
|
+
* A list of VALUES. The other side of a relation is `many()`, and passing one here throws.
|
|
10
|
+
* FR : une liste de VALEURS. L'autre côté d'une relation est `many()`, et en passer une ici lève.
|
|
11
|
+
* `list(text(), { max: 5 })` → `{ type: 'array', items: { type: 'string' }, maxItems: 5 }`
|
|
12
12
|
*/
|
|
13
13
|
export function list<T>(item: Field<T>, opts?: ListOptions): Field<T[]> {
|
|
14
14
|
if (item.role?.relation)
|
|
@@ -2,9 +2,9 @@ import { Relation, type EntityConstructor } from '../../axis/role/Relation.js';
|
|
|
2
2
|
import { Field } from '../../field/Field.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
* FR :
|
|
7
|
-
* `many(() => Post)` →
|
|
5
|
+
* The far side of a `ref()`: no column of its own, and absent from what a client sends.
|
|
6
|
+
* FR : l'autre côté d'un `ref()` : aucune colonne à lui, et absent de ce qu'un client envoie.
|
|
7
|
+
* `many(() => Post)` → `{ type: 'array' }` with `role.relation.kind` `'many'`
|
|
8
8
|
*/
|
|
9
9
|
export function many<E extends EntityConstructor>(
|
|
10
10
|
target: E | (() => E),
|
|
@@ -8,11 +8,6 @@ export interface NumberOptions {
|
|
|
8
8
|
description?: string;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
/**
|
|
12
|
-
* So `integer` is a shape, not a second word to remember.
|
|
13
|
-
* FR : pour qu'`integer` soit une forme, pas un second mot à retenir.
|
|
14
|
-
* `number({ integer: true, min: 0 })` → `{ type: 'integer', minimum: 0 }`
|
|
15
|
-
*/
|
|
16
11
|
export function number(opts?: NumberOptions): Field<number> {
|
|
17
12
|
return new Field<number>({
|
|
18
13
|
shape: {
|
|
@@ -12,9 +12,9 @@ export function oneOf<const T extends readonly string[]>(
|
|
|
12
12
|
...args: [...T, OneOfOptions<T[number]>]
|
|
13
13
|
): Field<T[number]>;
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
16
|
-
* FR :
|
|
17
|
-
* `oneOf('draft', 'published', { default: 'draft' })`
|
|
15
|
+
* The set travels: GraphQL enum, form `select` and DDL `CHECK`, from this one declaration.
|
|
16
|
+
* FR : l'ensemble voyage : enum GraphQL, `select` du formulaire, `CHECK` du DDL.
|
|
17
|
+
* `oneOf('draft', 'published', { default: 'draft' })` → `{ type: 'string', enum: [...] }`
|
|
18
18
|
*/
|
|
19
19
|
export function oneOf<const T extends readonly string[]>(
|
|
20
20
|
...args: [...T] | [...T, OneOfOptions<T[number]>]
|
|
@@ -8,9 +8,9 @@ interface PrimaryOptions {
|
|
|
8
8
|
export function primary(opts?: PrimaryOptions): Field<string>;
|
|
9
9
|
export function primary<T>(field: Field<T>): Field<T>;
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
12
|
-
* FR : pour
|
|
13
|
-
* `primary()` → cuid2
|
|
11
|
+
* `primary()` for a generated id; `primary(number())` to make a declared field the key.
|
|
12
|
+
* FR : `primary()` pour un identifiant généré ; `primary(number())` pour promouvoir un champ.
|
|
13
|
+
* `primary()` → `create: { generate: 'cuid2' }`, `update: 'forbidden'`
|
|
14
14
|
*/
|
|
15
15
|
export function primary(fieldOrOptions?: Field | PrimaryOptions): Field {
|
|
16
16
|
if (Field.is(fieldOrOptions)) {
|
|
@@ -5,11 +5,6 @@ export interface RefOptions {
|
|
|
5
5
|
cascade?: boolean;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
/**
|
|
9
|
-
* So a reference names the target entity, and the column type follows from it.
|
|
10
|
-
* FR : pour qu'une référence nomme l'entité cible, la colonne en découlant.
|
|
11
|
-
* `ref(() => User, { cascade: true })`
|
|
12
|
-
*/
|
|
13
8
|
export function ref<E extends EntityConstructor>(
|
|
14
9
|
target: E | (() => E),
|
|
15
10
|
opts?: RefOptions,
|
|
@@ -10,11 +10,6 @@ export interface TextOptions {
|
|
|
10
10
|
description?: string;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
/**
|
|
14
|
-
* So a string field states its bounds where the DDL and the validator both read them.
|
|
15
|
-
* FR : pour qu'un champ texte énonce ses bornes là où le DDL et le juge les lisent.
|
|
16
|
-
* `text({ max: 200, format: 'email' })`
|
|
17
|
-
*/
|
|
18
13
|
export function text(opts?: TextOptions): Field<string> {
|
|
19
14
|
return new Field<string>({
|
|
20
15
|
shape: {
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import { vocabulary } from '../vocabulary.js';
|
|
2
2
|
import { Field } from '../../field/Field.js';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* So a write-once field is refused on a patch by the validator, not by the table.
|
|
6
|
-
* FR : pour qu'un champ écrit une fois soit refusé par le juge sur une modification.
|
|
7
|
-
* `immutable(text())` → `update: 'forbidden'`
|
|
8
|
-
*/
|
|
9
4
|
export const immutable: <T>(field: Field<T>) => Field<T> = vocabulary(
|
|
10
5
|
'immutable',
|
|
11
6
|
() => ({
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import { vocabulary } from '../vocabulary.js';
|
|
2
2
|
import { Field } from '../../field/Field.js';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* So the entity states the index, and the DDL is the one that emits it.
|
|
6
|
-
* FR : pour que l'entité énonce l'index, le DDL étant celui qui l'émet.
|
|
7
|
-
* `indexed(text())` → `role.index` is `true`
|
|
8
|
-
*/
|
|
9
4
|
export const indexed: <T>(field: Field<T>) => Field<T> = vocabulary('indexed', () => ({
|
|
10
5
|
role: { index: true },
|
|
11
6
|
}));
|
|
@@ -3,9 +3,9 @@ import { Shapes } from '../../axis/shape/Shape.js';
|
|
|
3
3
|
import { type Field } from '../../field/Field.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
* FR :
|
|
8
|
-
* `nullable(text())` → `{ type: ['string', 'null'] }`,
|
|
6
|
+
* Adds `null` and leaves the field REQUIRED — `optional()` is the one permitting absence.
|
|
7
|
+
* FR : ajoute `null` en laissant le champ OBLIGATOIRE — `optional()` permet l'absence.
|
|
8
|
+
* `nullable(text())` → `{ type: ['string', 'null'] }`, and `validate({})` still refuses
|
|
9
9
|
*/
|
|
10
10
|
export const nullable: <T>(field: Field<T>) => Field<T | null> = vocabulary(
|
|
11
11
|
'nullable',
|
|
@@ -3,9 +3,9 @@ import { Shapes } from '../../axis/shape/Shape.js';
|
|
|
3
3
|
import { type Field } from '../../field/Field.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
* FR :
|
|
8
|
-
* `optional(text())` →
|
|
6
|
+
* Adds `null` AND permits absence. A field that already states a `create` rule keeps it.
|
|
7
|
+
* FR : ajoute `null` ET permet l'absence. Un champ qui énonce déjà un `create` le garde.
|
|
8
|
+
* `optional(text())` → `{ type: ['string', 'null'] }` and `create: 'optional'`
|
|
9
9
|
*/
|
|
10
10
|
export const optional: <T>(field: Field<T>) => Field<T | null> = vocabulary(
|
|
11
11
|
'optional',
|
|
@@ -3,13 +3,13 @@ import { Boundary } from '../../axis/boundary/Boundary.js';
|
|
|
3
3
|
import { Field } from '../../field/Field.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
* FR :
|
|
8
|
-
* `readOnly(text())` → `boundary.in` is `'closed'
|
|
6
|
+
* Closes the way in, so the field leaves `Visibility.input` and every form derived from it.
|
|
7
|
+
* FR : ferme l'entrée : le champ quitte `Visibility.input` et tout formulaire qui en dérive.
|
|
8
|
+
* `readOnly(text())` → `boundary.in` is `'closed'`
|
|
9
9
|
*/
|
|
10
10
|
export const readOnly: <T>(field: Field<T>) => Field<T> = vocabulary(
|
|
11
11
|
'readOnly',
|
|
12
12
|
(field) => ({
|
|
13
|
-
boundary: Boundary.declared(field).
|
|
13
|
+
boundary: Boundary.declared(field).declaring({ in: 'closed' }),
|
|
14
14
|
}),
|
|
15
15
|
);
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import { vocabulary } from '../vocabulary.js';
|
|
2
2
|
import { Field } from '../../field/Field.js';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* So a field is unique on its own, whatever key it ends up under.
|
|
6
|
-
* FR : pour qu'un champ soit unique à lui seul, quelle que soit sa clé.
|
|
7
|
-
* `unique(email)` → `role.unique` is true
|
|
8
|
-
*/
|
|
9
4
|
export const unique: <T>(field: Field<T>) => Field<T> = vocabulary('unique', () => ({
|
|
10
5
|
role: { unique: true },
|
|
11
6
|
}));
|
|
@@ -3,13 +3,13 @@ import { Boundary } from '../../axis/boundary/Boundary.js';
|
|
|
3
3
|
import { Field } from '../../field/Field.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
* FR :
|
|
6
|
+
* Closes the way out, the dual of `readOnly`: the value is written and never sent back.
|
|
7
|
+
* FR : ferme la sortie, dual de `readOnly` : la valeur s'écrit et ne repart jamais.
|
|
8
8
|
* `writeOnly(text())` → `boundary.out` is `'closed'`
|
|
9
9
|
*/
|
|
10
10
|
export const writeOnly: <T>(field: Field<T>) => Field<T> = vocabulary(
|
|
11
11
|
'writeOnly',
|
|
12
12
|
(field) => ({
|
|
13
|
-
boundary: Boundary.declared(field).
|
|
13
|
+
boundary: Boundary.declared(field).declaring({ out: 'closed' }),
|
|
14
14
|
}),
|
|
15
15
|
);
|
|
@@ -5,8 +5,8 @@ import { dequal } from 'dequal';
|
|
|
5
5
|
const MEMBER_SLOTS = [...EXTENSION_SLOTS, 'meta'] as const;
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
9
|
-
* FR :
|
|
8
|
+
* Builds a `rule/` word, which states members on the field it receives.
|
|
9
|
+
* FR : fabrique un mot de `rule/`, qui énonce des membres sur le champ reçu.
|
|
10
10
|
* `vocabulary('indexed', () => ({ role: { index: true } }))`
|
|
11
11
|
*/
|
|
12
12
|
export function vocabulary(
|
|
@@ -19,9 +19,9 @@ export function vocabulary(
|
|
|
19
19
|
export type FieldWord = (field: Field<any>) => Field<any>;
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
*
|
|
23
|
-
* FR :
|
|
24
|
-
* `readOnly(writeOnly(text()))` → both
|
|
22
|
+
* Refuses two words stating one member differently, rather than letting the outer win.
|
|
23
|
+
* FR : refuse deux mots qui énoncent un même membre différemment.
|
|
24
|
+
* `readOnly(writeOnly(text()))` → both apply; `immutable(created())` → throws
|
|
25
25
|
*/
|
|
26
26
|
function merge(name: string, field: Field, given: Partial<Field>): Partial<Field> {
|
|
27
27
|
const merged: Record<string, unknown> = {};
|
package/dist/validation.d.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export interface ValidationError {
|
|
2
|
-
path: string;
|
|
3
|
-
message: string;
|
|
4
|
-
}
|
|
5
|
-
export type ValidationResult<T> = {
|
|
6
|
-
success: true;
|
|
7
|
-
data: T;
|
|
8
|
-
} | {
|
|
9
|
-
success: false;
|
|
10
|
-
errors: ValidationError[];
|
|
11
|
-
};
|
|
12
|
-
export type Checked = {
|
|
13
|
-
value: unknown;
|
|
14
|
-
} | {
|
|
15
|
-
error: string;
|
|
16
|
-
};
|
|
17
|
-
//# sourceMappingURL=validation.d.ts.map
|
package/dist/validation.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAC1B;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,CAAC,CAAA;CAAE,GAC1B;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,eAAe,EAAE,CAAA;CAAE,CAAC;AAElD,MAAM,MAAM,OAAO,GAAG;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC"}
|
package/dist/validation.js
DELETED
package/dist/validation.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":""}
|
package/src/validation.ts
DELETED