@bedrockio/yada 1.0.7 → 1.0.9
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 +46 -5
- package/dist/cjs/Schema.js +10 -0
- package/dist/cjs/object.js +25 -9
- package/package.json +1 -1
- package/src/Schema.js +10 -0
- package/src/object.js +25 -9
- package/test/all.test.js +73 -0
package/README.md
CHANGED
|
@@ -22,6 +22,7 @@ Concepts
|
|
|
22
22
|
- [Reject](#reject)
|
|
23
23
|
- [Custom](#custom)
|
|
24
24
|
- [Default](#default)
|
|
25
|
+
- [Strip](#strip)
|
|
25
26
|
- [Validation Options](#validation-options)
|
|
26
27
|
- [Error Messages](#error-messages)
|
|
27
28
|
- [Localization](#localization)
|
|
@@ -300,11 +301,6 @@ const schema = yd
|
|
|
300
301
|
.required();
|
|
301
302
|
```
|
|
302
303
|
|
|
303
|
-
#### Methods:
|
|
304
|
-
|
|
305
|
-
- `append` - Appends the passed argument to create a new object schema. Accepts
|
|
306
|
-
either an object or another `.object()` schema.
|
|
307
|
-
|
|
308
304
|
## Date
|
|
309
305
|
|
|
310
306
|
Dates are similar to the basic types with the exception that in addition to date
|
|
@@ -376,6 +372,33 @@ await schema.validate(true); // pass
|
|
|
376
372
|
await schema.validate('true'); // error!
|
|
377
373
|
```
|
|
378
374
|
|
|
375
|
+
### Append
|
|
376
|
+
|
|
377
|
+
Appends another schema:
|
|
378
|
+
|
|
379
|
+
```js
|
|
380
|
+
const schema1 = yd.string();
|
|
381
|
+
const schema2 = yd.custom((str) => {
|
|
382
|
+
if (str === 'foo') {
|
|
383
|
+
throw new Error('Cannot be foo!');
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
const schema = schema1.append(schema2);
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
Note that when applied to an object schema the fields will be merged. In this
|
|
390
|
+
case a plain object is also accepted:
|
|
391
|
+
|
|
392
|
+
```js
|
|
393
|
+
const schema1 = yd.object({
|
|
394
|
+
foo: yd.string(),
|
|
395
|
+
});
|
|
396
|
+
const schema2 = yd.object({
|
|
397
|
+
bar: yd.string(),
|
|
398
|
+
});
|
|
399
|
+
const schema = schema1.append(schema2);
|
|
400
|
+
```
|
|
401
|
+
|
|
379
402
|
### Custom
|
|
380
403
|
|
|
381
404
|
The `custom` schema allows for custom validations expressed in code. A custom
|
|
@@ -467,6 +490,24 @@ console.log(await schema.validate()); // "hi!"
|
|
|
467
490
|
console.log(await schema.validate('hello!')); // "hello!"
|
|
468
491
|
```
|
|
469
492
|
|
|
493
|
+
### Strip
|
|
494
|
+
|
|
495
|
+
The `strip` method serves as a way to conditionally exclude fields when the
|
|
496
|
+
schema is used inside an object schema:
|
|
497
|
+
|
|
498
|
+
```js
|
|
499
|
+
const schema = yd.object({
|
|
500
|
+
name: yd.string(),
|
|
501
|
+
age: yd.number().strip((val, { self }) => {
|
|
502
|
+
// That's private!
|
|
503
|
+
return !self;
|
|
504
|
+
}),
|
|
505
|
+
});
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
Arguments are identical to those passed to [custom](#custom). The field will be
|
|
509
|
+
stripped out if the function returns a truthy value.
|
|
510
|
+
|
|
470
511
|
## Validation Options
|
|
471
512
|
|
|
472
513
|
Validation options in Yada can be passed at runtime on validation or baked into
|
package/dist/cjs/Schema.js
CHANGED
|
@@ -46,6 +46,11 @@ class Schema {
|
|
|
46
46
|
return await fn(val, options);
|
|
47
47
|
});
|
|
48
48
|
}
|
|
49
|
+
strip(strip) {
|
|
50
|
+
return this.clone({
|
|
51
|
+
strip
|
|
52
|
+
});
|
|
53
|
+
}
|
|
49
54
|
allow(...set) {
|
|
50
55
|
return this.assertEnum(set, true);
|
|
51
56
|
}
|
|
@@ -120,6 +125,11 @@ class Schema {
|
|
|
120
125
|
};
|
|
121
126
|
return clone;
|
|
122
127
|
}
|
|
128
|
+
append(schema) {
|
|
129
|
+
const merged = this.clone(schema.meta);
|
|
130
|
+
merged.assertions = [...this.assertions, ...schema.assertions];
|
|
131
|
+
return merged;
|
|
132
|
+
}
|
|
123
133
|
|
|
124
134
|
// Private
|
|
125
135
|
|
package/dist/cjs/object.js
CHANGED
|
@@ -48,9 +48,22 @@ class ObjectSchema extends _TypeSchema.default {
|
|
|
48
48
|
for (let [key, schema] of Object.entries(this.meta.fields)) {
|
|
49
49
|
this.assert('field', async (obj, options) => {
|
|
50
50
|
if (obj) {
|
|
51
|
-
|
|
51
|
+
const val = obj[key];
|
|
52
|
+
const {
|
|
53
|
+
strip
|
|
54
|
+
} = schema.meta;
|
|
55
|
+
if (strip && strip(val, options)) {
|
|
56
|
+
delete obj[key];
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
52
59
|
try {
|
|
53
|
-
|
|
60
|
+
const result = await schema.validate(val, options);
|
|
61
|
+
if (result !== undefined) {
|
|
62
|
+
return {
|
|
63
|
+
...obj,
|
|
64
|
+
[key]: result
|
|
65
|
+
};
|
|
66
|
+
}
|
|
54
67
|
} catch (error) {
|
|
55
68
|
if (error.details?.length === 1) {
|
|
56
69
|
const {
|
|
@@ -62,18 +75,21 @@ class ObjectSchema extends _TypeSchema.default {
|
|
|
62
75
|
throw new _errors.FieldError('Field failed validation.', key, error.original, error.details);
|
|
63
76
|
}
|
|
64
77
|
}
|
|
65
|
-
return {
|
|
66
|
-
...obj,
|
|
67
|
-
...(val !== undefined && {
|
|
68
|
-
[key]: val
|
|
69
|
-
})
|
|
70
|
-
};
|
|
71
78
|
}
|
|
72
79
|
});
|
|
73
80
|
}
|
|
74
81
|
}
|
|
75
82
|
append(arg) {
|
|
76
|
-
|
|
83
|
+
let schema;
|
|
84
|
+
if (arg instanceof ObjectSchema) {
|
|
85
|
+
schema = arg;
|
|
86
|
+
} else if ((0, _Schema.isSchema)(arg)) {
|
|
87
|
+
// If the schema is of a different type then
|
|
88
|
+
// simply append it and don't merge fields.
|
|
89
|
+
return super.append(arg);
|
|
90
|
+
} else {
|
|
91
|
+
schema = new ObjectSchema(arg);
|
|
92
|
+
}
|
|
77
93
|
const fields = {
|
|
78
94
|
...this.meta.fields,
|
|
79
95
|
...schema.meta.fields
|
package/package.json
CHANGED
package/src/Schema.js
CHANGED
|
@@ -46,6 +46,10 @@ export default class Schema {
|
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
strip(strip) {
|
|
50
|
+
return this.clone({ strip });
|
|
51
|
+
}
|
|
52
|
+
|
|
49
53
|
allow(...set) {
|
|
50
54
|
return this.assertEnum(set, true);
|
|
51
55
|
}
|
|
@@ -123,6 +127,12 @@ export default class Schema {
|
|
|
123
127
|
return clone;
|
|
124
128
|
}
|
|
125
129
|
|
|
130
|
+
append(schema) {
|
|
131
|
+
const merged = this.clone(schema.meta);
|
|
132
|
+
merged.assertions = [...this.assertions, ...schema.assertions];
|
|
133
|
+
return merged;
|
|
134
|
+
}
|
|
135
|
+
|
|
126
136
|
// Private
|
|
127
137
|
|
|
128
138
|
assertEnum(set, allow) {
|
package/src/object.js
CHANGED
|
@@ -38,9 +38,22 @@ class ObjectSchema extends TypeSchema {
|
|
|
38
38
|
for (let [key, schema] of Object.entries(this.meta.fields)) {
|
|
39
39
|
this.assert('field', async (obj, options) => {
|
|
40
40
|
if (obj) {
|
|
41
|
-
|
|
41
|
+
const val = obj[key];
|
|
42
|
+
const { strip } = schema.meta;
|
|
43
|
+
|
|
44
|
+
if (strip && strip(val, options)) {
|
|
45
|
+
delete obj[key];
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
42
49
|
try {
|
|
43
|
-
|
|
50
|
+
const result = await schema.validate(val, options);
|
|
51
|
+
if (result !== undefined) {
|
|
52
|
+
return {
|
|
53
|
+
...obj,
|
|
54
|
+
[key]: result,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
44
57
|
} catch (error) {
|
|
45
58
|
if (error.details?.length === 1) {
|
|
46
59
|
const { message, original } = error.details[0];
|
|
@@ -54,19 +67,22 @@ class ObjectSchema extends TypeSchema {
|
|
|
54
67
|
);
|
|
55
68
|
}
|
|
56
69
|
}
|
|
57
|
-
return {
|
|
58
|
-
...obj,
|
|
59
|
-
...(val !== undefined && {
|
|
60
|
-
[key]: val,
|
|
61
|
-
}),
|
|
62
|
-
};
|
|
63
70
|
}
|
|
64
71
|
});
|
|
65
72
|
}
|
|
66
73
|
}
|
|
67
74
|
|
|
68
75
|
append(arg) {
|
|
69
|
-
|
|
76
|
+
let schema;
|
|
77
|
+
if (arg instanceof ObjectSchema) {
|
|
78
|
+
schema = arg;
|
|
79
|
+
} else if (isSchema(arg)) {
|
|
80
|
+
// If the schema is of a different type then
|
|
81
|
+
// simply append it and don't merge fields.
|
|
82
|
+
return super.append(arg);
|
|
83
|
+
} else {
|
|
84
|
+
schema = new ObjectSchema(arg);
|
|
85
|
+
}
|
|
70
86
|
|
|
71
87
|
const fields = {
|
|
72
88
|
...this.meta.fields,
|
package/test/all.test.js
CHANGED
|
@@ -693,6 +693,29 @@ describe('custom', () => {
|
|
|
693
693
|
});
|
|
694
694
|
});
|
|
695
695
|
|
|
696
|
+
describe('strip', () => {
|
|
697
|
+
it('should conditionally strip out fields', async () => {
|
|
698
|
+
const schema = yd.object({
|
|
699
|
+
name: yd.string(),
|
|
700
|
+
age: yd.number().strip((val, { self }) => {
|
|
701
|
+
return !self;
|
|
702
|
+
}),
|
|
703
|
+
});
|
|
704
|
+
const result = await schema.validate(
|
|
705
|
+
{
|
|
706
|
+
name: 'Brett',
|
|
707
|
+
age: 25,
|
|
708
|
+
},
|
|
709
|
+
{
|
|
710
|
+
isPrivate: true,
|
|
711
|
+
}
|
|
712
|
+
);
|
|
713
|
+
expect(result).toEqual({
|
|
714
|
+
name: 'Brett',
|
|
715
|
+
});
|
|
716
|
+
});
|
|
717
|
+
});
|
|
718
|
+
|
|
696
719
|
describe('array', () => {
|
|
697
720
|
it('should validate an optional array', async () => {
|
|
698
721
|
const schema = yd.array();
|
|
@@ -955,6 +978,56 @@ describe('default', () => {
|
|
|
955
978
|
});
|
|
956
979
|
});
|
|
957
980
|
|
|
981
|
+
describe('append', () => {
|
|
982
|
+
it('should allow appending to a string schema', async () => {
|
|
983
|
+
const custom = yd.custom((str) => {
|
|
984
|
+
if (str === 'fop') {
|
|
985
|
+
throw new Error('You misspelled foo!');
|
|
986
|
+
}
|
|
987
|
+
});
|
|
988
|
+
|
|
989
|
+
const schema = yd.string().append(custom);
|
|
990
|
+
|
|
991
|
+
await assertPass(schema, 'foo');
|
|
992
|
+
await assertFail(schema, 'fop', ['You misspelled foo!']);
|
|
993
|
+
});
|
|
994
|
+
|
|
995
|
+
it('should append a custom schema to an object schema', async () => {
|
|
996
|
+
const custom = yd.custom((obj) => {
|
|
997
|
+
if (obj.foo === 'fop') {
|
|
998
|
+
throw new Error('You misspelled foo!');
|
|
999
|
+
}
|
|
1000
|
+
});
|
|
1001
|
+
|
|
1002
|
+
const schema = yd
|
|
1003
|
+
.object({
|
|
1004
|
+
foo: yd.string(),
|
|
1005
|
+
})
|
|
1006
|
+
.append(custom);
|
|
1007
|
+
|
|
1008
|
+
await assertPass(schema, { foo: 'foo' });
|
|
1009
|
+
await assertFail(schema, { foo: 'fop' }, ['You misspelled foo!']);
|
|
1010
|
+
});
|
|
1011
|
+
|
|
1012
|
+
it('should preserve defaults', async () => {
|
|
1013
|
+
const custom = yd.custom((str) => {
|
|
1014
|
+
if (str === 'fop') {
|
|
1015
|
+
throw new Error('You misspelled foo!');
|
|
1016
|
+
}
|
|
1017
|
+
});
|
|
1018
|
+
const schema = yd.string().required();
|
|
1019
|
+
|
|
1020
|
+
await assertPass(schema.default('foo').append(custom));
|
|
1021
|
+
await assertPass(schema.append(custom).default('foo'));
|
|
1022
|
+
await assertFail(schema.default('fop').append(custom), undefined, [
|
|
1023
|
+
'You misspelled foo!',
|
|
1024
|
+
]);
|
|
1025
|
+
await assertFail(schema.append(custom).default('fop'), undefined, [
|
|
1026
|
+
'You misspelled foo!',
|
|
1027
|
+
]);
|
|
1028
|
+
});
|
|
1029
|
+
});
|
|
1030
|
+
|
|
958
1031
|
describe('serialization', () => {
|
|
959
1032
|
it('should correctly serialize object error', async () => {
|
|
960
1033
|
const schema = yd.object({
|