Skip to content

Commit

Permalink
Merge branch 'master' into string-date-time
Browse files Browse the repository at this point in the history
  • Loading branch information
igalklebanov authored Jan 29, 2023
2 parents 65be470 + 2cea6e5 commit 9d24251
Show file tree
Hide file tree
Showing 10 changed files with 138 additions and 14 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,7 @@ z.string().email();
z.string().url();
z.string().uuid();
z.string().cuid();
z.string().cuid2();
z.string().regex(regex);
z.string().startsWith(string);
z.string().endsWith(string);
Expand Down Expand Up @@ -668,6 +669,7 @@ const datetime = z.string().datetime({ offset: true });
datetime.parse("2020-01-01T00:00:00+02:00"); // pass
datetime.parse("2020-01-01T00:00:00.123+02:00"); // pass (millis optional)
datetime.parse("2020-01-01T00:00:00.123+0200"); // pass (millis optional)
datetime.parse("2020-01-01T00:00:00.123+02"); // pass (only offset hours)
datetime.parse("2020-01-01T00:00:00Z"); // pass (Z still supported)

const time = z.string().time({ offset: true });
Expand Down
2 changes: 2 additions & 0 deletions deno/lib/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,7 @@ z.string().email();
z.string().url();
z.string().uuid();
z.string().cuid();
z.string().cuid2();
z.string().regex(regex);
z.string().startsWith(string);
z.string().endsWith(string);
Expand Down Expand Up @@ -668,6 +669,7 @@ const datetime = z.string().datetime({ offset: true });
datetime.parse("2020-01-01T00:00:00+02:00"); // pass
datetime.parse("2020-01-01T00:00:00.123+02:00"); // pass (millis optional)
datetime.parse("2020-01-01T00:00:00.123+0200"); // pass (millis optional)
datetime.parse("2020-01-01T00:00:00.123+02"); // pass (only offset hours)
datetime.parse("2020-01-01T00:00:00Z"); // pass (Z still supported)

const time = z.string().time({ offset: true });
Expand Down
1 change: 1 addition & 0 deletions deno/lib/ZodError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export type StringValidation =
| "uuid"
| "regex"
| "cuid"
| "cuid2"
| "datetime"
| "date"
| "time"
Expand Down
6 changes: 6 additions & 0 deletions deno/lib/__tests__/promise.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,9 @@ test("async promise parsing", () => {
const res = z.promise(z.number()).parseAsync(Promise.resolve(12));
expect(res).toBeInstanceOf(Promise);
});

test("resolves", () => {
const foo = z.literal("foo");
const res = z.promise(foo);
expect(res.unwrap()).toEqual(foo);
});
34 changes: 34 additions & 0 deletions deno/lib/__tests__/string.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,27 @@ test("cuid", () => {
}
});

test("cuid2", () => {
const cuid2 = z.string().cuid2();
const validStrings = [
"a", // short string
"tz4a98xxat96iws9zmbrgj3a", // normal string
"kf5vz6ssxe4zjcb409rjgo747tc5qjazgptvotk6", // longer than require("@paralleldrive/cuid2").bigLength
];
validStrings.forEach((s) => cuid2.parse(s));
const invalidStrings = [
"", // empty string
"1z4a98xxat96iws9zmbrgj3a", // starts with a number
"tz4a98xxat96iws9zMbrgj3a", // include uppercase
"tz4a98xxat96iws-zmbrgj3a", // involve symbols
];
const results = invalidStrings.map((s) => cuid2.safeParse(s));
expect(results.every((r) => !r.success)).toEqual(true);
if (!results[0].success) {
expect(results[0].error.issues[0].message).toEqual("Invalid cuid2");
}
});

test("regex", () => {
z.string()
.regex(/^moo+$/)
Expand Down Expand Up @@ -156,21 +177,31 @@ test("checks getters", () => {
expect(z.string().email().isEmail).toEqual(true);
expect(z.string().email().isURL).toEqual(false);
expect(z.string().email().isCUID).toEqual(false);
expect(z.string().email().isCUID2).toEqual(false);
expect(z.string().email().isUUID).toEqual(false);

expect(z.string().url().isEmail).toEqual(false);
expect(z.string().url().isURL).toEqual(true);
expect(z.string().url().isCUID).toEqual(false);
expect(z.string().url().isCUID2).toEqual(false);
expect(z.string().url().isUUID).toEqual(false);

expect(z.string().cuid().isEmail).toEqual(false);
expect(z.string().cuid().isURL).toEqual(false);
expect(z.string().cuid().isCUID).toEqual(true);
expect(z.string().cuid().isCUID2).toEqual(false);
expect(z.string().cuid().isUUID).toEqual(false);

expect(z.string().cuid2().isEmail).toEqual(false);
expect(z.string().cuid2().isURL).toEqual(false);
expect(z.string().cuid2().isCUID).toEqual(false);
expect(z.string().cuid2().isCUID2).toEqual(true);
expect(z.string().cuid2().isUUID).toEqual(false);

expect(z.string().uuid().isEmail).toEqual(false);
expect(z.string().uuid().isURL).toEqual(false);
expect(z.string().uuid().isCUID).toEqual(false);
expect(z.string().uuid().isCUID2).toEqual(false);
expect(z.string().uuid().isUUID).toEqual(true);
});

Expand Down Expand Up @@ -246,6 +277,7 @@ test("datetime parsing", () => {
datetimeOffset.parse("2020-10-14T17:42:29+00:00");
datetimeOffset.parse("2020-10-14T17:42:29+03:15");
datetimeOffset.parse("2020-10-14T17:42:29+0315");
datetimeOffset.parse("2020-10-14T17:42:29+03");
expect(() => datetimeOffset.parse("tuna")).toThrow();
expect(() => datetimeOffset.parse("2022-10-13T09:52:31.Z")).toThrow();

Expand All @@ -256,6 +288,7 @@ test("datetime parsing", () => {
datetimeOffsetNoMs.parse("2022-10-13T09:52:31Z");
datetimeOffsetNoMs.parse("2020-10-14T17:42:29+00:00");
datetimeOffsetNoMs.parse("2020-10-14T17:42:29+0000");
datetimeOffsetNoMs.parse("2020-10-14T17:42:29+00");
expect(() => datetimeOffsetNoMs.parse("tuna")).toThrow();
expect(() => datetimeOffsetNoMs.parse("1970-01-01T00:00:00.000Z")).toThrow();
expect(() => datetimeOffsetNoMs.parse("1970-01-01T00:00:00.Z")).toThrow();
Expand All @@ -268,6 +301,7 @@ test("datetime parsing", () => {
datetimeOffset4Ms.parse("1970-01-01T00:00:00.1234Z");
datetimeOffset4Ms.parse("2020-10-14T17:42:29.1234+00:00");
datetimeOffset4Ms.parse("2020-10-14T17:42:29.1234+0000");
datetimeOffset4Ms.parse("2020-10-14T17:42:29.1234+00");
expect(() => datetimeOffset4Ms.parse("tuna")).toThrow();
expect(() => datetimeOffset4Ms.parse("1970-01-01T00:00:00.123Z")).toThrow();
expect(() =>
Expand Down
33 changes: 26 additions & 7 deletions deno/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,7 @@ export type ZodStringCheck =
| { kind: "url"; message?: string }
| { kind: "uuid"; message?: string }
| { kind: "cuid"; message?: string }
| { kind: "cuid2"; message?: string }
| { kind: "startsWith"; value: string; message?: string }
| { kind: "endsWith"; value: string; message?: string }
| { kind: "regex"; regex: RegExp; message?: string }
Expand Down Expand Up @@ -522,6 +523,7 @@ export interface ZodStringDef extends ZodTypeDef {
}

const cuidRegex = /^c[^\s-]{8,}$/i;
const cuid2Regex = /^[a-z][a-z0-9]*$/;
const uuidRegex =
/^([a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[a-f0-9]{4}-[a-f0-9]{12}|00000000-0000-0000-0000-000000000000)$/i;
// from https://stackoverflow.com/a/46181/1550155
Expand Down Expand Up @@ -682,6 +684,16 @@ export class ZodString extends ZodType<string, ZodStringDef> {
});
status.dirty();
}
} else if (check.kind === "cuid2") {
if (!cuid2Regex.test(input.data)) {
ctx = this._getOrReturnCtx(input, ctx);
addIssueToContext(ctx, {
validation: "cuid2",
code: ZodIssueCode.invalid_string,
message: check.message,
});
status.dirty();
}
} else if (check.kind === "url") {
try {
new URL(input.data);
Expand Down Expand Up @@ -805,7 +817,9 @@ export class ZodString extends ZodType<string, ZodStringDef> {
cuid(message?: errorUtil.ErrMessage) {
return this._addCheck({ kind: "cuid", ...errorUtil.errToObj(message) });
}

cuid2(message?: errorUtil.ErrMessage) {
return this._addCheck({ kind: "cuid2", ...errorUtil.errToObj(message) });
}
datetime(
options?:
| string
Expand Down Expand Up @@ -956,6 +970,9 @@ export class ZodString extends ZodType<string, ZodStringDef> {
get isCUID() {
return !!this._def.checks.find((ch) => ch.kind === "cuid");
}
get isCUID2() {
return !!this._def.checks.find((ch) => ch.kind === "cuid2");
}

get minLength() {
let min: number | null = null;
Expand Down Expand Up @@ -2617,11 +2634,9 @@ export class ZodDiscriminatedUnion<
}

const discriminator = this.discriminator;
console.log("ctx.data", ctx.data);
console.log("discriminator", discriminator);

const discriminatorValue: string = ctx.data[discriminator];
console.log(this.optionsMap);
console.log(discriminatorValue);

const option = this.optionsMap.get(discriminatorValue);

if (!option) {
Expand Down Expand Up @@ -2698,7 +2713,7 @@ export class ZodDiscriminatedUnion<
)} has duplicate value ${String(value)}`
);
}
console.log(`setting ${String(value)}`);

optionsMap.set(value, type);
}
}
Expand Down Expand Up @@ -3423,7 +3438,7 @@ export class ZodFunction<
});
const result = await fn(...(parsedArgs as any));
const parsedReturns = await (
this._def.returns as ZodPromise<ZodTypeAny>
this._def.returns as unknown as ZodPromise<ZodTypeAny>
)._def.type
.parseAsync(result, params)
.catch((e) => {
Expand Down Expand Up @@ -3786,6 +3801,10 @@ export class ZodPromise<T extends ZodTypeAny> extends ZodType<
ZodPromiseDef<T>,
Promise<T["_input"]>
> {
unwrap() {
return this._def.type;
}

_parse(input: ParseInput): ParseReturnType<this["_output"]> {
const { ctx } = this._processInputParams(input);
if (
Expand Down
1 change: 1 addition & 0 deletions src/ZodError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export type StringValidation =
| "uuid"
| "regex"
| "cuid"
| "cuid2"
| "datetime"
| "date"
| "time"
Expand Down
6 changes: 6 additions & 0 deletions src/__tests__/promise.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,9 @@ test("async promise parsing", () => {
const res = z.promise(z.number()).parseAsync(Promise.resolve(12));
expect(res).toBeInstanceOf(Promise);
});

test("resolves", () => {
const foo = z.literal("foo");
const res = z.promise(foo);
expect(res.unwrap()).toEqual(foo);
});
34 changes: 34 additions & 0 deletions src/__tests__/string.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,27 @@ test("cuid", () => {
}
});

test("cuid2", () => {
const cuid2 = z.string().cuid2();
const validStrings = [
"a", // short string
"tz4a98xxat96iws9zmbrgj3a", // normal string
"kf5vz6ssxe4zjcb409rjgo747tc5qjazgptvotk6", // longer than require("@paralleldrive/cuid2").bigLength
];
validStrings.forEach((s) => cuid2.parse(s));
const invalidStrings = [
"", // empty string
"1z4a98xxat96iws9zmbrgj3a", // starts with a number
"tz4a98xxat96iws9zMbrgj3a", // include uppercase
"tz4a98xxat96iws-zmbrgj3a", // involve symbols
];
const results = invalidStrings.map((s) => cuid2.safeParse(s));
expect(results.every((r) => !r.success)).toEqual(true);
if (!results[0].success) {
expect(results[0].error.issues[0].message).toEqual("Invalid cuid2");
}
});

test("regex", () => {
z.string()
.regex(/^moo+$/)
Expand Down Expand Up @@ -155,21 +176,31 @@ test("checks getters", () => {
expect(z.string().email().isEmail).toEqual(true);
expect(z.string().email().isURL).toEqual(false);
expect(z.string().email().isCUID).toEqual(false);
expect(z.string().email().isCUID2).toEqual(false);
expect(z.string().email().isUUID).toEqual(false);

expect(z.string().url().isEmail).toEqual(false);
expect(z.string().url().isURL).toEqual(true);
expect(z.string().url().isCUID).toEqual(false);
expect(z.string().url().isCUID2).toEqual(false);
expect(z.string().url().isUUID).toEqual(false);

expect(z.string().cuid().isEmail).toEqual(false);
expect(z.string().cuid().isURL).toEqual(false);
expect(z.string().cuid().isCUID).toEqual(true);
expect(z.string().cuid().isCUID2).toEqual(false);
expect(z.string().cuid().isUUID).toEqual(false);

expect(z.string().cuid2().isEmail).toEqual(false);
expect(z.string().cuid2().isURL).toEqual(false);
expect(z.string().cuid2().isCUID).toEqual(false);
expect(z.string().cuid2().isCUID2).toEqual(true);
expect(z.string().cuid2().isUUID).toEqual(false);

expect(z.string().uuid().isEmail).toEqual(false);
expect(z.string().uuid().isURL).toEqual(false);
expect(z.string().uuid().isCUID).toEqual(false);
expect(z.string().uuid().isCUID2).toEqual(false);
expect(z.string().uuid().isUUID).toEqual(true);
});

Expand Down Expand Up @@ -245,6 +276,7 @@ test("datetime parsing", () => {
datetimeOffset.parse("2020-10-14T17:42:29+00:00");
datetimeOffset.parse("2020-10-14T17:42:29+03:15");
datetimeOffset.parse("2020-10-14T17:42:29+0315");
datetimeOffset.parse("2020-10-14T17:42:29+03");
expect(() => datetimeOffset.parse("tuna")).toThrow();
expect(() => datetimeOffset.parse("2022-10-13T09:52:31.Z")).toThrow();

Expand All @@ -255,6 +287,7 @@ test("datetime parsing", () => {
datetimeOffsetNoMs.parse("2022-10-13T09:52:31Z");
datetimeOffsetNoMs.parse("2020-10-14T17:42:29+00:00");
datetimeOffsetNoMs.parse("2020-10-14T17:42:29+0000");
datetimeOffsetNoMs.parse("2020-10-14T17:42:29+00");
expect(() => datetimeOffsetNoMs.parse("tuna")).toThrow();
expect(() => datetimeOffsetNoMs.parse("1970-01-01T00:00:00.000Z")).toThrow();
expect(() => datetimeOffsetNoMs.parse("1970-01-01T00:00:00.Z")).toThrow();
Expand All @@ -267,6 +300,7 @@ test("datetime parsing", () => {
datetimeOffset4Ms.parse("1970-01-01T00:00:00.1234Z");
datetimeOffset4Ms.parse("2020-10-14T17:42:29.1234+00:00");
datetimeOffset4Ms.parse("2020-10-14T17:42:29.1234+0000");
datetimeOffset4Ms.parse("2020-10-14T17:42:29.1234+00");
expect(() => datetimeOffset4Ms.parse("tuna")).toThrow();
expect(() => datetimeOffset4Ms.parse("1970-01-01T00:00:00.123Z")).toThrow();
expect(() =>
Expand Down
Loading

0 comments on commit 9d24251

Please sign in to comment.