Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Faster paths for nested parsers #1036

Merged
merged 3 commits into from
Mar 21, 2022
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 41 additions & 32 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
ParseParams,
ParseReturnType,
ParseStatus,
ParsePath,
SyncParseReturnType,
ZodParsedType,
} from "./helpers/parseUtil";
Expand Down Expand Up @@ -76,6 +77,27 @@ export interface ZodTypeDef {
description?: string;
}

class ParseInputLazyPath implements ParseInput {
parent: ParseContext;
data: any;
_path: ParsePath;
_key: string | number;
constructor(
parent: ParseContext,
value: any,
path: ParsePath,
key: string | number
) {
this.parent = parent;
this.data = value;
this._path = path;
this._key = key;
}
get path() {
return [...this._path, this._key];
}
}
tmcw marked this conversation as resolved.
Show resolved Hide resolved

const handleResult = <Input, Output>(
ctx: ParseContext,
result: SyncParseReturnType<Output>
Expand Down Expand Up @@ -1289,23 +1311,19 @@ export class ZodArray<
if (ctx.common.async) {
return Promise.all(
(ctx.data as any[]).map((item, i) => {
return def.type._parseAsync({
parent: ctx,
path: [...ctx.path, i],
data: item,
});
return def.type._parseAsync(
new ParseInputLazyPath(ctx, item, ctx.path, i)
);
})
).then((result) => {
return ParseStatus.mergeArray(status, result);
});
}

const result = (ctx.data as any[]).map((item, i) => {
return def.type._parseSync({
parent: ctx,
path: [...ctx.path, i],
data: item,
});
return def.type._parseSync(
new ParseInputLazyPath(ctx, item, ctx.path, i)
);
});

return ParseStatus.mergeArray(status, result);
Expand Down Expand Up @@ -1505,6 +1523,7 @@ function deepPartialify(schema: ZodTypeAny): any {
return schema;
}
}

export class ZodObject<
T extends ZodRawShape,
UnknownKeys extends UnknownKeysParam = "strip",
Expand Down Expand Up @@ -1552,11 +1571,9 @@ export class ZodObject<
const value = ctx.data[key];
pairs.push({
key: { status: "valid", value: key },
value: keyValidator._parse({
parent: ctx,
data: value,
path: [...ctx.path, key],
}),
value: keyValidator._parse(
new ParseInputLazyPath(ctx, value, ctx.path, key)
),
alwaysSet: key in ctx.data,
});
}
Expand Down Expand Up @@ -1592,7 +1609,7 @@ export class ZodObject<
pairs.push({
key: { status: "valid", value: key },
value: catchall._parse(
{ parent: ctx, path: [...ctx.path, key], data: value } //, ctx.child(key), value, getParsedType(value)
new ParseInputLazyPath(ctx, value, ctx.path, key) //, ctx.child(key), value, getParsedType(value)
),
alwaysSet: key in ctx.data,
});
Expand Down Expand Up @@ -2368,11 +2385,9 @@ export class ZodTuple<
.map((item, itemIndex) => {
const schema = this._def.items[itemIndex] || this._def.rest;
if (!schema) return null as any as SyncParseReturnType<any>;
return schema._parse({
data: item,
path: [...ctx.path, itemIndex],
parent: ctx,
});
return schema._parse(
new ParseInputLazyPath(ctx, item, ctx.path, itemIndex)
);
})
.filter((x) => !!x); // filter nulls

Expand Down Expand Up @@ -2468,16 +2483,10 @@ export class ZodRecord<

for (const key in ctx.data) {
pairs.push({
key: keyType._parse({
data: key,
path: [...ctx.path, key],
parent: ctx,
}),
value: valueType._parse({
data: ctx.data[key],
path: [...ctx.path, key],
parent: ctx,
}),
key: keyType._parse(new ParseInputLazyPath(ctx, key, ctx.path, key)),
value: valueType._parse(
new ParseInputLazyPath(ctx, ctx.data[key], ctx.path, key)
),
});
}

Expand Down Expand Up @@ -2698,7 +2707,7 @@ export class ZodSet<Value extends ZodTypeAny = ZodTypeAny> extends ZodType<
}

const elements = [...(ctx.data as Set<unknown>).values()].map((item, i) =>
valueType._parse({ data: item, path: [...ctx.path, i], parent: ctx })
valueType._parse(new ParseInputLazyPath(ctx, item, ctx.path, i))
);

if (ctx.common.async) {
Expand Down