Skip to content

Commit dde11ca

Browse files
authored
chore: improve internal test run APIs and Error handling (#1545)
* docs * WIP * chore: clean up internal test running APIs * fix order
1 parent 57b81f4 commit dde11ca

11 files changed

+271
-273
lines changed

src/Lazy.ts

+7-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import isSchema from './util/isSchema';
2-
import type { AnyObject, Callback, ValidateOptions } from './types';
2+
import type { AnyObject, ValidateOptions } from './types';
33
import type { ResolveOptions } from './Condition';
44

55
import type {
@@ -82,13 +82,12 @@ class Lazy<T, TContext = AnyObject, TDefault = any, TFlags extends Flags = any>
8282
return this._resolve(value, options).cast(value, options);
8383
}
8484

85-
validate(
86-
value: any,
87-
options?: ValidateOptions,
88-
maybeCb?: Callback,
89-
): Promise<T> {
90-
// @ts-expect-error missing public callback on type
91-
return this._resolve(value, options).validate(value, options, maybeCb);
85+
asTest(value: any, options?: ValidateOptions<TContext>) {
86+
return this._resolve(value, options).asTest(value, options);
87+
}
88+
89+
validate(value: any, options?: ValidateOptions<TContext>): Promise<T> {
90+
return this._resolve(value, options).validate(value, options);
9291
}
9392

9493
validateSync(value: any, options?: ValidateOptions<TContext>): T {

src/array.ts

+22-33
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,13 @@ import isAbsent from './util/isAbsent';
22
import isSchema from './util/isSchema';
33
import printValue from './util/printValue';
44
import { array as locale } from './locale';
5-
import runTests, { RunTest } from './util/runTests';
65
import type {
76
AnyObject,
87
InternalOptions,
9-
Callback,
108
Message,
119
Maybe,
1210
Optionals,
1311
} from './types';
14-
import ValidationError from './ValidationError';
1512
import type Reference from './Reference';
1613
import {
1714
Defined,
@@ -24,9 +21,14 @@ import {
2421
UnsetFlag,
2522
Concat,
2623
} from './util/types';
27-
import Schema, { SchemaInnerTypeDescription, SchemaSpec } from './schema';
24+
import Schema, {
25+
RunTest,
26+
SchemaInnerTypeDescription,
27+
SchemaSpec,
28+
} from './schema';
2829
import { ResolveOptions } from './Condition';
2930
import parseJson from 'parse-json';
31+
import { ValidationError } from '.';
3032

3133
type InnerType<T> = T extends Array<infer I> ? I : never;
3234

@@ -36,9 +38,7 @@ export type RejectorFn = (
3638
array: readonly any[],
3739
) => boolean;
3840

39-
export function create<C extends AnyObject = AnyObject, T = any>(
40-
type?: ISchema<T, C>,
41-
) {
41+
export function create<C = AnyObject, T = any>(type?: ISchema<T, C>) {
4242
return new ArraySchema<T[] | undefined, C>(type as any);
4343
}
4444

@@ -89,28 +89,22 @@ export default class ArraySchema<
8989
protected _validate(
9090
_value: any,
9191
options: InternalOptions<TContext> = {},
92-
callback: Callback,
92+
93+
panic: (err: Error, value: unknown) => void,
94+
callback: (err: ValidationError[], value: unknown) => void,
9395
) {
94-
let errors = [] as ValidationError[];
95-
let sync = options.sync;
96-
let path = options.path;
96+
// let sync = options.sync;
97+
// let path = options.path;
9798
let innerType = this.innerType;
98-
let endEarly = options.abortEarly ?? this.spec.abortEarly;
99+
// let endEarly = options.abortEarly ?? this.spec.abortEarly;
99100
let recursive = options.recursive ?? this.spec.recursive;
100101

101102
let originalValue =
102103
options.originalValue != null ? options.originalValue : _value;
103104

104-
super._validate(_value, options, (err, value) => {
105-
if (err) {
106-
if (!ValidationError.isError(err) || endEarly) {
107-
return void callback(err, value);
108-
}
109-
errors.push(err);
110-
}
111-
105+
super._validate(_value, options, panic, (arrayErrors, value) => {
112106
if (!recursive || !innerType || !this._typeCheck(value)) {
113-
callback(errors[0] || null, value);
107+
callback(arrayErrors, value);
114108
return;
115109
}
116110

@@ -122,29 +116,24 @@ export default class ArraySchema<
122116
let item = value[idx];
123117
let path = `${options.path || ''}[${idx}]`;
124118

125-
// object._validate note for isStrict explanation
126-
let innerOptions = {
119+
tests[idx] = innerType!.asTest(item, {
127120
...options,
128121
path,
129-
strict: true,
130122
parent: value,
123+
// FIXME
131124
index: idx,
132125
originalValue: originalValue[idx],
133-
};
134-
135-
tests[idx] = (_, cb) => innerType!.validate(item, innerOptions, cb);
126+
});
136127
}
137128

138-
runTests(
129+
this.runTests(
139130
{
140-
sync,
141-
path,
142131
value,
143-
errors,
144-
endEarly,
145132
tests,
146133
},
147-
callback,
134+
panic,
135+
(innerTypeErrors) =>
136+
callback(innerTypeErrors.concat(arrayErrors), value),
148137
);
149138
});
150139
}

src/object.ts

+28-53
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,9 @@ import {
1212
import { object as locale } from './locale';
1313
import sortFields from './util/sortFields';
1414
import sortByKeyOrder from './util/sortByKeyOrder';
15-
import runTests from './util/runTests';
16-
import { InternalOptions, Callback, Maybe, Message } from './types';
17-
import ValidationError from './ValidationError';
15+
import { InternalOptions, Maybe, Message } from './types';
1816
import type { Defined, Thunk, NotNull, _ } from './util/types';
19-
import type Reference from './Reference';
17+
import Reference from './Reference';
2018
import Schema, { SchemaObjectDescription, SchemaSpec } from './schema';
2119
import { ResolveOptions } from './Condition';
2220
import type {
@@ -30,6 +28,8 @@ import type {
3028
TypeFromShape,
3129
} from './util/objectTypes';
3230
import parseJson from './util/parseJson';
31+
import type { Test } from './util/createValidation';
32+
import type ValidationError from './ValidationError';
3333

3434
export type { AnyObject };
3535

@@ -205,14 +205,12 @@ export default class ObjectSchema<
205205
protected _validate(
206206
_value: any,
207207
opts: InternalOptions<TContext> = {},
208-
callback: Callback,
208+
panic: (err: Error, value: unknown) => void,
209+
next: (err: ValidationError[], value: unknown) => void,
209210
) {
210-
let errors = [] as ValidationError[];
211211
let {
212-
sync,
213212
from = [],
214213
originalValue = _value,
215-
abortEarly = this.spec.abortEarly,
216214
recursive = this.spec.recursive,
217215
} = opts;
218216

@@ -224,64 +222,41 @@ export default class ObjectSchema<
224222
opts.originalValue = originalValue;
225223
opts.from = from;
226224

227-
super._validate(_value, opts, (err, value) => {
228-
if (err) {
229-
if (!ValidationError.isError(err) || abortEarly) {
230-
return void callback(err, value);
231-
}
232-
errors.push(err);
233-
}
234-
225+
super._validate(_value, opts, panic, (objectErrors, value) => {
235226
if (!recursive || !isObject(value)) {
236-
callback(errors[0] || null, value);
227+
next(objectErrors, value);
237228
return;
238229
}
239230

240231
originalValue = originalValue || value;
241232

242-
let tests = this._nodes.map((key) => (__: any, cb: Callback) => {
233+
let tests = [] as Test[];
234+
for (let key of this._nodes) {
235+
let field = this.fields[key];
236+
237+
if (!field || Reference.isRef(field)) {
238+
continue;
239+
}
240+
243241
let path =
244242
key.indexOf('.') === -1
245243
? (opts.path ? `${opts.path}.` : '') + key
246244
: `${opts.path || ''}["${key}"]`;
247245

248-
let field = this.fields[key];
249-
250-
if (field && 'validate' in field) {
251-
field.validate(
252-
value[key],
253-
{
254-
...opts,
255-
// @ts-ignore
256-
path,
257-
from,
258-
// inner fields are always strict:
259-
// 1. this isn't strict so the casting will also have cast inner values
260-
// 2. this is strict in which case the nested values weren't cast either
261-
strict: true,
262-
parent: value,
263-
originalValue: originalValue[key],
264-
},
265-
cb,
266-
);
267-
return;
268-
}
246+
tests.push(
247+
field.asTest(value[key], {
248+
...opts,
249+
path,
250+
from,
251+
parent: value,
252+
originalValue: originalValue[key],
253+
}),
254+
);
255+
}
269256

270-
cb(null);
257+
this.runTests({ tests, value }, panic, (fieldErrors) => {
258+
next(fieldErrors.sort(this._sortErrors).concat(objectErrors), value);
271259
});
272-
273-
runTests(
274-
{
275-
sync,
276-
tests,
277-
value,
278-
errors,
279-
endEarly: abortEarly,
280-
sort: this._sortErrors,
281-
path: opts.path,
282-
},
283-
callback,
284-
);
285260
});
286261
}
287262

0 commit comments

Comments
 (0)