@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 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
 
@@ -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) {
@@ -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 _string = _interopRequireDefault(require("./string"));
84
- var _number = _interopRequireDefault(require("./number"));
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 _array = _interopRequireDefault(require("./array"));
91
+ var _string = _interopRequireDefault(require("./string"));
89
92
  var _tuple = _interopRequireDefault(require("./tuple"));
90
- var _Schema = _interopRequireWildcard(require("./Schema"));
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
  */
@@ -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
- var _Schema = _interopRequireWildcard(require("./Schema"));
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
- if (!preserveKeys) {
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 = !!fields && !(key in fields);
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
- * `preserveKeys` - Prevents expansion of "flat" keys using dot syntax.
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.preserveKeys]
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 expandKeys(obj) {
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;
@@ -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
- const {
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
- const {
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
@@ -1,3 +1,3 @@
1
- import { jest, recommended, nodeImports } from '@bedrockio/eslint-plugin';
1
+ import { jest, nodeImports, recommended } from '@bedrockio/eslint-plugin';
2
2
 
3
3
  export default [jest, recommended, nodeImports];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bedrockio/yada",
3
- "version": "1.6.0",
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.1.7",
28
- "@bedrockio/prettier-config": "^1.0.2",
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.19.0",
31
- "jest": "^29.6.2",
32
- "prettier": "^3.4.2",
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
@@ -1,5 +1,5 @@
1
- import { getFullMessage } from './messages';
2
1
  import { localize } from './localization';
2
+ import { getFullMessage } from './messages';
3
3
 
4
4
  export class LocalizedError extends Error {
5
5
  constructor(message, values = {}) {
package/src/index.js CHANGED
@@ -1,17 +1,15 @@
1
- import string from './string';
2
- import number from './number';
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 { set, pick, omit } from 'lodash';
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 { fields, stripUnknown, stripEmpty, preserveKeys } = options;
28
+ const { stripUnknown, stripEmpty } = options;
27
29
  if (obj) {
28
30
  const result = {};
29
- if (!preserveKeys) {
30
- obj = expandKeys(obj);
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 = !!fields && !(key in fields);
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
- * `preserveKeys` - Prevents expansion of "flat" keys using dot syntax.
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.preserveKeys]
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 expandKeys(obj) {
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
- getPasswordOptions,
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
- const { required, allowEmpty } = options;
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
- const { allowEmpty } = options;
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
@@ -0,0 +1,4 @@
1
+ export function canAllowEmptyString(options) {
2
+ const { type, required, allowEmpty = true } = options;
3
+ return type === 'string' && !required && allowEmpty;
4
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"Schema.d.ts","sourceRoot":"","sources":["../src/Schema.js"],"names":[],"mappings":"AAcA,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,CAmDhB;IAED;;OAEG;IACH,4BAFa,IAAI,CAUhB;IAED,oCAKC;IAED,gEAQC;IAED;;OAEG;IACH,oBAFa,IAAI,CAShB;IAED,gCAGC;IAED,qEAYC;CACF"}
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 array from './array';
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
- * Reject values or schemas. [Link](https://github.com/bedrockio/yada#reject)
26
+ * Accepts anything.
37
27
  */
38
- export function reject(...args: any[]): Schema;
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, number, object, string, tuple, isSchema, isSchemaError, useLocalizer, getLocalizedMessages, LocalizedError };
50
+ export { LocalizedError, array, boolean, date, getLocalizedMessages, isSchema, isSchemaError, number, object, string, tuple, useLocalizer };
51
51
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;kBAKkB,SAAS;oBAHP,WAAW;iBACd,QAAQ;mBAFN,UAAU;mBAGV,UAAU;mBAJV,UAAU;kBAMX,SAAS;AAS3B;;GAEG;AACH,8BAEC;AAED;;GAEG;AACH,8CAEC;AAED;;GAEG;AACH,+CAEC;AAED;;;GAGG;AACH,6CAEC;yBA9BwB,UAAU;8BACL,UAAU;6BAJW,gBAAgB;qCAAhB,gBAAgB;+BACpC,UAAU;mBAFtB,UAAU"}
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
- * `preserveKeys` - Prevents expansion of "flat" keys using dot syntax.
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.preserveKeys]
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
- preserveKeys?: boolean;
89
+ allowFlatKeys?: boolean;
90
+ expandFlatKeys?: boolean;
88
91
  }): this;
89
92
  }
90
93
  import Schema from './Schema';
@@ -1 +1 @@
1
- {"version":3,"file":"object.d.ts","sourceRoot":"","sources":["../src/object.js"],"names":[],"mappings":"AA+TA;;;;;;GAMG;AACH,uCAJW,SAAS,gBAQnB;wBAjUY;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;;;;;;;;;OASG;IACH,kBAJG;QAA0B,UAAU,GAA5B,OAAO;QACW,YAAY,GAA9B,OAAO;QACW,YAAY,GAA9B,OAAO;KAAwB,QAIzC;CAwBF;mBA5RgC,UAAU;uBAFpB,cAAc"}
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"}
@@ -1 +1 @@
1
- {"version":3,"file":"string.d.ts","sourceRoot":"","sources":["../src/string.js"],"names":[],"mappings":"AAwcA;;GAEG;AACH,iDAEC;AArbD;IACE,cAoBC;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,iCAWC;CAgBF;uBApcsB,cAAc"}
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 pick(obj: any, keys: any): {};
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
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.js"],"names":[],"mappings":"AAGA,8CAMC;AAED,8CAQC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.js"],"names":[],"mappings":"AAAA,uDAGC"}