isvalid 4.0.23 → 4.1.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/index.js CHANGED
@@ -9,4 +9,4 @@
9
9
  import validate, { formalize, keyPaths, merge, plugins } from './lib/index.js';
10
10
 
11
11
  export default validate;
12
- export { formalize, keyPaths, merge, plugins };
12
+ export { validate, formalize, keyPaths, merge, plugins };
@@ -0,0 +1,18 @@
1
+ //
2
+ // aggregated.js
3
+ //
4
+ // Created by Kristian Trenskow on 2024-03-05
5
+ //
6
+ // See license in LICENSE
7
+ //
8
+
9
+ import ValidationError from './validation.js';
10
+
11
+ export default class AggregatedError extends ValidationError {
12
+
13
+ constructor(keyPath, schema, validator, message, errors) {
14
+ super(keyPath, schema, validator, message);
15
+ this.errors = errors;
16
+ }
17
+
18
+ }
package/lib/validate.js CHANGED
@@ -7,6 +7,7 @@
7
7
  //
8
8
 
9
9
  import ValidationError from './errors/validation.js';
10
+ import AggregatedError from './errors/aggregated.js';
10
11
  import { testIndex } from './ranges.js';
11
12
  import unique from './unique.js';
12
13
  import formalize from './formalize.js';
@@ -64,11 +65,39 @@ const validateObject = async (data, schema, options, keyPath, validatedData) =>
64
65
  return schema.schema[key1].priority - schema.schema[key2].priority;
65
66
  });
66
67
 
68
+ let errors = [];
69
+
67
70
  for (let key of keys) {
68
- let value = await validateAny(data[key], schema.schema[key], options, keyPath.concat([key]), validatedData);
69
- if (typeof value !== 'undefined') {
70
- data[key] = value;
71
+
72
+ try {
73
+ let value = await validateAny(data[key], schema.schema[key], options, keyPath.concat([key]), validatedData);
74
+ if (typeof value !== 'undefined') {
75
+ data[key] = value;
76
+ }
77
+ } catch (error) {
78
+
79
+ if (options.stopOnFirstError !== false) {
80
+ throw error;
81
+ }
82
+
83
+ errors.push(error);
84
+
71
85
  }
86
+
87
+ }
88
+
89
+ if (errors.length) {
90
+
91
+ if (errors.length === 1) throw errors[0];
92
+
93
+ throw new AggregatedError(
94
+ keyPath,
95
+ schema._nonFormalizedSchema,
96
+ 'object',
97
+ (schema.errors || {}).object || customErrorMessage(((options.errorMessages || {}).object || {}).object || 'Multiple errors occurred.'),
98
+ errors
99
+ );
100
+
72
101
  }
73
102
 
74
103
  }
@@ -97,9 +126,37 @@ const validateArray = async (data, schema, options, keyPath, validatedData) => {
97
126
  }
98
127
 
99
128
  if (typeof schema.schema !== 'undefined') {
100
- data = await Promise.all(data.map((data, idx) => {
101
- return validateAny(data, schema.schema, options, keyPath.concat([idx]), validatedData);
102
- }));
129
+
130
+ let errors = [];
131
+
132
+ for (let idx in data) {
133
+ try {
134
+ data[idx] = await validateAny(data[idx], schema.schema, options, keyPath.concat([idx]), validatedData);
135
+ } catch (error) {
136
+
137
+ if (options.stopOnFirstError !== false) {
138
+ throw error;
139
+ }
140
+
141
+ errors.push(error);
142
+
143
+ }
144
+ }
145
+
146
+ if (errors.length) {
147
+
148
+ if (errors.length === 1) throw errors[0];
149
+
150
+ throw new AggregatedError(
151
+ keyPath,
152
+ schema._nonFormalizedSchema,
153
+ 'array',
154
+ (schema.errors || {}).array || customErrorMessage(((options.errorMessages || {}).array || {}).array || 'Multiple errors occurred.'),
155
+ errors
156
+ );
157
+
158
+ }
159
+
103
160
  }
104
161
 
105
162
  if ((schema.len || options.defaults.len) && !testIndex((schema.len || options.defaults.len), data.length)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "isvalid",
3
- "version": "4.0.23",
3
+ "version": "4.1.0",
4
4
  "description": "Async JSON validation library for node.js.",
5
5
  "main": "./index.js",
6
6
  "type": "module",
package/test/validate.js CHANGED
@@ -8,6 +8,7 @@
8
8
 
9
9
  import { expect, assert } from 'chai';
10
10
  import ValidationError from '../lib/errors/validation.js';
11
+ import AggregatedError from '../lib/errors/aggregated.js';
11
12
  import isvalid from '../index.js';
12
13
  import { typeName, instanceTypeName, isSameType } from '../lib/utils.js';
13
14
 
@@ -476,17 +477,23 @@ describe('validate', function() {
476
477
  })).to.eventually.not.have.property('why');
477
478
  });
478
479
  describe('required', function() {
479
- it ('should come back with object key path when implicit.', () => {
480
+ it ('should come back with object key path when implicit (aggregated error).', () => {
480
481
  return expect(isvalid(undefined, {
481
482
  'myObject': {
482
- 'myKey': {
483
+ 'myFirstKey': {
484
+ type: String,
485
+ required: true
486
+ },
487
+ 'mySecondKey': {
483
488
  type: String,
484
489
  required: true
485
490
  }
486
- }}))
487
- .to.eventually.be.rejectedWith('Data is required.')
488
- .and.to.be.instanceOf(ValidationError)
489
- .and.have.property('keyPath').to.have.members(['myObject', 'myKey']);
491
+ }}, { keyPath: ['root'], stopOnFirstError: false }))
492
+ .to.eventually.be.rejectedWith('Multiple errors occurred.')
493
+ .and.to.be.instanceOf(AggregatedError)
494
+ .and.have.property('errors')
495
+ .and.have.property(0)
496
+ .and.have.property('message', 'Data is required.');
490
497
  });
491
498
  });
492
499
  describe('#errors', function() {
@@ -541,7 +548,7 @@ describe('validate', function() {
541
548
  }}, { keyPath: 'root'}))
542
549
  .to.eventually.be.rejectedWith('Is not of type string.')
543
550
  .and.to.be.instanceOf(ValidationError)
544
- .and.have.property('keyPath').eql(['root', 0]);
551
+ .and.have.property('keyPath').eql(['root', '0']);
545
552
  });
546
553
  });
547
554
  describe('len', function() {