@bedrockio/yada 1.6.0 → 1.7.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/CHANGELOG.md +13 -0
- package/README.md +12 -2
- package/dist/cjs/Schema.js +4 -0
- package/dist/cjs/errors.js +1 -1
- package/dist/cjs/index.js +7 -7
- package/dist/cjs/object.js +74 -12
- package/dist/cjs/string.js +3 -9
- package/dist/cjs/utils.js +14 -0
- package/eslint.config.js +1 -1
- package/package.json +6 -6
- package/src/Schema.js +7 -2
- package/src/errors.js +1 -1
- package/src/index.js +16 -18
- package/src/object.js +77 -10
- package/src/string.js +7 -6
- package/src/utils.js +4 -0
- package/types/Schema.d.ts.map +1 -1
- package/types/index.d.ts +16 -16
- package/types/index.d.ts.map +1 -1
- package/types/object.d.ts +6 -3
- package/types/object.d.ts.map +1 -1
- package/types/string.d.ts.map +1 -1
- package/types/utils.d.ts +1 -4
- package/types/utils.d.ts.map +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
## 1.7.0
|
|
2
|
+
|
|
3
|
+
- Partial revert of 1.6.0. Dot syntax expanding no longer default but enabled.
|
|
4
|
+
- Expanding flat syntax is now `expandFlatKeys`.
|
|
5
|
+
- Flat syntax can also now be allowed without being expanded with
|
|
6
|
+
`allowFlatKeys`.
|
|
7
|
+
- Checks on flat key syntax (array, object presence, etc).
|
|
8
|
+
|
|
9
|
+
## 1.6.1
|
|
10
|
+
|
|
11
|
+
- Fixed empty string not allowed when enum provided.
|
|
12
|
+
- Some development version bumps.
|
|
13
|
+
|
|
1
14
|
## 1.6.0
|
|
2
15
|
|
|
3
16
|
- Make `expandDotSyntax` option default and rename inverse option to
|
package/README.md
CHANGED
|
@@ -230,6 +230,10 @@ const schema = yd.string().options({
|
|
|
230
230
|
});
|
|
231
231
|
```
|
|
232
232
|
|
|
233
|
+
### String Schema Options
|
|
234
|
+
|
|
235
|
+
- `allowEmpty` - Allows empty strings.
|
|
236
|
+
|
|
233
237
|
### Number
|
|
234
238
|
|
|
235
239
|
Numbers have a handful of useful valiadtions:
|
|
@@ -431,6 +435,13 @@ const newSchema = yd.object({
|
|
|
431
435
|
});
|
|
432
436
|
```
|
|
433
437
|
|
|
438
|
+
### Object Schema Options
|
|
439
|
+
|
|
440
|
+
- `stripEmpty` - Removes properties that are empty strings.
|
|
441
|
+
- `stripUnknown` - Removes properties not in the schema.
|
|
442
|
+
- `allowFlatKeys` - Allows "flat" keys like `profile.name`.
|
|
443
|
+
- `expendFlatKeys` - Expands "flat" keys into nested objects.
|
|
444
|
+
|
|
434
445
|
## Date
|
|
435
446
|
|
|
436
447
|
Dates are similar to the basic types with the exception that in addition to date
|
|
@@ -777,12 +788,11 @@ await schema
|
|
|
777
788
|
|
|
778
789
|
#### Options:
|
|
779
790
|
|
|
780
|
-
- `stripUnknown` - Strips unknown fields on object schemas which otherwise would
|
|
781
|
-
throw an error.
|
|
782
791
|
- `cast` - Casts input to its associated type. For strings and numbers this
|
|
783
792
|
performs a simple type coercion. For booleans `"true"` or `"1"` will be
|
|
784
793
|
considered `true` and `"false"` or `"0"` will be considered `false`. This
|
|
785
794
|
option is useful to convert query strings.
|
|
795
|
+
- [Object Schema Options](#object-schema-options)
|
|
786
796
|
|
|
787
797
|
## Error Messages
|
|
788
798
|
|
package/dist/cjs/Schema.js
CHANGED
|
@@ -7,6 +7,7 @@ exports.default = void 0;
|
|
|
7
7
|
exports.isSchema = isSchema;
|
|
8
8
|
var _lodash = require("lodash");
|
|
9
9
|
var _errors = require("./errors");
|
|
10
|
+
var _utils = require("./utils");
|
|
10
11
|
const INITIAL_TYPES = ['default', 'required', 'type', 'transform', 'empty'];
|
|
11
12
|
const REQUIRED_TYPES = ['default', 'required', 'missing'];
|
|
12
13
|
function isSchema(arg) {
|
|
@@ -351,6 +352,9 @@ class Schema {
|
|
|
351
352
|
return this.clone({
|
|
352
353
|
enum: set
|
|
353
354
|
}).assert('enum', async (val, options) => {
|
|
355
|
+
if (val === '' && (0, _utils.canAllowEmptyString)(options)) {
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
354
358
|
if (val !== undefined) {
|
|
355
359
|
let captured = [];
|
|
356
360
|
for (let el of set) {
|
package/dist/cjs/errors.js
CHANGED
|
@@ -5,8 +5,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.ValidationError = exports.TypeError = exports.LocalizedError = exports.FormatError = exports.FieldError = exports.ElementError = exports.AssertionError = exports.ArrayError = exports.AllowedError = void 0;
|
|
7
7
|
exports.isSchemaError = isSchemaError;
|
|
8
|
-
var _messages = require("./messages");
|
|
9
8
|
var _localization = require("./localization");
|
|
9
|
+
var _messages = require("./messages");
|
|
10
10
|
class LocalizedError extends Error {
|
|
11
11
|
constructor(message, values = {}) {
|
|
12
12
|
super((0, _localization.localize)(message, values));
|
package/dist/cjs/index.js
CHANGED
|
@@ -80,19 +80,19 @@ Object.defineProperty(exports, "useLocalizer", {
|
|
|
80
80
|
return _localization.useLocalizer;
|
|
81
81
|
}
|
|
82
82
|
});
|
|
83
|
-
var
|
|
84
|
-
var
|
|
83
|
+
var _Schema = _interopRequireWildcard(require("./Schema"));
|
|
84
|
+
var _array = _interopRequireDefault(require("./array"));
|
|
85
85
|
var _boolean = _interopRequireDefault(require("./boolean"));
|
|
86
86
|
var _date = _interopRequireDefault(require("./date"));
|
|
87
|
+
var _errors = require("./errors");
|
|
88
|
+
var _localization = require("./localization");
|
|
89
|
+
var _number = _interopRequireDefault(require("./number"));
|
|
87
90
|
var _object = _interopRequireDefault(require("./object"));
|
|
88
|
-
var
|
|
91
|
+
var _string = _interopRequireDefault(require("./string"));
|
|
89
92
|
var _tuple = _interopRequireDefault(require("./tuple"));
|
|
90
|
-
|
|
91
|
-
var _localization = require("./localization");
|
|
92
|
-
var _errors = require("./errors");
|
|
93
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
93
94
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
94
95
|
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
95
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
96
96
|
/**
|
|
97
97
|
* Accepts anything.
|
|
98
98
|
*/
|
package/dist/cjs/object.js
CHANGED
|
@@ -5,13 +5,14 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.default = _default;
|
|
7
7
|
var _lodash = require("lodash");
|
|
8
|
+
var _Schema = _interopRequireWildcard(require("./Schema"));
|
|
8
9
|
var _TypeSchema = _interopRequireDefault(require("./TypeSchema"));
|
|
9
10
|
var _errors = require("./errors");
|
|
10
|
-
|
|
11
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
11
12
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
12
13
|
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
13
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
14
14
|
const APPEND_ASSERTION_TYPES = ['required', 'type', 'custom'];
|
|
15
|
+
const INTEGER_REG = /^\d+$/;
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* @typedef {{ [key: string]: Schema } | {}} SchemaMap
|
|
@@ -30,19 +31,15 @@ class ObjectSchema extends _TypeSchema.default {
|
|
|
30
31
|
});
|
|
31
32
|
this.transform((obj, options) => {
|
|
32
33
|
const {
|
|
33
|
-
fields,
|
|
34
34
|
stripUnknown,
|
|
35
|
-
stripEmpty
|
|
36
|
-
preserveKeys
|
|
35
|
+
stripEmpty
|
|
37
36
|
} = options;
|
|
38
37
|
if (obj) {
|
|
39
38
|
const result = {};
|
|
40
|
-
|
|
41
|
-
obj = expandKeys(obj);
|
|
42
|
-
}
|
|
39
|
+
obj = expandFlatSyntax(obj, options);
|
|
43
40
|
for (let key of Object.keys(obj)) {
|
|
44
41
|
const value = obj[key];
|
|
45
|
-
const isUnknown =
|
|
42
|
+
const isUnknown = !isKnownKey(key, this, options);
|
|
46
43
|
if (value === '' && stripEmpty || isUnknown && stripUnknown) {
|
|
47
44
|
continue;
|
|
48
45
|
} else if (isUnknown) {
|
|
@@ -262,12 +259,14 @@ class ObjectSchema extends _TypeSchema.default {
|
|
|
262
259
|
/**
|
|
263
260
|
* `stripEmpty` - Removes properties that are empty strings.
|
|
264
261
|
* `stripUnknown` - Removes properties not in the schema.
|
|
265
|
-
* `
|
|
262
|
+
* `allowFlatKeys` - Allows "flat" keys like `profile.name`.
|
|
263
|
+
* `expendFlatKeys` - Expands "flat" keys into nested objects.
|
|
266
264
|
*
|
|
267
265
|
* @param {Object} [options]
|
|
268
266
|
* @param {boolean} [options.stripEmpty]
|
|
269
267
|
* @param {boolean} [options.stripUnknown]
|
|
270
|
-
* @param {boolean} [options.
|
|
268
|
+
* @param {boolean} [options.allowFlatKeys]
|
|
269
|
+
* @param {boolean} [options.expandFlatKeys]
|
|
271
270
|
*/
|
|
272
271
|
options(options) {
|
|
273
272
|
return super.options(options);
|
|
@@ -297,7 +296,10 @@ class ObjectSchema extends _TypeSchema.default {
|
|
|
297
296
|
};
|
|
298
297
|
}
|
|
299
298
|
}
|
|
300
|
-
function
|
|
299
|
+
function expandFlatSyntax(obj, options) {
|
|
300
|
+
if (!options.expandFlatKeys) {
|
|
301
|
+
return obj;
|
|
302
|
+
}
|
|
301
303
|
const result = {
|
|
302
304
|
...obj
|
|
303
305
|
};
|
|
@@ -309,6 +311,66 @@ function expandKeys(obj) {
|
|
|
309
311
|
}
|
|
310
312
|
return result;
|
|
311
313
|
}
|
|
314
|
+
function isKnownKey(key, schema, options) {
|
|
315
|
+
const {
|
|
316
|
+
fields
|
|
317
|
+
} = schema.meta;
|
|
318
|
+
const {
|
|
319
|
+
allowFlatKeys
|
|
320
|
+
} = options;
|
|
321
|
+
if (!fields) {
|
|
322
|
+
// No fields defined -> all keys are "known".
|
|
323
|
+
return true;
|
|
324
|
+
} else if (key in fields) {
|
|
325
|
+
// Exact match -> key is known.
|
|
326
|
+
return true;
|
|
327
|
+
} else if (allowFlatKeys && key.includes('.')) {
|
|
328
|
+
// Flat syntax "foo.bar".
|
|
329
|
+
const [base, ...rest] = key.split('.');
|
|
330
|
+
let subschema = fields[base];
|
|
331
|
+
if (!subschema) {
|
|
332
|
+
return false;
|
|
333
|
+
}
|
|
334
|
+
const {
|
|
335
|
+
type,
|
|
336
|
+
schemas
|
|
337
|
+
} = subschema.meta;
|
|
338
|
+
let subkey;
|
|
339
|
+
if (type === 'array') {
|
|
340
|
+
// If the subschema is an array then take the first of
|
|
341
|
+
// its defined schemas as we can safely assume that an
|
|
342
|
+
// array of objects will be defined as a single element
|
|
343
|
+
// or multiple schemas will only set the base property.
|
|
344
|
+
// Test that the element key is valid and take any
|
|
345
|
+
// further properties as the subkey. Examples:
|
|
346
|
+
// - profiles.0.name (array of objects)
|
|
347
|
+
// - profiles.0 (array of stringsmk)
|
|
348
|
+
const [index, ...other] = rest;
|
|
349
|
+
if (!INTEGER_REG.test(index)) {
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
352
|
+
subschema = schemas[0];
|
|
353
|
+
subkey = other.join('.');
|
|
354
|
+
} else if (type === 'object') {
|
|
355
|
+
// If the subschema is an object then simply take any
|
|
356
|
+
// further properties as the subkey. Example:
|
|
357
|
+
// - profile.name
|
|
358
|
+
subkey = rest.join('.');
|
|
359
|
+
} else {
|
|
360
|
+
// If the subschema is anything else then disallow it
|
|
361
|
+
// further properties as the subkey. Example:
|
|
362
|
+
// - profile.name
|
|
363
|
+
return false;
|
|
364
|
+
}
|
|
365
|
+
if (subschema.meta.type === 'object') {
|
|
366
|
+
return isKnownKey(subkey, subschema, options);
|
|
367
|
+
} else {
|
|
368
|
+
return !subkey;
|
|
369
|
+
}
|
|
370
|
+
} else {
|
|
371
|
+
return false;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
312
374
|
function mergeFields(aFields, bFields) {
|
|
313
375
|
if (!aFields || !bFields) {
|
|
314
376
|
return aFields || bFields;
|
package/dist/cjs/string.js
CHANGED
|
@@ -8,6 +8,7 @@ var _validator = _interopRequireDefault(require("validator"));
|
|
|
8
8
|
var _TypeSchema = _interopRequireDefault(require("./TypeSchema"));
|
|
9
9
|
var _errors = require("./errors");
|
|
10
10
|
var _password = require("./password");
|
|
11
|
+
var _utils = require("./utils");
|
|
11
12
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
12
13
|
const SLUG_REG = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
13
14
|
const PHONE_REG = /^\+\d{1,3}\d{3,14}$/;
|
|
@@ -31,11 +32,7 @@ class StringSchema extends _TypeSchema.default {
|
|
|
31
32
|
return val;
|
|
32
33
|
});
|
|
33
34
|
this.assert('empty', (val, options) => {
|
|
34
|
-
|
|
35
|
-
required,
|
|
36
|
-
allowEmpty
|
|
37
|
-
} = options;
|
|
38
|
-
if (val === '' && (required || allowEmpty === false)) {
|
|
35
|
+
if (val === '' && !(0, _utils.canAllowEmptyString)(options)) {
|
|
39
36
|
throw new _errors.LocalizedError('Value is required.');
|
|
40
37
|
}
|
|
41
38
|
return val;
|
|
@@ -411,10 +408,7 @@ class StringSchema extends _TypeSchema.default {
|
|
|
411
408
|
return this.clone({
|
|
412
409
|
format: name
|
|
413
410
|
}).assert('format', function (val, options) {
|
|
414
|
-
|
|
415
|
-
allowEmpty
|
|
416
|
-
} = options;
|
|
417
|
-
if (val === '' && allowEmpty !== false) {
|
|
411
|
+
if (val === '' && (0, _utils.canAllowEmptyString)(options)) {
|
|
418
412
|
return;
|
|
419
413
|
}
|
|
420
414
|
fn(val, options);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.canAllowEmptyString = canAllowEmptyString;
|
|
7
|
+
function canAllowEmptyString(options) {
|
|
8
|
+
const {
|
|
9
|
+
type,
|
|
10
|
+
required,
|
|
11
|
+
allowEmpty = true
|
|
12
|
+
} = options;
|
|
13
|
+
return type === 'string' && !required && allowEmpty;
|
|
14
|
+
}
|
package/eslint.config.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bedrockio/yada",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "Validation library inspired by Joi.",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "jest",
|
|
@@ -24,12 +24,12 @@
|
|
|
24
24
|
"@babel/cli": "^7.20.7",
|
|
25
25
|
"@babel/core": "^7.20.12",
|
|
26
26
|
"@babel/preset-env": "^7.20.2",
|
|
27
|
-
"@bedrockio/eslint-plugin": "^1.
|
|
28
|
-
"@bedrockio/prettier-config": "^1.
|
|
27
|
+
"@bedrockio/eslint-plugin": "^1.2.2",
|
|
28
|
+
"@bedrockio/prettier-config": "^1.1.1",
|
|
29
29
|
"babel-plugin-add-module-exports": "^1.0.4",
|
|
30
|
-
"eslint": "^9.
|
|
31
|
-
"jest": "^
|
|
32
|
-
"prettier": "^3.
|
|
30
|
+
"eslint": "^9.36.0",
|
|
31
|
+
"jest": "^30.1.3",
|
|
32
|
+
"prettier": "^3.6.2",
|
|
33
33
|
"typescript": "^5.7.2"
|
|
34
34
|
},
|
|
35
35
|
"prettier": "@bedrockio/prettier-config",
|
package/src/Schema.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { omit, uniqBy } from 'lodash';
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
-
TypeError,
|
|
5
|
-
FormatError,
|
|
6
4
|
AllowedError,
|
|
7
5
|
AssertionError,
|
|
6
|
+
FormatError,
|
|
8
7
|
LocalizedError,
|
|
8
|
+
TypeError,
|
|
9
9
|
ValidationError,
|
|
10
10
|
} from './errors';
|
|
11
11
|
|
|
12
|
+
import { canAllowEmptyString } from './utils';
|
|
13
|
+
|
|
12
14
|
const INITIAL_TYPES = ['default', 'required', 'type', 'transform', 'empty'];
|
|
13
15
|
const REQUIRED_TYPES = ['default', 'required', 'missing'];
|
|
14
16
|
|
|
@@ -329,6 +331,9 @@ export default class Schema {
|
|
|
329
331
|
set = set[0];
|
|
330
332
|
}
|
|
331
333
|
return this.clone({ enum: set }).assert('enum', async (val, options) => {
|
|
334
|
+
if (val === '' && canAllowEmptyString(options)) {
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
332
337
|
if (val !== undefined) {
|
|
333
338
|
let captured = [];
|
|
334
339
|
|
package/src/errors.js
CHANGED
package/src/index.js
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import Schema from './Schema';
|
|
2
|
+
import { isSchema } from './Schema';
|
|
3
|
+
import array from './array';
|
|
3
4
|
import boolean from './boolean';
|
|
4
5
|
import date from './date';
|
|
5
|
-
import object from './object';
|
|
6
|
-
import array from './array';
|
|
7
|
-
import tuple from './tuple';
|
|
8
|
-
|
|
9
|
-
import Schema from './Schema';
|
|
10
|
-
import { useLocalizer, getLocalizedMessages } from './localization';
|
|
11
6
|
import { LocalizedError } from './errors';
|
|
12
|
-
|
|
13
|
-
import { isSchema } from './Schema';
|
|
14
7
|
import { isSchemaError } from './errors';
|
|
8
|
+
import { getLocalizedMessages, useLocalizer } from './localization';
|
|
9
|
+
import number from './number';
|
|
10
|
+
import object from './object';
|
|
11
|
+
import string from './string';
|
|
12
|
+
import tuple from './tuple';
|
|
15
13
|
|
|
16
14
|
/**
|
|
17
15
|
* Accepts anything.
|
|
@@ -43,22 +41,22 @@ function custom(fn) {
|
|
|
43
41
|
}
|
|
44
42
|
|
|
45
43
|
export {
|
|
44
|
+
LocalizedError,
|
|
45
|
+
allow,
|
|
46
|
+
any,
|
|
46
47
|
array,
|
|
47
48
|
boolean,
|
|
49
|
+
custom,
|
|
48
50
|
date,
|
|
51
|
+
getLocalizedMessages,
|
|
52
|
+
isSchema,
|
|
53
|
+
isSchemaError,
|
|
49
54
|
number,
|
|
50
55
|
object,
|
|
56
|
+
reject,
|
|
51
57
|
string,
|
|
52
58
|
tuple,
|
|
53
|
-
any,
|
|
54
|
-
allow,
|
|
55
|
-
reject,
|
|
56
|
-
custom,
|
|
57
|
-
isSchema,
|
|
58
|
-
isSchemaError,
|
|
59
59
|
useLocalizer,
|
|
60
|
-
getLocalizedMessages,
|
|
61
|
-
LocalizedError,
|
|
62
60
|
};
|
|
63
61
|
|
|
64
62
|
export default {
|
package/src/object.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { omit, pick, set } from 'lodash';
|
|
2
2
|
|
|
3
|
+
import Schema, { isSchema } from './Schema';
|
|
3
4
|
import TypeSchema from './TypeSchema';
|
|
4
5
|
import { FieldError, LocalizedError } from './errors';
|
|
5
|
-
import Schema, { isSchema } from './Schema';
|
|
6
6
|
|
|
7
7
|
const APPEND_ASSERTION_TYPES = ['required', 'type', 'custom'];
|
|
8
8
|
|
|
9
|
+
const INTEGER_REG = /^\d+$/;
|
|
10
|
+
|
|
9
11
|
/**
|
|
10
12
|
* @typedef {{ [key: string]: Schema } | {}} SchemaMap
|
|
11
13
|
*/
|
|
@@ -23,15 +25,15 @@ class ObjectSchema extends TypeSchema {
|
|
|
23
25
|
}
|
|
24
26
|
});
|
|
25
27
|
this.transform((obj, options) => {
|
|
26
|
-
const {
|
|
28
|
+
const { stripUnknown, stripEmpty } = options;
|
|
27
29
|
if (obj) {
|
|
28
30
|
const result = {};
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
|
|
32
|
+
obj = expandFlatSyntax(obj, options);
|
|
33
|
+
|
|
32
34
|
for (let key of Object.keys(obj)) {
|
|
33
35
|
const value = obj[key];
|
|
34
|
-
const isUnknown =
|
|
36
|
+
const isUnknown = !isKnownKey(key, this, options);
|
|
35
37
|
|
|
36
38
|
if ((value === '' && stripEmpty) || (isUnknown && stripUnknown)) {
|
|
37
39
|
continue;
|
|
@@ -253,12 +255,14 @@ class ObjectSchema extends TypeSchema {
|
|
|
253
255
|
/**
|
|
254
256
|
* `stripEmpty` - Removes properties that are empty strings.
|
|
255
257
|
* `stripUnknown` - Removes properties not in the schema.
|
|
256
|
-
* `
|
|
258
|
+
* `allowFlatKeys` - Allows "flat" keys like `profile.name`.
|
|
259
|
+
* `expendFlatKeys` - Expands "flat" keys into nested objects.
|
|
257
260
|
*
|
|
258
261
|
* @param {Object} [options]
|
|
259
262
|
* @param {boolean} [options.stripEmpty]
|
|
260
263
|
* @param {boolean} [options.stripUnknown]
|
|
261
|
-
* @param {boolean} [options.
|
|
264
|
+
* @param {boolean} [options.allowFlatKeys]
|
|
265
|
+
* @param {boolean} [options.expandFlatKeys]
|
|
262
266
|
*/
|
|
263
267
|
options(options) {
|
|
264
268
|
return super.options(options);
|
|
@@ -288,7 +292,11 @@ class ObjectSchema extends TypeSchema {
|
|
|
288
292
|
}
|
|
289
293
|
}
|
|
290
294
|
|
|
291
|
-
function
|
|
295
|
+
function expandFlatSyntax(obj, options) {
|
|
296
|
+
if (!options.expandFlatKeys) {
|
|
297
|
+
return obj;
|
|
298
|
+
}
|
|
299
|
+
|
|
292
300
|
const result = { ...obj };
|
|
293
301
|
for (let [key, value] of Object.entries(result)) {
|
|
294
302
|
if (key.includes('.')) {
|
|
@@ -299,6 +307,65 @@ function expandKeys(obj) {
|
|
|
299
307
|
return result;
|
|
300
308
|
}
|
|
301
309
|
|
|
310
|
+
function isKnownKey(key, schema, options) {
|
|
311
|
+
const { fields } = schema.meta;
|
|
312
|
+
const { allowFlatKeys } = options;
|
|
313
|
+
if (!fields) {
|
|
314
|
+
// No fields defined -> all keys are "known".
|
|
315
|
+
return true;
|
|
316
|
+
} else if (key in fields) {
|
|
317
|
+
// Exact match -> key is known.
|
|
318
|
+
return true;
|
|
319
|
+
} else if (allowFlatKeys && key.includes('.')) {
|
|
320
|
+
// Flat syntax "foo.bar".
|
|
321
|
+
const [base, ...rest] = key.split('.');
|
|
322
|
+
let subschema = fields[base];
|
|
323
|
+
|
|
324
|
+
if (!subschema) {
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const { type, schemas } = subschema.meta;
|
|
329
|
+
|
|
330
|
+
let subkey;
|
|
331
|
+
|
|
332
|
+
if (type === 'array') {
|
|
333
|
+
// If the subschema is an array then take the first of
|
|
334
|
+
// its defined schemas as we can safely assume that an
|
|
335
|
+
// array of objects will be defined as a single element
|
|
336
|
+
// or multiple schemas will only set the base property.
|
|
337
|
+
// Test that the element key is valid and take any
|
|
338
|
+
// further properties as the subkey. Examples:
|
|
339
|
+
// - profiles.0.name (array of objects)
|
|
340
|
+
// - profiles.0 (array of stringsmk)
|
|
341
|
+
const [index, ...other] = rest;
|
|
342
|
+
if (!INTEGER_REG.test(index)) {
|
|
343
|
+
return false;
|
|
344
|
+
}
|
|
345
|
+
subschema = schemas[0];
|
|
346
|
+
subkey = other.join('.');
|
|
347
|
+
} else if (type === 'object') {
|
|
348
|
+
// If the subschema is an object then simply take any
|
|
349
|
+
// further properties as the subkey. Example:
|
|
350
|
+
// - profile.name
|
|
351
|
+
subkey = rest.join('.');
|
|
352
|
+
} else {
|
|
353
|
+
// If the subschema is anything else then disallow it
|
|
354
|
+
// further properties as the subkey. Example:
|
|
355
|
+
// - profile.name
|
|
356
|
+
return false;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if (subschema.meta.type === 'object') {
|
|
360
|
+
return isKnownKey(subkey, subschema, options);
|
|
361
|
+
} else {
|
|
362
|
+
return !subkey;
|
|
363
|
+
}
|
|
364
|
+
} else {
|
|
365
|
+
return false;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
302
369
|
function mergeFields(aFields, bFields) {
|
|
303
370
|
if (!aFields || !bFields) {
|
|
304
371
|
return aFields || bFields;
|
package/src/string.js
CHANGED
|
@@ -2,15 +2,18 @@ import validator from 'validator';
|
|
|
2
2
|
|
|
3
3
|
import TypeSchema from './TypeSchema';
|
|
4
4
|
import { LocalizedError } from './errors';
|
|
5
|
+
|
|
5
6
|
import {
|
|
7
|
+
getPasswordOptions,
|
|
6
8
|
validateLength,
|
|
7
9
|
validateLowercase,
|
|
8
|
-
validateUppercase,
|
|
9
10
|
validateNumbers,
|
|
10
11
|
validateSymbols,
|
|
11
|
-
|
|
12
|
+
validateUppercase,
|
|
12
13
|
} from './password';
|
|
13
14
|
|
|
15
|
+
import { canAllowEmptyString } from './utils';
|
|
16
|
+
|
|
14
17
|
const SLUG_REG = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
15
18
|
const PHONE_REG = /^\+\d{1,3}\d{3,14}$/;
|
|
16
19
|
const NANP_REG = /^\+1[2-9]\d{2}[2-9]\d{6}$/;
|
|
@@ -37,8 +40,7 @@ class StringSchema extends TypeSchema {
|
|
|
37
40
|
return val;
|
|
38
41
|
});
|
|
39
42
|
this.assert('empty', (val, options) => {
|
|
40
|
-
|
|
41
|
-
if (val === '' && (required || allowEmpty === false)) {
|
|
43
|
+
if (val === '' && !canAllowEmptyString(options)) {
|
|
42
44
|
throw new LocalizedError('Value is required.');
|
|
43
45
|
}
|
|
44
46
|
return val;
|
|
@@ -429,8 +431,7 @@ class StringSchema extends TypeSchema {
|
|
|
429
431
|
return this.clone({ format: name }).assert(
|
|
430
432
|
'format',
|
|
431
433
|
function (val, options) {
|
|
432
|
-
|
|
433
|
-
if (val === '' && allowEmpty !== false) {
|
|
434
|
+
if (val === '' && canAllowEmptyString(options)) {
|
|
434
435
|
return;
|
|
435
436
|
}
|
|
436
437
|
fn(val, options);
|
package/src/utils.js
ADDED
package/types/Schema.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Schema.d.ts","sourceRoot":"","sources":["../src/Schema.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Schema.d.ts","sourceRoot":"","sources":["../src/Schema.js"],"names":[],"mappings":"AAgBA,kDAEC;AAED;IACE,uBAGC;IAFC,kBAAoB;IACpB,SAAgB;IAKlB;;OAEG;IACH,YAFa,IAAI,CAQhB;IAED;;;OAGG;IACH,mBAFa,IAAI,CAShB;IAED;;;;OAIG;IACH,sBAFa,IAAI,CAShB;IAED;;;;OAIG;IACH,uBAFa,IAAI,CAShB;IAED;;;;OAIG;IACH,mBAFa,IAAI,CAIhB;IAED;;;OAGG;IACH,sBAFa,IAAI,CAIhB;IAED;;;OAGG;IACH,uBAFa,IAAI,CAIhB;IAED;;;OAGG;IACH,YAFa,IAAI,CAIhB;IAED;;OAEG;IACH,uBAFa,IAAI,CAIhB;IAED;;OAEG;IACH,gBAFa,IAAI,CAShB;IAED;;OAEG;IACH,+BAFa,IAAI,CAMhB;IAED;;OAEG;IACH,uBAFa,IAAI,CAIhB;IAED,iDAwCC;IAED;;OAEG;IACH,kBAFa,IAAI,CAOhB;IAED;;;OAGG;IACH,qBAFa,MAAM,CAMlB;IAED;;;;;OAKG;IACH,yBAWC;IAED;;;OAGG;IACH,gCAEC;IAED;;MAOC;IAED;;;;MASC;IAED;;MAOC;IAED,eAsCC;IAED,4BAMC;IAED,kBAEC;IAED,YAGC;IAID;;OAEG;IACH,kCAFa,IAAI,CAsDhB;IAED;;OAEG;IACH,4BAFa,IAAI,CAUhB;IAED,oCAKC;IAED,gEAQC;IAED;;OAEG;IACH,oBAFa,IAAI,CAShB;IAED,gCAGC;IAED,qEAYC;CACF"}
|
package/types/index.d.ts
CHANGED
|
@@ -17,35 +17,35 @@ declare namespace _default {
|
|
|
17
17
|
export { LocalizedError };
|
|
18
18
|
}
|
|
19
19
|
export default _default;
|
|
20
|
-
import
|
|
21
|
-
import boolean from './boolean';
|
|
22
|
-
import date from './date';
|
|
23
|
-
import number from './number';
|
|
24
|
-
import object from './object';
|
|
25
|
-
import string from './string';
|
|
26
|
-
import tuple from './tuple';
|
|
27
|
-
/**
|
|
28
|
-
* Accepts anything.
|
|
29
|
-
*/
|
|
30
|
-
export function any(): Schema;
|
|
20
|
+
import { LocalizedError } from './errors';
|
|
31
21
|
/**
|
|
32
22
|
* Accept values or schemas. [Link](https://github.com/bedrockio/yada#allow)
|
|
33
23
|
*/
|
|
34
24
|
export function allow(...args: any[]): Schema;
|
|
35
25
|
/**
|
|
36
|
-
*
|
|
26
|
+
* Accepts anything.
|
|
37
27
|
*/
|
|
38
|
-
export function
|
|
28
|
+
export function any(): Schema;
|
|
29
|
+
import array from './array';
|
|
30
|
+
import boolean from './boolean';
|
|
39
31
|
/**
|
|
40
32
|
* Validate by a custom function. [Link](https://github.com/bedrockio/yada#custom)
|
|
41
33
|
* @param {Function} fn
|
|
42
34
|
*/
|
|
43
35
|
export function custom(fn: Function): Schema;
|
|
36
|
+
import date from './date';
|
|
37
|
+
import { getLocalizedMessages } from './localization';
|
|
44
38
|
import { isSchema } from './Schema';
|
|
45
39
|
import { isSchemaError } from './errors';
|
|
40
|
+
import number from './number';
|
|
41
|
+
import object from './object';
|
|
42
|
+
/**
|
|
43
|
+
* Reject values or schemas. [Link](https://github.com/bedrockio/yada#reject)
|
|
44
|
+
*/
|
|
45
|
+
export function reject(...args: any[]): Schema;
|
|
46
|
+
import string from './string';
|
|
47
|
+
import tuple from './tuple';
|
|
46
48
|
import { useLocalizer } from './localization';
|
|
47
|
-
import { getLocalizedMessages } from './localization';
|
|
48
|
-
import { LocalizedError } from './errors';
|
|
49
49
|
import Schema from './Schema';
|
|
50
|
-
export { array, boolean, date,
|
|
50
|
+
export { LocalizedError, array, boolean, date, getLocalizedMessages, isSchema, isSchemaError, number, object, string, tuple, useLocalizer };
|
|
51
51
|
//# sourceMappingURL=index.d.ts.map
|
package/types/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;+BAK+B,UAAU;AAezC;;GAEG;AACH,8CAEC;AAZD;;GAEG;AACH,8BAEC;kBAhBiB,SAAS;oBACP,WAAW;AA+B/B;;;GAGG;AACH,6CAEC;iBApCgB,QAAQ;qCAG0B,gBAAgB;yBAN1C,UAAU;8BAKL,UAAU;mBAErB,UAAU;mBACV,UAAU;AAkB7B;;GAEG;AACH,+CAEC;mBAtBkB,UAAU;kBACX,SAAS;6BAJwB,gBAAgB;mBAPhD,UAAU"}
|
package/types/object.d.ts
CHANGED
|
@@ -74,17 +74,20 @@ declare class ObjectSchema extends TypeSchema {
|
|
|
74
74
|
/**
|
|
75
75
|
* `stripEmpty` - Removes properties that are empty strings.
|
|
76
76
|
* `stripUnknown` - Removes properties not in the schema.
|
|
77
|
-
* `
|
|
77
|
+
* `allowFlatKeys` - Allows "flat" keys like `profile.name`.
|
|
78
|
+
* `expendFlatKeys` - Expands "flat" keys into nested objects.
|
|
78
79
|
*
|
|
79
80
|
* @param {Object} [options]
|
|
80
81
|
* @param {boolean} [options.stripEmpty]
|
|
81
82
|
* @param {boolean} [options.stripUnknown]
|
|
82
|
-
* @param {boolean} [options.
|
|
83
|
+
* @param {boolean} [options.allowFlatKeys]
|
|
84
|
+
* @param {boolean} [options.expandFlatKeys]
|
|
83
85
|
*/
|
|
84
86
|
options(options?: {
|
|
85
87
|
stripEmpty?: boolean;
|
|
86
88
|
stripUnknown?: boolean;
|
|
87
|
-
|
|
89
|
+
allowFlatKeys?: boolean;
|
|
90
|
+
expandFlatKeys?: boolean;
|
|
88
91
|
}): this;
|
|
89
92
|
}
|
|
90
93
|
import Schema from './Schema';
|
package/types/object.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"object.d.ts","sourceRoot":"","sources":["../src/object.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"object.d.ts","sourceRoot":"","sources":["../src/object.js"],"names":[],"mappings":"AAkYA;;;;;;GAMG;AACH,uCAJW,SAAS,gBAQnB;wBAlYY;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,GAAG,EAAE;AAD3C;;GAEG;AAEH;IACE,uBAGC;IAED,cA8EC;IAED;;;;;;OAMG;IACH,WAFW,MAAM,GAAC,KAAK,CAAC,MAAM,CAAC,OAsB9B;IAED;;;;;;OAMG;IACH,cAFW,MAAM,GAAC,KAAK,CAAC,MAAM,CAAC,OAY9B;IAED;;;;OAIG;IACH,gBAFc,MAAM,EAAA,gBASnB;IAED;;;;OAIG;IACH,gBAFc,MAAM,EAAA,gBASnB;IAED;;;;;;;OAOG;IACH,mBAHc,MAAM,EAAA,gBAmBnB;IAED;;;;;;OAMG;IACH,cAEC;IAED;;;;;;;;;OASG;IACH,YAFW,SAAS,GAAC,MAAM,gBA+B1B;IAED;;;;;;;;;;;OAWG;IACH,kBALG;QAA0B,UAAU,GAA5B,OAAO;QACW,YAAY,GAA9B,OAAO;QACW,aAAa,GAA/B,OAAO;QACW,cAAc,GAAhC,OAAO;KAA0B,QAI3C;CAwBF;mBAlSgC,UAAU;uBACpB,cAAc"}
|
package/types/string.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"string.d.ts","sourceRoot":"","sources":["../src/string.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"string.d.ts","sourceRoot":"","sources":["../src/string.js"],"names":[],"mappings":"AAycA;;GAEG;AACH,iDAEC;AAnbD;IACE,cAmBC;IAED;;OAEG;IACH,YAFa,IAAI,CAQhB;IAED;;OAEG;IACH,eAFW,MAAM,QAUhB;IAED;;OAEG;IACH,YAFW,MAAM,QAUhB;IAED;;OAEG;IACH,YAFW,MAAM,QAUhB;IAED,aAIC;IAED;;OAEG;IACH,mBAFW,OAAO,QAYjB;IAED;;OAEG;IACH,mBAFW,OAAO,QAYjB;IAED;;OAEG;IACH,WAFW,MAAM,QAahB;IAED,cAMC;IAED,uBASC;IAED,YAMC;IAED,YAMC;IAED,aAMC;IAED,cAMC;IAED;;;OAGG;IACH,iBAFG;QAA0B,OAAO,GAAzB,OAAO;KAAmB,QAQpC;IAED,mBAMC;IAED,WAMC;IAED,gBAMC;IAED,eAMC;IAED,YAMC;IAED,aAOC;IAED,eAMC;IAED;;OAEG;IACH,oBAFW,MAAM,QAQhB;IAED,gBAMC;IAED;;;;;;;OAOG;IACH,mBANG;QAAyB,SAAS,GAA1B,MAAM;QACW,UAAU,GAA3B,MAAM;QACW,UAAU,GAA3B,MAAM;QACW,YAAY,GAA7B,MAAM;QACW,YAAY,GAA7B,MAAM;KAAwB,QA+BxC;IAED;;;;;;;;;;;OAWG;IACH,cAVG;QAA0B,gBAAgB,GAAlC,OAAO;QACW,sBAAsB,GAAxC,OAAO;QACW,YAAY,GAA9B,OAAO;QACW,YAAY,GAA9B,OAAO;QACW,4BAA4B,GAA9C,OAAO;QACW,eAAe,GAAjC,OAAO;QACW,sBAAsB,GAAxC,OAAO;QACW,eAAe,GAAjC,OAAO;QACY,SAAS,GAA5B,MAAM,EAAE;KAAqB,QAQvC;IAED;;;;;;;;OAQG;IACH,iBAPG;QAA0B,WAAW,GAA7B,OAAO;QACW,iBAAiB,GAAnC,OAAO;QACW,kBAAkB,GAApC,OAAO;QACW,iBAAiB,GAAnC,OAAO;QACW,cAAc,GAAhC,OAAO;QACW,iBAAiB,GAAnC,OAAO;KAAmC,QAQpD;IAED;;OAEG;IACH,eAFW,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,QAQ3B;IAED,YAMC;IAED,YAMC;IAED,cAMC;IAED,cAMC;IAED;;;;;;;;;;;OAWG;IACH,iBAMC;IAED,iCAUC;CAgBF;uBArcsB,cAAc"}
|
package/types/utils.d.ts
CHANGED
|
@@ -1,5 +1,2 @@
|
|
|
1
|
-
export function
|
|
2
|
-
export function omit(obj: any, keys: any): {};
|
|
3
|
-
export { isSchema } from "./Schema";
|
|
4
|
-
export { isSchemaError } from "./errors";
|
|
1
|
+
export function canAllowEmptyString(options: any): any;
|
|
5
2
|
//# sourceMappingURL=utils.d.ts.map
|
package/types/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.js"],"names":[],"mappings":"AAAA,uDAGC"}
|