@bedrockio/yada 1.6.1 → 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 +8 -0
- package/README.md +12 -2
- package/dist/cjs/object.js +72 -10
- package/dist/cjs/utils.js +2 -2
- package/package.json +1 -1
- package/src/object.js +75 -8
- package/src/utils.js +2 -2
- package/types/object.d.ts +6 -3
- package/types/object.d.ts.map +1 -1
- package/types/utils.d.ts +1 -1
- package/types/utils.d.ts.map +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
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
|
+
|
|
1
9
|
## 1.6.1
|
|
2
10
|
|
|
3
11
|
- Fixed empty string not allowed when enum provided.
|
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/object.js
CHANGED
|
@@ -12,6 +12,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
|
12
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); }
|
|
13
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; }
|
|
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/utils.js
CHANGED
package/package.json
CHANGED
package/src/object.js
CHANGED
|
@@ -6,6 +6,8 @@ import { FieldError, LocalizedError } from './errors';
|
|
|
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/utils.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export function canAllowEmptyString(options) {
|
|
2
|
-
const { type, required, allowEmpty } = options;
|
|
3
|
-
return type === 'string' && !required && allowEmpty
|
|
2
|
+
const { type, required, allowEmpty = true } = options;
|
|
3
|
+
return type === 'string' && !required && allowEmpty;
|
|
4
4
|
}
|
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/utils.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export function canAllowEmptyString(options: any):
|
|
1
|
+
export function canAllowEmptyString(options: any): any;
|
|
2
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":"AAAA,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.js"],"names":[],"mappings":"AAAA,uDAGC"}
|