Skip to content

Commit

Permalink
Rebase and refactor (#2522)
Browse files Browse the repository at this point in the history
Co-authored-by: Colin McDonnell <[email protected]>
  • Loading branch information
bchrobot and colinhacks authored Apr 12, 2024
1 parent cd663b3 commit 9cc890d
Show file tree
Hide file tree
Showing 7 changed files with 223 additions and 207 deletions.
71 changes: 43 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@
- [Coercion for primitives](#coercion-for-primitives)
- [Literals](#literals)
- [Strings](#strings)
- [ISO datetimes](#iso-datetimes)
- [Datetimes](#datetimes)
- [Dates](#dates)
- [Times](#times)
- [IP addresses](#ip-addresses)
- [Numbers](#numbers)
- [BigInts](#bigints)
Expand Down Expand Up @@ -893,18 +895,13 @@ z.string().time({ message: "Invalid time string!" });
z.string().ip({ message: "Invalid IP address" });
```

### ISO Date, Time & Datetime validation
### Datetimes

As you may have noticed, Zod string includes a few date/time related validations.
These validations are regular expression based, so they are not as strict as a full
date/time library. However, they are very convenient for validating user input.
As you may have noticed, Zod string includes a few date/time related validations. These validations are regular expression based, so they are not as strict as a full date/time library. However, they are very convenient for validating user input.

The `z.string().date()` method validates strings in the format `YYYY-MM-DD`.

The `z.string().time()` method validates strings in the format `HH:mm:ss[.SSSSSS][Z|(+|-)hh[:]mm]`
(the time portion of [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601)). It defaults
to `HH:mm:ss[.SSSSSS]` validation: no timezone offsets or `Z`, with arbitrary sub-second
decimal.
The `z.string().time()` method validates strings in the format `HH:mm:ss[.SSSSSS][Z|(+|-)hh[:]mm]` (the time portion of [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601)). It defaults to `HH:mm:ss[.SSSSSS]` validation: no timezone offsets or `Z`, with arbitrary sub-second decimal.

The `z.string().datetime()` method enforces ISO 8601; default is no timezone offsets and arbitrary sub-second decimal precision.

Expand All @@ -915,18 +912,6 @@ datetime.parse("2020-01-01T00:00:00Z"); // pass
datetime.parse("2020-01-01T00:00:00.123Z"); // pass
datetime.parse("2020-01-01T00:00:00.123456Z"); // pass (arbitrary precision)
datetime.parse("2020-01-01T00:00:00+02:00"); // fail (no offsets allowed)

const date = z.string().date();

date.parse("2020-01-01"); // pass

const time = z.string().time();

time.parse("00:00:00"); // pass
time.parse("09:52:31"); // pass
time.parse("23:59:59.9999999"); // pass (arbitrary precision)
time.parse("00:00:00.123Z"); // fail (no `Z` allowed)
time.parse("00:00:00.123+02:00"); // fail (no offsets allowed)
```

Timezone offsets can be allowed by setting the `offset` option to `true`.
Expand All @@ -939,13 +924,6 @@ 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 });

time.parse("00:00:00+02:00"); // pass
time.parse("00:00:00.123+02:00"); // pass (millis optional)
time.parse("00:00:00.123+0200"); // pass (millis optional)
time.parse("00:00:00Z"); // pass (`Z` now supported)
```

You can additionally constrain the allowable `precision`. By default, arbitrary sub-second precision is supported (but optional).
Expand All @@ -964,6 +942,43 @@ time.parse("00:00:00"); // fail
time.parse("00:00:00.123456"); // fail
```

### Dates

The `z.string().date()` method validates strings in the format `YYYY-MM-DD`.

```ts
const date = z.string().date();

date.parse("2020-01-01"); // pass
date.parse("2020-1-1"); // fail
date.parse("2020-01-32"); // fail
```

### Times

The `z.string().time()` method validates strings in the format `HH:MM:SS[.s+]`. The second can include arbitrary decimal precision. It does not allow timezone offsets of any kind.

```ts
const time = z.string().time();

time.parse("00:00:00"); // pass
time.parse("09:52:31"); // pass
time.parse("23:59:59.9999999"); // pass (arbitrary precision)

time.parse("00:00:00.123Z"); // fail (no `Z` allowed)
time.parse("00:00:00.123+02:00"); // fail (no offsets allowed)
```

You can set the `precision` option to constrain the allowable decimal precision.

```ts
const time = z.string().time({ precision: 3 });

time.parse("00:00:00.123"); // pass
time.parse("00:00:00.123456"); // fail
time.parse("00:00:00"); // fail
```

### IP addresses

The `z.string().ip()` method by default validate IPv4 and IPv6.
Expand Down
74 changes: 45 additions & 29 deletions deno/lib/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,10 @@
- [Coercion for primitives](#coercion-for-primitives)
- [Literals](#literals)
- [Strings](#strings)
- [Datetime](#iso-datetimes)
- [IP](#ip-addresses)
- [Datetimes](#datetimes)
- [Dates](#dates)
- [Times](#times)
- [IP addresses](#ip-addresses)
- [Numbers](#numbers)
- [BigInts](#bigints)
- [NaNs](#nans)
Expand Down Expand Up @@ -638,6 +640,7 @@ There are a growing number of tools that are built atop or support Zod natively!
- [`zod_utilz`](https://github.com/JacobWeisenburger/zod_utilz): Framework agnostic utilities for Zod.
- [`zod-sandbox`](https://github.com/nereumelo/zod-sandbox): Controlled environment for testing zod schemas. [Live demo](https://zod-sandbox.vercel.app/).
- [`zod-dev`](https://github.com/schalkventer/zod-dev): Conditionally disables Zod runtime parsing in production.
- [`zod-accelerator`](https://github.com/duplojs/duplojs-zod-accelerator): Accelerates Zod's throughput up to ~100x.

## Installation

Expand Down Expand Up @@ -892,18 +895,13 @@ z.string().time({ message: "Invalid time string!" });
z.string().ip({ message: "Invalid IP address" });
```

### ISO Date, Time & Datetime validation
### Datetimes

As you may have noticed, Zod string includes a few date/time related validations.
These validations are regular expression based, so they are not as strict as a full
date/time library. However, they are very convenient for validating user input.
As you may have noticed, Zod string includes a few date/time related validations. These validations are regular expression based, so they are not as strict as a full date/time library. However, they are very convenient for validating user input.

The `z.string().date()` method validates strings in the format `YYYY-MM-DD`.

The `z.string().time()` method validates strings in the format `HH:mm:ss[.SSSSSS][Z|(+|-)hh[:]mm]`
(the time portion of [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601)). It defaults
to `HH:mm:ss[.SSSSSS]` validation: no timezone offsets or `Z`, with arbitrary sub-second
decimal.
The `z.string().time()` method validates strings in the format `HH:mm:ss[.SSSSSS][Z|(+|-)hh[:]mm]` (the time portion of [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601)). It defaults to `HH:mm:ss[.SSSSSS]` validation: no timezone offsets or `Z`, with arbitrary sub-second decimal.

The `z.string().datetime()` method enforces ISO 8601; default is no timezone offsets and arbitrary sub-second decimal precision.

Expand All @@ -914,18 +912,6 @@ datetime.parse("2020-01-01T00:00:00Z"); // pass
datetime.parse("2020-01-01T00:00:00.123Z"); // pass
datetime.parse("2020-01-01T00:00:00.123456Z"); // pass (arbitrary precision)
datetime.parse("2020-01-01T00:00:00+02:00"); // fail (no offsets allowed)

const date = z.string().date();

date.parse("2020-01-01"); // pass

const time = z.string().time();

time.parse("00:00:00"); // pass
time.parse("09:52:31"); // pass
time.parse("23:59:59.9999999"); // pass (arbitrary precision)
time.parse("00:00:00.123Z"); // fail (no `Z` allowed)
time.parse("00:00:00.123+02:00"); // fail (no offsets allowed)
```

Timezone offsets can be allowed by setting the `offset` option to `true`.
Expand All @@ -938,13 +924,6 @@ 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 });

time.parse("00:00:00+02:00"); // pass
time.parse("00:00:00.123+02:00"); // pass (millis optional)
time.parse("00:00:00.123+0200"); // pass (millis optional)
time.parse("00:00:00Z"); // pass (`Z` now supported)
```

You can additionally constrain the allowable `precision`. By default, arbitrary sub-second precision is supported (but optional).
Expand All @@ -963,6 +942,43 @@ time.parse("00:00:00"); // fail
time.parse("00:00:00.123456"); // fail
```

### Dates

The `z.string().date()` method validates strings in the format `YYYY-MM-DD`.

```ts
const date = z.string().date();

date.parse("2020-01-01"); // pass
date.parse("2020-1-1"); // fail
date.parse("2020-01-32"); // fail
```

### Times

The `z.string().time()` method validates strings in the format `HH:MM:SS[.s+]`. The second can include arbitrary decimal precision. It does not allow timezone offsets of any kind.

```ts
const time = z.string().time();

time.parse("00:00:00"); // pass
time.parse("09:52:31"); // pass
time.parse("23:59:59.9999999"); // pass (arbitrary precision)

time.parse("00:00:00.123Z"); // fail (no `Z` allowed)
time.parse("00:00:00.123+02:00"); // fail (no offsets allowed)
```

You can set the `precision` option to constrain the allowable decimal precision.

```ts
const time = z.string().time({ precision: 3 });

time.parse("00:00:00.123"); // pass
time.parse("00:00:00.123456"); // fail
time.parse("00:00:00"); // fail
```

### IP addresses

The `z.string().ip()` method by default validate IPv4 and IPv6.
Expand Down
50 changes: 25 additions & 25 deletions deno/lib/__tests__/string.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,8 @@ test("nanoid", () => {
const nanoid = z.string().nanoid("custom error");
nanoid.parse("lfNZluvAxMkf7Q8C5H-QS");
nanoid.parse("mIU_4PJWikaU8fMbmkouz");
nanoid.parse("Hb9ZUtUa2JDm_dD-47EGv");
nanoid.parse("5Noocgv_8vQ9oPijj4ioQ");
nanoid.parse("Hb9ZUtUa2JDm_dD-47EGv");
nanoid.parse("5Noocgv_8vQ9oPijj4ioQ");
const result = nanoid.safeParse("Xq90uDyhddC53KsoASYJGX");
expect(result.success).toEqual(false);
if (!result.success) {
Expand Down Expand Up @@ -566,29 +566,29 @@ test("time parsing", () => {
expect(() => time2.parse("00:00:00.000")).toThrow();
expect(() => time2.parse("00:00:00.00+00:00")).toThrow();

const time3 = z.string().time({ offset: true });
time3.parse("00:00:00Z");
time3.parse("09:52:31Z");
time3.parse("00:00:00+00:00");
time3.parse("00:00:00+0000");
time3.parse("00:00:00.000Z");
time3.parse("00:00:00.000+00:00");
time3.parse("00:00:00.000+0000");
expect(() => time3.parse("")).toThrow();
expect(() => time3.parse("foo")).toThrow();
expect(() => time3.parse("00:00:00")).toThrow();
expect(() => time3.parse("00:00:00.000")).toThrow();

const time4 = z.string().time({ offset: true, precision: 0 });
time4.parse("00:00:00Z");
time4.parse("09:52:31Z");
time4.parse("00:00:00+00:00");
time4.parse("00:00:00+0000");
expect(() => time4.parse("")).toThrow();
expect(() => time4.parse("foo")).toThrow();
expect(() => time4.parse("00:00:00.0")).toThrow();
expect(() => time4.parse("00:00:00.000")).toThrow();
expect(() => time4.parse("00:00:00.000+00:00")).toThrow();
// const time3 = z.string().time({ offset: true });
// time3.parse("00:00:00Z");
// time3.parse("09:52:31Z");
// time3.parse("00:00:00+00:00");
// time3.parse("00:00:00+0000");
// time3.parse("00:00:00.000Z");
// time3.parse("00:00:00.000+00:00");
// time3.parse("00:00:00.000+0000");
// expect(() => time3.parse("")).toThrow();
// expect(() => time3.parse("foo")).toThrow();
// expect(() => time3.parse("00:00:00")).toThrow();
// expect(() => time3.parse("00:00:00.000")).toThrow();

// const time4 = z.string().time({ offset: true, precision: 0 });
// time4.parse("00:00:00Z");
// time4.parse("09:52:31Z");
// time4.parse("00:00:00+00:00");
// time4.parse("00:00:00+0000");
// expect(() => time4.parse("")).toThrow();
// expect(() => time4.parse("foo")).toThrow();
// expect(() => time4.parse("00:00:00.0")).toThrow();
// expect(() => time4.parse("00:00:00.000")).toThrow();
// expect(() => time4.parse("00:00:00.000+00:00")).toThrow();
});

test("IP validation", () => {
Expand Down
Loading

0 comments on commit 9cc890d

Please sign in to comment.