@bedrockio/yada 1.0.16 → 1.0.17

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 CHANGED
@@ -15,6 +15,7 @@ Concepts
15
15
  - [Number](#number)
16
16
  - [Boolean](#boolean)
17
17
  - [Array](#array)
18
+ - [Tuple](#tuple)
18
19
  - [Object](#object)
19
20
  - [Date](#date)
20
21
  - [Common Methods](#common-methods)
@@ -254,12 +255,28 @@ const schema = yd.array([schemas]);
254
255
 
255
256
  #### Methods:
256
257
 
257
- - `max` - Length must be less than equal to `n` characters, passed as an
258
- argument.
259
- - `min` - Length must be more than or equal to `n` characters, passed as an
258
+ - `max` - Length must be less than equal to `n` elements.
259
+ - `min` - Length must be more than or equal to `n` elements.
260
+ - `length` - Length must be exactly `n` elements.
260
261
  - `latlng` - Must be a 2 element array of numbers that represent latitude (`-90`
261
262
  to `90`) and longitude(`-180` to `180`) coordinates.
262
263
 
264
+ ### Tuple
265
+
266
+ Tuple schemas are similar to arrays, however they validate the exact length as
267
+ well as types for a given position. Compare the following:
268
+
269
+ ```js
270
+ // Accepts any length of either strings or numbers.
271
+ const schema1 = yd.array(yd.string(), yd.number());
272
+ // Accepts exactly 2 elements. The first MUST be a
273
+ // string and the second MUST be a number.
274
+ const schema2 = yd.tuple(yd.string(), yd.number());
275
+ ```
276
+
277
+ Tuples are appropriate for strictly structured arrays, for example an array of
278
+ coordinates as latitude and longitude.
279
+
263
280
  ## Object
264
281
 
265
282
  Object schemas validate that input is an object and further validate individual
package/dist/cjs/index.js CHANGED
@@ -68,18 +68,25 @@ Object.defineProperty(exports, "string", {
68
68
  return _string.default;
69
69
  }
70
70
  });
71
+ Object.defineProperty(exports, "tuple", {
72
+ enumerable: true,
73
+ get: function () {
74
+ return _tuple.default;
75
+ }
76
+ });
71
77
  Object.defineProperty(exports, "useLocalizer", {
72
78
  enumerable: true,
73
79
  get: function () {
74
80
  return _localization.useLocalizer;
75
81
  }
76
82
  });
77
- var _array = _interopRequireDefault(require("./array"));
83
+ var _string = _interopRequireDefault(require("./string"));
84
+ var _number = _interopRequireDefault(require("./number"));
78
85
  var _boolean = _interopRequireDefault(require("./boolean"));
79
86
  var _date = _interopRequireDefault(require("./date"));
80
- var _number = _interopRequireDefault(require("./number"));
81
87
  var _object = _interopRequireDefault(require("./object"));
82
- var _string = _interopRequireDefault(require("./string"));
88
+ var _array = _interopRequireDefault(require("./array"));
89
+ var _tuple = _interopRequireDefault(require("./tuple"));
83
90
  var _Schema = _interopRequireDefault(require("./Schema"));
84
91
  var _utils = require("./utils");
85
92
  var _localization = require("./localization");
@@ -120,6 +127,7 @@ var _default = {
120
127
  number: _number.default,
121
128
  object: _object.default,
122
129
  string: _string.default,
130
+ tuple: _tuple.default,
123
131
  any,
124
132
  allow,
125
133
  reject,
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = _default;
7
+ var _Schema = _interopRequireDefault(require("./Schema"));
8
+ var _errors = require("./errors");
9
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
10
+ class TupleSchema extends _Schema.default {
11
+ constructor(schemas) {
12
+ super({
13
+ message: 'Tuple failed validation.',
14
+ schemas
15
+ });
16
+ this.setup();
17
+ }
18
+
19
+ /**
20
+ * @private
21
+ */
22
+ setup() {
23
+ const {
24
+ schemas
25
+ } = this.meta;
26
+ this.assert('type', (val, options) => {
27
+ if (typeof val === 'string' && options.cast) {
28
+ val = val.split(',');
29
+ }
30
+ if (!Array.isArray(val)) {
31
+ throw new _errors.LocalizedError('Must be an array.');
32
+ }
33
+ return val;
34
+ });
35
+ this.assert('length', val => {
36
+ const {
37
+ length
38
+ } = schemas;
39
+ if (val.length !== length) {
40
+ throw new _errors.LocalizedError('Tuple must be exactly {length} elements.', {
41
+ length: schemas.length
42
+ });
43
+ }
44
+ return val;
45
+ });
46
+ this.assert('elements', async (arr, options) => {
47
+ const errors = [];
48
+ const result = [];
49
+ for (let i = 0; i < schemas.length; i++) {
50
+ const schema = schemas[i];
51
+ const el = arr[i];
52
+ try {
53
+ result.push(await schema.validate(el, options));
54
+ } catch (error) {
55
+ if (error.details?.length === 1) {
56
+ errors.push(new _errors.ElementError(error.details[0].message, i));
57
+ } else {
58
+ errors.push(new _errors.ElementError('Element failed validation.', i, error.details));
59
+ }
60
+ }
61
+ }
62
+ if (errors.length) {
63
+ throw new _errors.ArrayError(this.meta.message, errors);
64
+ } else {
65
+ return result;
66
+ }
67
+ });
68
+ }
69
+ toString() {
70
+ return 'tuple';
71
+ }
72
+ toOpenApi(extra) {
73
+ const {
74
+ schemas
75
+ } = this.meta;
76
+ return {
77
+ type: 'array',
78
+ ...super.toOpenApi(extra),
79
+ prefixItems: schemas.map(schema => {
80
+ return schema.toOpenApi();
81
+ })
82
+ };
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Creates a [tuple schema](https://github.com/bedrockio/yada#tuple).
88
+ *
89
+ * @param {...Schema} [schemas] Schemas to validate
90
+ * the exact types of elements allowed in the tuple. Also
91
+ * accepts a single array argument.
92
+ */
93
+ function _default(...schemas) {
94
+ if (Array.isArray(schemas[0])) {
95
+ schemas = schemas[0];
96
+ }
97
+ return new TupleSchema(schemas);
98
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bedrockio/yada",
3
- "version": "1.0.16",
3
+ "version": "1.0.17",
4
4
  "description": "Validation library inspired by Joi.",
5
5
  "scripts": {
6
6
  "test": "jest",
package/src/index.js CHANGED
@@ -1,9 +1,10 @@
1
- import array from './array';
1
+ import string from './string';
2
+ import number from './number';
2
3
  import boolean from './boolean';
3
4
  import date from './date';
4
- import number from './number';
5
5
  import object from './object';
6
- import string from './string';
6
+ import array from './array';
7
+ import tuple from './tuple';
7
8
 
8
9
  import Schema from './Schema';
9
10
  import { isSchema, isSchemaError } from './utils';
@@ -46,6 +47,7 @@ export {
46
47
  number,
47
48
  object,
48
49
  string,
50
+ tuple,
49
51
  any,
50
52
  allow,
51
53
  reject,
@@ -64,6 +66,7 @@ export default {
64
66
  number,
65
67
  object,
66
68
  string,
69
+ tuple,
67
70
  any,
68
71
  allow,
69
72
  reject,
package/src/tuple.js ADDED
@@ -0,0 +1,91 @@
1
+ import Schema from './Schema';
2
+ import { ArrayError, ElementError, LocalizedError } from './errors';
3
+
4
+ class TupleSchema extends Schema {
5
+ constructor(schemas) {
6
+ super({ message: 'Tuple failed validation.', schemas });
7
+ this.setup();
8
+ }
9
+
10
+ /**
11
+ * @private
12
+ */
13
+ setup() {
14
+ const { schemas } = this.meta;
15
+
16
+ this.assert('type', (val, options) => {
17
+ if (typeof val === 'string' && options.cast) {
18
+ val = val.split(',');
19
+ }
20
+ if (!Array.isArray(val)) {
21
+ throw new LocalizedError('Must be an array.');
22
+ }
23
+ return val;
24
+ });
25
+
26
+ this.assert('length', (val) => {
27
+ const { length } = schemas;
28
+ if (val.length !== length) {
29
+ throw new LocalizedError('Tuple must be exactly {length} elements.', {
30
+ length: schemas.length,
31
+ });
32
+ }
33
+ return val;
34
+ });
35
+
36
+ this.assert('elements', async (arr, options) => {
37
+ const errors = [];
38
+ const result = [];
39
+
40
+ for (let i = 0; i < schemas.length; i++) {
41
+ const schema = schemas[i];
42
+ const el = arr[i];
43
+ try {
44
+ result.push(await schema.validate(el, options));
45
+ } catch (error) {
46
+ if (error.details?.length === 1) {
47
+ errors.push(new ElementError(error.details[0].message, i));
48
+ } else {
49
+ errors.push(
50
+ new ElementError('Element failed validation.', i, error.details)
51
+ );
52
+ }
53
+ }
54
+ }
55
+ if (errors.length) {
56
+ throw new ArrayError(this.meta.message, errors);
57
+ } else {
58
+ return result;
59
+ }
60
+ });
61
+ }
62
+
63
+ toString() {
64
+ return 'tuple';
65
+ }
66
+
67
+ toOpenApi(extra) {
68
+ const { schemas } = this.meta;
69
+ return {
70
+ type: 'array',
71
+ ...super.toOpenApi(extra),
72
+ prefixItems: schemas.map((schema) => {
73
+ return schema.toOpenApi();
74
+ }),
75
+ };
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Creates a [tuple schema](https://github.com/bedrockio/yada#tuple).
81
+ *
82
+ * @param {...Schema} [schemas] Schemas to validate
83
+ * the exact types of elements allowed in the tuple. Also
84
+ * accepts a single array argument.
85
+ */
86
+ export default function (...schemas) {
87
+ if (Array.isArray(schemas[0])) {
88
+ schemas = schemas[0];
89
+ }
90
+ return new TupleSchema(schemas);
91
+ }
package/types/index.d.ts CHANGED
@@ -5,6 +5,7 @@ declare namespace _default {
5
5
  export { number };
6
6
  export { object };
7
7
  export { string };
8
+ export { tuple };
8
9
  export { any };
9
10
  export { allow };
10
11
  export { reject };
@@ -22,6 +23,7 @@ import date from "./date";
22
23
  import number from "./number";
23
24
  import object from "./object";
24
25
  import string from "./string";
26
+ import tuple from "./tuple";
25
27
  /**
26
28
  * Accepts anything.
27
29
  */
@@ -45,5 +47,5 @@ import { useLocalizer } from "./localization";
45
47
  import { getLocalizedMessages } from "./localization";
46
48
  import { LocalizedError } from "./errors";
47
49
  import Schema from "./Schema";
48
- export { array, boolean, date, number, object, string, isSchema, isSchemaError, useLocalizer, getLocalizedMessages, LocalizedError };
50
+ export { array, boolean, date, number, object, string, tuple, isSchema, isSchemaError, useLocalizer, getLocalizedMessages, LocalizedError };
49
51
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAYA;;GAEG;AACH,8BAEC;AAED;;GAEG;AACH,8CAEC;AAED;;GAEG;AACH,+CAEC;AAED;;;GAGG;AACH,gCAFW,OAAO,UAAU,EAAE,eAAe,UAI5C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAaA;;GAEG;AACH,8BAEC;AAED;;GAEG;AACH,8CAEC;AAED;;GAEG;AACH,+CAEC;AAED;;;GAGG;AACH,gCAFW,OAAO,UAAU,EAAE,eAAe,UAI5C"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Creates a [tuple schema](https://github.com/bedrockio/yada#tuple).
3
+ *
4
+ * @param {...Schema} [schemas] Schemas to validate
5
+ * the exact types of elements allowed in the tuple. Also
6
+ * accepts a single array argument.
7
+ */
8
+ export default function _default(...schemas?: Schema[]): TupleSchema;
9
+ import Schema from "./Schema";
10
+ declare class TupleSchema extends Schema {
11
+ constructor(schemas: any);
12
+ /**
13
+ * @private
14
+ */
15
+ private setup;
16
+ }
17
+ export {};
18
+ //# sourceMappingURL=tuple.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tuple.d.ts","sourceRoot":"","sources":["../src/tuple.js"],"names":[],"mappings":"AA8EA;;;;;;GAMG;AACH,8CAJc,MAAM,iBASnB;;AAvFD;IACE,0BAGC;IAED;;OAEG;IACH,cAgDC;CAgBF"}