@bedrockio/yada 1.4.3 → 1.5.1

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,12 @@
1
+ ## 1.5.1
2
+
3
+ - Require more strict adherence to JSON Schema.
4
+
5
+ ## 1.5.0
6
+
7
+ - Calendar date validator moved to string as it cannot work when coerced to a
8
+ date object.
9
+
1
10
  ## 1.4.3
2
11
 
3
12
  - Fixed date not allowing calendar date format without time.
package/dist/cjs/date.js CHANGED
@@ -95,17 +95,10 @@ class DateSchema extends _Schema.default {
95
95
  }
96
96
  });
97
97
  }
98
-
99
- /**
100
- * @param {"date" | "date-time"} format
101
- */
102
- iso(format = 'date-time') {
103
- if (format !== 'date' && format !== 'date-time') {
104
- throw new Error(`Invalid format ${JSON.stringify(format)}.`);
105
- }
98
+ iso() {
106
99
  return this.clone({
107
- format
108
- }).assert('format', (val, options) => {
100
+ format: 'date-time'
101
+ }).assert('format', (date, options) => {
109
102
  const {
110
103
  original
111
104
  } = options;
@@ -113,9 +106,7 @@ class DateSchema extends _Schema.default {
113
106
  if (!options.default) {
114
107
  throw new _errors.LocalizedError('Must be a string.');
115
108
  }
116
- } else if (format === 'date' && !_validator.default.isDate(original)) {
117
- throw new _errors.LocalizedError('Must be an ISO-8601 calendar date.');
118
- } else if (format === 'date-time' && !_validator.default.isISO8601(original)) {
109
+ } else if (!_validator.default.isISO8601(original)) {
119
110
  throw new _errors.LocalizedError('Must be in ISO-8601 format.');
120
111
  }
121
112
  });
@@ -213,9 +213,9 @@ class ObjectSchema extends _TypeSchema.default {
213
213
  /**
214
214
  * Returns the schema's fields as an object allowing them
215
215
  * to be "spread" to create new schemas. Note that doing
216
- * this will mean that custom and required assertions will
217
- * not be preserved. Compare to {@link append} which
218
- * preserves all assertions on the base schema.
216
+ * this will mean that custom and required assertions on
217
+ * the object itself will not be preserved. Compare to
218
+ * {@link append} which preserves all assertions.
219
219
  */
220
220
  export() {
221
221
  return this.meta.fields || {};
@@ -262,14 +262,23 @@ class ObjectSchema extends _TypeSchema.default {
262
262
  // Private
263
263
 
264
264
  toOpenApi(extra) {
265
+ const {
266
+ stripUnknown = false
267
+ } = this.meta;
268
+ const required = [];
265
269
  const properties = {};
266
270
  for (let [key, schema] of Object.entries(this.export())) {
267
271
  properties[key] = schema.toOpenApi(extra);
272
+ if (schema.meta.required) {
273
+ required.push(key);
274
+ }
268
275
  }
269
276
  return {
270
277
  ...super.toOpenApi(extra),
271
278
  ...(Object.keys(properties).length > 0 && {
272
- properties
279
+ properties,
280
+ required,
281
+ additionalProperties: stripUnknown
273
282
  })
274
283
  };
275
284
  }
@@ -12,6 +12,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
12
12
  const SLUG_REG = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
13
13
  const PHONE_REG = /^\+\d{1,3}\d{3,14}$/;
14
14
  const NANP_REG = /^\+1[2-9]\d{2}[2-9]\d{6}$/;
15
+ const DATE_REG = /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[01])$/;
15
16
  const E164_DESCRIPTION = 'A phone number in [E.164](https://en.wikipedia.org/wiki/E.164) format.';
16
17
  const NANP_DESCRIPTION = 'A phone number in [NANP](https://en.wikipedia.org/wiki/North_American_Numbering_Plan) format.';
17
18
  class StringSchema extends _TypeSchema.default {
@@ -386,6 +387,26 @@ class StringSchema extends _TypeSchema.default {
386
387
  }
387
388
  });
388
389
  }
390
+
391
+ /**
392
+ * Validates a calendar date in extended ISO-8601 format:
393
+ *
394
+ * 1. Must exactly match `YYYY-MM-DD`.
395
+ * 2. Year may not be negative.
396
+ * 3. Month must be 1-12.
397
+ * 4. Date must be 1-31.
398
+ *
399
+ * Note that only individual components are validated so impossible
400
+ * dates like "2020-02-30" are still considered valid.
401
+ *
402
+ */
403
+ calendar() {
404
+ return this.format('date', str => {
405
+ if (!DATE_REG.test(str)) {
406
+ throw new _errors.LocalizedError('Must be an ISO-8601 calendar date.');
407
+ }
408
+ });
409
+ }
389
410
  format(name, fn) {
390
411
  return this.clone({
391
412
  format: name
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bedrockio/yada",
3
- "version": "1.4.3",
3
+ "version": "1.5.1",
4
4
  "description": "Validation library inspired by Joi.",
5
5
  "scripts": {
6
6
  "test": "jest",
package/src/date.js CHANGED
@@ -90,25 +90,20 @@ class DateSchema extends Schema {
90
90
  });
91
91
  }
92
92
 
93
- /**
94
- * @param {"date" | "date-time"} format
95
- */
96
- iso(format = 'date-time') {
97
- if (format !== 'date' && format !== 'date-time') {
98
- throw new Error(`Invalid format ${JSON.stringify(format)}.`);
99
- }
100
- return this.clone({ format }).assert('format', (val, options) => {
101
- const { original } = options;
102
- if (typeof original !== 'string') {
103
- if (!options.default) {
104
- throw new LocalizedError('Must be a string.');
93
+ iso() {
94
+ return this.clone({ format: 'date-time' }).assert(
95
+ 'format',
96
+ (date, options) => {
97
+ const { original } = options;
98
+ if (typeof original !== 'string') {
99
+ if (!options.default) {
100
+ throw new LocalizedError('Must be a string.');
101
+ }
102
+ } else if (!validator.isISO8601(original)) {
103
+ throw new LocalizedError('Must be in ISO-8601 format.');
105
104
  }
106
- } else if (format === 'date' && !validator.isDate(original)) {
107
- throw new LocalizedError('Must be an ISO-8601 calendar date.');
108
- } else if (format === 'date-time' && !validator.isISO8601(original)) {
109
- throw new LocalizedError('Must be in ISO-8601 format.');
110
- }
111
- });
105
+ },
106
+ );
112
107
  }
113
108
 
114
109
  timestamp() {
package/src/object.js CHANGED
@@ -200,9 +200,9 @@ class ObjectSchema extends TypeSchema {
200
200
  /**
201
201
  * Returns the schema's fields as an object allowing them
202
202
  * to be "spread" to create new schemas. Note that doing
203
- * this will mean that custom and required assertions will
204
- * not be preserved. Compare to {@link append} which
205
- * preserves all assertions on the base schema.
203
+ * this will mean that custom and required assertions on
204
+ * the object itself will not be preserved. Compare to
205
+ * {@link append} which preserves all assertions.
206
206
  */
207
207
  export() {
208
208
  return this.meta.fields || {};
@@ -252,14 +252,22 @@ class ObjectSchema extends TypeSchema {
252
252
  // Private
253
253
 
254
254
  toOpenApi(extra) {
255
+ const { stripUnknown = false } = this.meta;
256
+
257
+ const required = [];
255
258
  const properties = {};
256
259
  for (let [key, schema] of Object.entries(this.export())) {
257
260
  properties[key] = schema.toOpenApi(extra);
261
+ if (schema.meta.required) {
262
+ required.push(key);
263
+ }
258
264
  }
259
265
  return {
260
266
  ...super.toOpenApi(extra),
261
267
  ...(Object.keys(properties).length > 0 && {
262
268
  properties,
269
+ required,
270
+ additionalProperties: stripUnknown,
263
271
  }),
264
272
  };
265
273
  }
package/src/string.js CHANGED
@@ -14,6 +14,7 @@ import {
14
14
  const SLUG_REG = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
15
15
  const PHONE_REG = /^\+\d{1,3}\d{3,14}$/;
16
16
  const NANP_REG = /^\+1[2-9]\d{2}[2-9]\d{6}$/;
17
+ const DATE_REG = /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[01])$/;
17
18
 
18
19
  const E164_DESCRIPTION =
19
20
  'A phone number in [E.164](https://en.wikipedia.org/wiki/E.164) format.';
@@ -404,6 +405,26 @@ class StringSchema extends TypeSchema {
404
405
  });
405
406
  }
406
407
 
408
+ /**
409
+ * Validates a calendar date in extended ISO-8601 format:
410
+ *
411
+ * 1. Must exactly match `YYYY-MM-DD`.
412
+ * 2. Year may not be negative.
413
+ * 3. Month must be 1-12.
414
+ * 4. Date must be 1-31.
415
+ *
416
+ * Note that only individual components are validated so impossible
417
+ * dates like "2020-02-30" are still considered valid.
418
+ *
419
+ */
420
+ calendar() {
421
+ return this.format('date', (str) => {
422
+ if (!DATE_REG.test(str)) {
423
+ throw new LocalizedError('Must be an ISO-8601 calendar date.');
424
+ }
425
+ });
426
+ }
427
+
407
428
  format(name, fn) {
408
429
  return this.clone({ format: name }).assert(
409
430
  'format',
package/types/date.d.ts CHANGED
@@ -22,10 +22,7 @@ declare class DateSchema extends Schema {
22
22
  after(min: string | number | Date): this;
23
23
  past(): this;
24
24
  future(): this;
25
- /**
26
- * @param {"date" | "date-time"} format
27
- */
28
- iso(format?: "date" | "date-time"): this;
25
+ iso(): this;
29
26
  timestamp(): this;
30
27
  unix(): this;
31
28
  }
@@ -1 +1 @@
1
- {"version":3,"file":"date.d.ts","sourceRoot":"","sources":["../src/date.js"],"names":[],"mappings":"AAqKA;;GAEG;AACH,+CAEC;AArKD;IACE,cAUC;IAED;;OAEG;IACH,SAFW,MAAM,GAAC,MAAM,GAAC,IAAI,QAW5B;IAED;;OAEG;IACH,SAFW,MAAM,GAAC,MAAM,GAAC,IAAI,QAW5B;IAED;;OAEG;IACH,YAFW,MAAM,GAAC,MAAM,GAAC,IAAI,QAW5B;IAED;;OAEG;IACH,WAFW,MAAM,GAAC,MAAM,GAAC,IAAI,QAW5B;IAED,aAOC;IAED,eAOC;IAED;;OAEG;IACH,aAFW,MAAM,GAAG,WAAW,QAkB9B;IAED,kBAUC;IAED,aAcC;CAwBF;mBAjKkB,UAAU"}
1
+ {"version":3,"file":"date.d.ts","sourceRoot":"","sources":["../src/date.js"],"names":[],"mappings":"AAgKA;;GAEG;AACH,+CAEC;AAhKD;IACE,cAUC;IAED;;OAEG;IACH,SAFW,MAAM,GAAC,MAAM,GAAC,IAAI,QAW5B;IAED;;OAEG;IACH,SAFW,MAAM,GAAC,MAAM,GAAC,IAAI,QAW5B;IAED;;OAEG;IACH,YAFW,MAAM,GAAC,MAAM,GAAC,IAAI,QAW5B;IAED;;OAEG;IACH,WAFW,MAAM,GAAC,MAAM,GAAC,IAAI,QAW5B;IAED,aAOC;IAED,eAOC;IAED,YAcC;IAED,kBAUC;IAED,aAcC;CAwBF;mBA5JkB,UAAU"}
package/types/object.d.ts CHANGED
@@ -55,9 +55,9 @@ declare class ObjectSchema extends TypeSchema {
55
55
  /**
56
56
  * Returns the schema's fields as an object allowing them
57
57
  * to be "spread" to create new schemas. Note that doing
58
- * this will mean that custom and required assertions will
59
- * not be preserved. Compare to {@link append} which
60
- * preserves all assertions on the base schema.
58
+ * this will mean that custom and required assertions on
59
+ * the object itself will not be preserved. Compare to
60
+ * {@link append} which preserves all assertions.
61
61
  */
62
62
  export(): any;
63
63
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"object.d.ts","sourceRoot":"","sources":["../src/object.js"],"names":[],"mappings":"AAmTA;;;;;;GAMG;AACH,uCAJW,SAAS,gBAQnB;wBArTY;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,gBAkBnB;IAED;;;;;;OAMG;IACH,cAEC;IAED;;;;;;;;;OASG;IACH,YAFW,SAAS,GAAC,MAAM,gBA+B1B;CAgBF;mBArQgC,UAAU;uBAFpB,cAAc"}
1
+ {"version":3,"file":"object.d.ts","sourceRoot":"","sources":["../src/object.js"],"names":[],"mappings":"AA2TA;;;;;;GAMG;AACH,uCAJW,SAAS,gBAQnB;wBA7TY;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,gBAkBnB;IAED;;;;;;OAMG;IACH,cAEC;IAED;;;;;;;;;OASG;IACH,YAFW,SAAS,GAAC,MAAM,gBA+B1B;CAwBF;mBA7QgC,UAAU;uBAFpB,cAAc"}
package/types/string.d.ts CHANGED
@@ -121,6 +121,19 @@ declare class StringSchema extends TypeSchema {
121
121
  eth(): this;
122
122
  swift(): this;
123
123
  mongo(): this;
124
+ /**
125
+ * Validates a calendar date in extended ISO-8601 format:
126
+ *
127
+ * 1. Must exactly match `YYYY-MM-DD`.
128
+ * 2. Year may not be negative.
129
+ * 3. Month must be 1-12.
130
+ * 4. Date must be 1-31.
131
+ *
132
+ * Note that only individual components are validated so impossible
133
+ * dates like "2020-02-30" are still considered valid.
134
+ *
135
+ */
136
+ calendar(): this;
124
137
  format(name: any, fn: any): this;
125
138
  }
126
139
  import TypeSchema from './TypeSchema';
@@ -1 +1 @@
1
- {"version":3,"file":"string.d.ts","sourceRoot":"","sources":["../src/string.js"],"names":[],"mappings":"AAmbA;;GAEG;AACH,iDAEC;AAjaD;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,iCAWC;CAgBF;uBA/asB,cAAc"}
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"}