zod 4.5.4 → 4.6.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/compile.cjs +19 -0
- package/index.cjs +19 -0
- package/locales/index.cjs +19 -0
- package/mini/index.cjs +19 -0
- package/package.json +8 -7
- package/src/v3/helpers/errorUtil.ts +1 -1
- package/src/v4/classic/checks.ts +0 -1
- package/src/v4/classic/external.ts +2 -0
- package/src/v4/classic/from-json-schema.ts +248 -25
- package/src/v4/classic/schemas.ts +255 -164
- package/src/v4/classic/tests/assignability.test.ts +59 -9
- package/src/v4/classic/tests/bigint.test.ts +6 -0
- package/src/v4/classic/tests/continuability.test.ts +2 -2
- package/src/v4/classic/tests/cyclic-data.test.ts +274 -0
- package/src/v4/classic/tests/enum.test.ts +9 -0
- package/src/v4/classic/tests/error.test.ts +130 -1
- package/src/v4/classic/tests/firstparty.test.ts +4 -0
- package/src/v4/classic/tests/from-json-schema.test.ts +157 -0
- package/src/v4/classic/tests/iban.test.ts +81 -0
- package/src/v4/classic/tests/instance-footprint.test.ts +18 -2
- package/src/v4/classic/tests/instanceof.test.ts +27 -7
- package/src/v4/classic/tests/issue-schema.test.ts +88 -56
- package/src/v4/classic/tests/object.test.ts +56 -0
- package/src/v4/classic/tests/optin-ladder.test.ts +3 -2
- package/src/v4/classic/tests/properties.test.ts +225 -0
- package/src/v4/classic/tests/recursive-types.test.ts +1 -1
- package/src/v4/classic/tests/standard-schema.test.ts +19 -0
- package/src/v4/classic/tests/string.test.ts +25 -0
- package/src/v4/classic/tests/template-literal.test.ts +33 -1
- package/src/v4/classic/tests/to-json-schema.test.ts +147 -3
- package/src/v4/classic/tests/validate.test.ts +569 -0
- package/src/v4/core/api.ts +30 -6
- package/src/v4/core/checks.ts +1 -101
- package/src/v4/core/compile.ts +193 -81
- package/src/v4/core/doc.ts +6 -2
- package/src/v4/core/errors.ts +3 -6
- package/src/v4/core/json-schema-generator.ts +2 -2
- package/src/v4/core/json-schema-processors.ts +226 -68
- package/src/v4/core/memoizer.ts +78 -28
- package/src/v4/core/parse.ts +37 -16
- package/src/v4/core/regexes.ts +10 -4
- package/src/v4/core/schemas.ts +314 -83
- package/src/v4/core/tests/cached.test.ts +54 -0
- package/src/v4/core/tests/compile-generative.test.ts +445 -0
- package/src/v4/core/tests/compile.test.ts +222 -2
- package/src/v4/core/tests/email-regex.test.ts +140 -0
- package/src/v4/core/tests/polyfill-collision.test.ts +46 -0
- package/src/v4/core/to-json-schema.ts +10 -8
- package/src/v4/core/util.ts +222 -147
- package/src/v4/core/versions.ts +2 -2
- package/src/v4/core/visit.ts +11 -0
- package/src/v4/locales/ar.ts +1 -0
- package/src/v4/locales/az.ts +1 -0
- package/src/v4/locales/be.ts +1 -0
- package/src/v4/locales/bg.ts +1 -0
- package/src/v4/locales/bn.ts +1 -0
- package/src/v4/locales/ca.ts +1 -0
- package/src/v4/locales/ckb.ts +1 -0
- package/src/v4/locales/cs.ts +1 -0
- package/src/v4/locales/da.ts +1 -0
- package/src/v4/locales/de.ts +1 -0
- package/src/v4/locales/el.ts +1 -0
- package/src/v4/locales/en.ts +1 -0
- package/src/v4/locales/eo.ts +1 -0
- package/src/v4/locales/es.ts +1 -0
- package/src/v4/locales/fa.ts +1 -0
- package/src/v4/locales/fi.ts +1 -0
- package/src/v4/locales/fr-CA.ts +1 -0
- package/src/v4/locales/fr.ts +1 -0
- package/src/v4/locales/gu.ts +1 -0
- package/src/v4/locales/he.ts +1 -0
- package/src/v4/locales/hi.ts +1 -0
- package/src/v4/locales/hr.ts +1 -0
- package/src/v4/locales/hu.ts +1 -0
- package/src/v4/locales/hy.ts +1 -0
- package/src/v4/locales/id.ts +1 -0
- package/src/v4/locales/is.ts +1 -0
- package/src/v4/locales/it.ts +1 -0
- package/src/v4/locales/ja.ts +1 -0
- package/src/v4/locales/ka.ts +1 -0
- package/src/v4/locales/km.ts +1 -0
- package/src/v4/locales/kn.ts +1 -0
- package/src/v4/locales/ko.ts +1 -0
- package/src/v4/locales/lt.ts +1 -0
- package/src/v4/locales/mk.ts +1 -0
- package/src/v4/locales/ms.ts +1 -0
- package/src/v4/locales/ne.ts +1 -0
- package/src/v4/locales/nl.ts +1 -0
- package/src/v4/locales/nn.ts +1 -0
- package/src/v4/locales/no.ts +1 -0
- package/src/v4/locales/ota.ts +1 -0
- package/src/v4/locales/pl.ts +1 -0
- package/src/v4/locales/ps.ts +1 -0
- package/src/v4/locales/pt-BR.ts +1 -0
- package/src/v4/locales/pt.ts +1 -0
- package/src/v4/locales/ro.ts +1 -0
- package/src/v4/locales/ru.ts +1 -0
- package/src/v4/locales/sk.ts +1 -0
- package/src/v4/locales/sl.ts +1 -0
- package/src/v4/locales/sv.ts +1 -0
- package/src/v4/locales/ta.ts +1 -0
- package/src/v4/locales/th.ts +1 -0
- package/src/v4/locales/tk.ts +1 -0
- package/src/v4/locales/tr.ts +1 -0
- package/src/v4/locales/uk.ts +1 -0
- package/src/v4/locales/ur.ts +1 -0
- package/src/v4/locales/uz.ts +1 -0
- package/src/v4/locales/vi.ts +1 -0
- package/src/v4/locales/yo.ts +1 -0
- package/src/v4/locales/zh-CN.ts +1 -0
- package/src/v4/locales/zh-TW.ts +1 -0
- package/src/v4/mini/checks.ts +0 -1
- package/src/v4/mini/external.ts +2 -0
- package/src/v4/mini/schemas.ts +38 -2
- package/src/v4/mini/tests/checks.test.ts +1 -1
- package/src/v4/mini/tests/computed.test.ts +11 -17
- package/src/v4/mini/tests/index.test.ts +8 -0
- package/src/v4/mini/tests/string.test.ts +16 -0
- package/v3/ZodError.cjs +19 -0
- package/v3/errors.cjs +19 -0
- package/v3/external.cjs +19 -0
- package/v3/helpers/enumUtil.cjs +19 -0
- package/v3/helpers/errorUtil.cjs +20 -1
- package/v3/helpers/errorUtil.js +1 -1
- package/v3/helpers/parseUtil.cjs +19 -0
- package/v3/helpers/partialUtil.cjs +19 -0
- package/v3/helpers/typeAliases.cjs +19 -0
- package/v3/helpers/util.cjs +19 -0
- package/v3/index.cjs +19 -0
- package/v3/standard-schema.cjs +19 -0
- package/v3/types.cjs +19 -0
- package/v4/classic/checks.cjs +20 -2
- package/v4/classic/checks.d.cts +1 -1
- package/v4/classic/checks.d.ts +1 -1
- package/v4/classic/checks.js +1 -1
- package/v4/classic/coerce.cjs +19 -0
- package/v4/classic/compat.cjs +19 -0
- package/v4/classic/deep-partial.cjs +19 -0
- package/v4/classic/errors.cjs +19 -0
- package/v4/classic/external.cjs +22 -1
- package/v4/classic/external.d.cts +1 -1
- package/v4/classic/external.d.ts +1 -1
- package/v4/classic/external.js +1 -1
- package/v4/classic/from-json-schema.cjs +264 -24
- package/v4/classic/from-json-schema.js +245 -24
- package/v4/classic/in-out.cjs +19 -0
- package/v4/classic/index.cjs +19 -0
- package/v4/classic/iso.cjs +19 -0
- package/v4/classic/parse.cjs +19 -0
- package/v4/classic/schemas.cjs +100 -31
- package/v4/classic/schemas.d.cts +17 -1
- package/v4/classic/schemas.d.ts +17 -1
- package/v4/classic/schemas.js +77 -29
- package/v4/core/api.cjs +37 -2
- package/v4/core/api.d.cts +6 -4
- package/v4/core/api.d.ts +6 -4
- package/v4/core/api.js +17 -2
- package/v4/core/checks.cjs +19 -96
- package/v4/core/checks.d.cts +1 -1
- package/v4/core/checks.d.ts +1 -1
- package/v4/core/checks.js +0 -96
- package/v4/core/compile.cjs +164 -65
- package/v4/core/compile.d.cts +18 -4
- package/v4/core/compile.d.ts +18 -4
- package/v4/core/compile.js +145 -66
- package/v4/core/core.cjs +19 -0
- package/v4/core/doc.cjs +26 -2
- package/v4/core/doc.js +7 -2
- package/v4/core/errors.cjs +21 -5
- package/v4/core/errors.js +2 -5
- package/v4/core/index.cjs +19 -0
- package/v4/core/json-schema-generator.cjs +20 -1
- package/v4/core/json-schema-generator.js +2 -2
- package/v4/core/json-schema-processors.cjs +215 -63
- package/v4/core/json-schema-processors.d.cts +17 -0
- package/v4/core/json-schema-processors.d.ts +17 -0
- package/v4/core/json-schema-processors.js +195 -64
- package/v4/core/json-schema.cjs +19 -0
- package/v4/core/memoizer.cjs +114 -23
- package/v4/core/memoizer.js +72 -23
- package/v4/core/parse.cjs +56 -16
- package/v4/core/parse.js +37 -16
- package/v4/core/regexes.cjs +29 -6
- package/v4/core/regexes.d.cts +2 -0
- package/v4/core/regexes.d.ts +2 -0
- package/v4/core/regexes.js +8 -4
- package/v4/core/registries.cjs +19 -0
- package/v4/core/schemas.cjs +285 -66
- package/v4/core/schemas.d.cts +34 -3
- package/v4/core/schemas.d.ts +34 -3
- package/v4/core/schemas.js +264 -65
- package/v4/core/standard-schema.cjs +19 -0
- package/v4/core/to-json-schema.cjs +29 -7
- package/v4/core/to-json-schema.d.cts +7 -3
- package/v4/core/to-json-schema.d.ts +7 -3
- package/v4/core/to-json-schema.js +8 -7
- package/v4/core/util.cjs +181 -143
- package/v4/core/util.d.cts +25 -4
- package/v4/core/util.d.ts +25 -4
- package/v4/core/util.js +160 -143
- package/v4/core/versions.cjs +21 -2
- package/v4/core/versions.d.cts +1 -1
- package/v4/core/versions.d.ts +1 -1
- package/v4/core/versions.js +2 -2
- package/v4/core/visit.cjs +31 -0
- package/v4/core/visit.js +12 -0
- package/v4/index.cjs +19 -0
- package/v4/locales/ar.cjs +1 -0
- package/v4/locales/ar.js +1 -0
- package/v4/locales/az.cjs +1 -0
- package/v4/locales/az.js +1 -0
- package/v4/locales/be.cjs +1 -0
- package/v4/locales/be.js +1 -0
- package/v4/locales/bg.cjs +1 -0
- package/v4/locales/bg.js +1 -0
- package/v4/locales/bn.cjs +1 -0
- package/v4/locales/bn.js +1 -0
- package/v4/locales/ca.cjs +1 -0
- package/v4/locales/ca.js +1 -0
- package/v4/locales/ckb.cjs +1 -0
- package/v4/locales/ckb.js +1 -0
- package/v4/locales/cs.cjs +1 -0
- package/v4/locales/cs.js +1 -0
- package/v4/locales/da.cjs +1 -0
- package/v4/locales/da.js +1 -0
- package/v4/locales/de.cjs +1 -0
- package/v4/locales/de.js +1 -0
- package/v4/locales/el.cjs +1 -0
- package/v4/locales/el.js +1 -0
- package/v4/locales/en.cjs +1 -0
- package/v4/locales/en.js +1 -0
- package/v4/locales/eo.cjs +1 -0
- package/v4/locales/eo.js +1 -0
- package/v4/locales/es.cjs +1 -0
- package/v4/locales/es.js +1 -0
- package/v4/locales/fa.cjs +1 -0
- package/v4/locales/fa.js +1 -0
- package/v4/locales/fi.cjs +1 -0
- package/v4/locales/fi.js +1 -0
- package/v4/locales/fr-CA.cjs +1 -0
- package/v4/locales/fr-CA.js +1 -0
- package/v4/locales/fr.cjs +1 -0
- package/v4/locales/fr.js +1 -0
- package/v4/locales/gu.cjs +1 -0
- package/v4/locales/gu.js +1 -0
- package/v4/locales/he.cjs +1 -0
- package/v4/locales/he.js +1 -0
- package/v4/locales/hi.cjs +1 -0
- package/v4/locales/hi.js +1 -0
- package/v4/locales/hr.cjs +1 -0
- package/v4/locales/hr.js +1 -0
- package/v4/locales/hu.cjs +1 -0
- package/v4/locales/hu.js +1 -0
- package/v4/locales/hy.cjs +1 -0
- package/v4/locales/hy.js +1 -0
- package/v4/locales/id.cjs +1 -0
- package/v4/locales/id.js +1 -0
- package/v4/locales/index.cjs +19 -0
- package/v4/locales/is.cjs +1 -0
- package/v4/locales/is.js +1 -0
- package/v4/locales/it.cjs +1 -0
- package/v4/locales/it.js +1 -0
- package/v4/locales/ja.cjs +1 -0
- package/v4/locales/ja.js +1 -0
- package/v4/locales/ka.cjs +1 -0
- package/v4/locales/ka.js +1 -0
- package/v4/locales/km.cjs +1 -0
- package/v4/locales/km.js +1 -0
- package/v4/locales/kn.cjs +1 -0
- package/v4/locales/kn.js +1 -0
- package/v4/locales/ko.cjs +1 -0
- package/v4/locales/ko.js +1 -0
- package/v4/locales/lt.cjs +1 -0
- package/v4/locales/lt.js +1 -0
- package/v4/locales/mk.cjs +1 -0
- package/v4/locales/mk.js +1 -0
- package/v4/locales/ms.cjs +1 -0
- package/v4/locales/ms.js +1 -0
- package/v4/locales/ne.cjs +1 -0
- package/v4/locales/ne.js +1 -0
- package/v4/locales/nl.cjs +1 -0
- package/v4/locales/nl.js +1 -0
- package/v4/locales/nn.cjs +1 -0
- package/v4/locales/nn.js +1 -0
- package/v4/locales/no.cjs +1 -0
- package/v4/locales/no.js +1 -0
- package/v4/locales/ota.cjs +1 -0
- package/v4/locales/ota.js +1 -0
- package/v4/locales/pl.cjs +1 -0
- package/v4/locales/pl.js +1 -0
- package/v4/locales/ps.cjs +1 -0
- package/v4/locales/ps.js +1 -0
- package/v4/locales/pt-BR.cjs +1 -0
- package/v4/locales/pt-BR.js +1 -0
- package/v4/locales/pt.cjs +1 -0
- package/v4/locales/pt.js +1 -0
- package/v4/locales/ro.cjs +1 -0
- package/v4/locales/ro.js +1 -0
- package/v4/locales/ru.cjs +1 -0
- package/v4/locales/ru.js +1 -0
- package/v4/locales/sk.cjs +1 -0
- package/v4/locales/sk.js +1 -0
- package/v4/locales/sl.cjs +1 -0
- package/v4/locales/sl.js +1 -0
- package/v4/locales/sv.cjs +1 -0
- package/v4/locales/sv.js +1 -0
- package/v4/locales/ta.cjs +1 -0
- package/v4/locales/ta.js +1 -0
- package/v4/locales/th.cjs +1 -0
- package/v4/locales/th.js +1 -0
- package/v4/locales/tk.cjs +1 -0
- package/v4/locales/tk.js +1 -0
- package/v4/locales/tr.cjs +1 -0
- package/v4/locales/tr.js +1 -0
- package/v4/locales/uk.cjs +1 -0
- package/v4/locales/uk.js +1 -0
- package/v4/locales/ur.cjs +1 -0
- package/v4/locales/ur.js +1 -0
- package/v4/locales/uz.cjs +1 -0
- package/v4/locales/uz.js +1 -0
- package/v4/locales/vi.cjs +1 -0
- package/v4/locales/vi.js +1 -0
- package/v4/locales/yo.cjs +1 -0
- package/v4/locales/yo.js +1 -0
- package/v4/locales/zh-CN.cjs +1 -0
- package/v4/locales/zh-CN.js +1 -0
- package/v4/locales/zh-TW.cjs +1 -0
- package/v4/locales/zh-TW.js +1 -0
- package/v4/mini/checks.cjs +20 -2
- package/v4/mini/checks.d.cts +1 -1
- package/v4/mini/checks.d.ts +1 -1
- package/v4/mini/checks.js +1 -1
- package/v4/mini/coerce.cjs +19 -0
- package/v4/mini/deep-partial.cjs +19 -0
- package/v4/mini/external.cjs +22 -1
- package/v4/mini/external.d.cts +1 -1
- package/v4/mini/external.d.ts +1 -1
- package/v4/mini/external.js +1 -1
- package/v4/mini/in-out.cjs +19 -0
- package/v4/mini/index.cjs +19 -0
- package/v4/mini/iso.cjs +19 -0
- package/v4/mini/parse.cjs +19 -0
- package/v4/mini/schemas.cjs +42 -4
- package/v4/mini/schemas.d.cts +8 -0
- package/v4/mini/schemas.d.ts +8 -0
- package/v4/mini/schemas.js +19 -2
- package/v4-mini/index.cjs +19 -0
|
@@ -1,7 +1,15 @@
|
|
|
1
|
-
import { expect, test } from "vitest";
|
|
1
|
+
import { expect, expectTypeOf, test } from "vitest";
|
|
2
2
|
|
|
3
3
|
import * as z from "../../index.js";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
INVALID,
|
|
6
|
+
ZodCompileAsyncError,
|
|
7
|
+
ZodCompileUnsupportedError,
|
|
8
|
+
compile,
|
|
9
|
+
compileFn,
|
|
10
|
+
withParser,
|
|
11
|
+
} from "../compile.js";
|
|
12
|
+
import { $ZodAsyncError } from "../core.js";
|
|
5
13
|
|
|
6
14
|
// Differential helper: assert compiled schema matches the original on a value.
|
|
7
15
|
function expectMatch(schema: z.ZodType, value: unknown) {
|
|
@@ -1350,6 +1358,29 @@ test("runtime island inside array element", () => {
|
|
|
1350
1358
|
invalid(aot, ["a", true]);
|
|
1351
1359
|
});
|
|
1352
1360
|
|
|
1361
|
+
test("an island thrown from inside an indented block leaves the indent level alone", () => {
|
|
1362
|
+
// nullable opens an indented block, coerce throws inside it, and the property islands the pair — two of them so a leak compounds
|
|
1363
|
+
const schema = z.object({ a: z.coerce.number().nullable(), b: z.coerce.number().nullable(), tail: z.string() });
|
|
1364
|
+
expect(compileFn(schema, { debug: true }).code).toMatchInlineSnapshot(`
|
|
1365
|
+
"// Constants: INVALID, c0, c1, c2
|
|
1366
|
+
if (typeof input !== "object" || input === null || Array.isArray(input)) return INVALID;
|
|
1367
|
+
const v0 = input["a"];
|
|
1368
|
+
if (!("a" in input)) return INVALID;
|
|
1369
|
+
const v1 = c1(c0, v0);
|
|
1370
|
+
if (v1 === INVALID) return INVALID;
|
|
1371
|
+
const v2 = input["b"];
|
|
1372
|
+
if (!("b" in input)) return INVALID;
|
|
1373
|
+
const v3 = c1(c2, v2);
|
|
1374
|
+
if (v3 === INVALID) return INVALID;
|
|
1375
|
+
const v4 = input["tail"];
|
|
1376
|
+
if (typeof v4 !== "string") return INVALID;
|
|
1377
|
+
const v5 = { "a": v1, "b": v3, "tail": v4 };
|
|
1378
|
+
return v5;"
|
|
1379
|
+
`);
|
|
1380
|
+
expectMatch(schema, { a: "1", b: null, tail: "x" });
|
|
1381
|
+
expectMatch(schema, { a: "nope", b: null, tail: "x" });
|
|
1382
|
+
});
|
|
1383
|
+
|
|
1353
1384
|
test("url string-format check never assigns to its accessor", () => {
|
|
1354
1385
|
// const accessor (array element): previously emitted `elem = normalized`,
|
|
1355
1386
|
// a TypeError on valid input.
|
|
@@ -1417,6 +1448,26 @@ test("xor and custom when-gated checks force runtime fallback", () => {
|
|
|
1417
1448
|
expectMatch(z.object({ n: gated }), { n: 3 }); // runtime skips the gated check
|
|
1418
1449
|
});
|
|
1419
1450
|
|
|
1451
|
+
test("compiled parse surfaces the interpreter's throws through the fallback", () => {
|
|
1452
|
+
// an unmergeable intersection bails to INVALID, and the fallback it hands to raises the interpreter's own error
|
|
1453
|
+
const unmergeable = compile(
|
|
1454
|
+
z.intersection(
|
|
1455
|
+
z.number(),
|
|
1456
|
+
z.number().transform((x) => x + 1)
|
|
1457
|
+
),
|
|
1458
|
+
{ strict: true }
|
|
1459
|
+
);
|
|
1460
|
+
expect(() => unmergeable.parse(1234)).toThrowErrorMatchingInlineSnapshot(
|
|
1461
|
+
`[Error: Unmergable intersection. Error path: []]`
|
|
1462
|
+
);
|
|
1463
|
+
|
|
1464
|
+
// a when-gated check islands at codegen, and the island's INVALID for an async run reaches the same fallback
|
|
1465
|
+
const gated = z.number().refine(() => Promise.resolve(true));
|
|
1466
|
+
(gated._zod.def.checks![0]!._zod.def as { when?: unknown }).when = () => true;
|
|
1467
|
+
const compiled = compile(z.object({ n: gated }), { strict: true });
|
|
1468
|
+
expect(() => compiled.parse({ n: 3 })).toThrow($ZodAsyncError);
|
|
1469
|
+
});
|
|
1470
|
+
|
|
1420
1471
|
test("strict objects reject inherited enumerable keys like the runtime", () => {
|
|
1421
1472
|
const schema = z.strictObject({ a: z.string() });
|
|
1422
1473
|
expectMatch(schema, Object.assign(Object.create({ extra: 1 }), { a: "x" }));
|
|
@@ -1637,3 +1688,172 @@ test("strict is per-call, so a supported schema compiles either way", () => {
|
|
|
1637
1688
|
invalid(aot, { a: 1, b: 1 });
|
|
1638
1689
|
}
|
|
1639
1690
|
});
|
|
1691
|
+
|
|
1692
|
+
test("compiled records walk own enumerable keys without Reflect.ownKeys", () => {
|
|
1693
|
+
// a getOwnPropertyNames snapshot plus a per-key recheck sees the same keys as the runtime's Reflect.ownKeys walk: inherited enumerables are skipped, symbols fail a string key schema but pass a symbol one, and the numeric-string retry still applies
|
|
1694
|
+
const sym = Symbol("s");
|
|
1695
|
+
const bare = compile(z.record(z.string(), z.number()));
|
|
1696
|
+
const inherited = Object.assign(Object.create({ proto: 1 }), { a: 1 });
|
|
1697
|
+
expect(bare.parse(inherited)).toEqual({ a: 1 });
|
|
1698
|
+
const symbolic = { a: 1, [sym]: 2 };
|
|
1699
|
+
expect(bare.safeParse(symbolic).error!.issues).toEqual(
|
|
1700
|
+
z.record(z.string(), z.number()).safeParse(symbolic).error!.issues
|
|
1701
|
+
);
|
|
1702
|
+
expect(bare.safeParse({ a: 1, b: "x" }).error!.issues).toEqual(
|
|
1703
|
+
z.record(z.string(), z.number()).safeParse({ a: 1, b: "x" }).error!.issues
|
|
1704
|
+
);
|
|
1705
|
+
const symKeys = compile(z.record(z.symbol(), z.number()));
|
|
1706
|
+
expect(symKeys.parse({ [sym]: 2 })).toEqual({ [sym]: 2 });
|
|
1707
|
+
expect(symKeys.safeParse({ a: 1 }).success).toBe(false);
|
|
1708
|
+
const emailKeys = compile(z.record(z.email(), z.number()));
|
|
1709
|
+
expect(emailKeys.parse({ "a@b.co": 1 })).toEqual({ "a@b.co": 1 });
|
|
1710
|
+
expect(emailKeys.safeParse({ "a@b.co": 1, [sym]: 2 }).success).toBe(false);
|
|
1711
|
+
expect(compile(z.record(z.number(), z.string())).parse({ 1: "a" })).toEqual({ 1: "a" });
|
|
1712
|
+
// keys are snapshotted before any value is read and rechecked when visited, like the runtime's Reflect.ownKeys walk: a getter that adds a key mid-walk is not visited, one that hides a later key skips it
|
|
1713
|
+
const mutating = (effect: (o: Record<PropertyKey, unknown>) => void) => {
|
|
1714
|
+
const o: Record<PropertyKey, unknown> = {};
|
|
1715
|
+
Object.defineProperty(o, "a", {
|
|
1716
|
+
enumerable: true,
|
|
1717
|
+
get() {
|
|
1718
|
+
effect(o);
|
|
1719
|
+
return 1;
|
|
1720
|
+
},
|
|
1721
|
+
});
|
|
1722
|
+
o.b = 2;
|
|
1723
|
+
return o;
|
|
1724
|
+
};
|
|
1725
|
+
const both = z.record(z.union([z.string(), z.symbol()]), z.number());
|
|
1726
|
+
for (const [schema, effect] of [
|
|
1727
|
+
[
|
|
1728
|
+
both,
|
|
1729
|
+
(o: Record<PropertyKey, unknown>) => {
|
|
1730
|
+
o[sym] = 2;
|
|
1731
|
+
},
|
|
1732
|
+
],
|
|
1733
|
+
[
|
|
1734
|
+
z.record(z.string(), z.number()),
|
|
1735
|
+
(o: Record<PropertyKey, unknown>) => {
|
|
1736
|
+
o[sym] = "bad";
|
|
1737
|
+
},
|
|
1738
|
+
],
|
|
1739
|
+
[
|
|
1740
|
+
z.record(z.string(), z.number()),
|
|
1741
|
+
(o: Record<PropertyKey, unknown>) => {
|
|
1742
|
+
o.z = "bad";
|
|
1743
|
+
},
|
|
1744
|
+
],
|
|
1745
|
+
[
|
|
1746
|
+
z.record(z.string(), z.number()),
|
|
1747
|
+
(o: Record<PropertyKey, unknown>) => Object.defineProperty(o, "b", { enumerable: false }),
|
|
1748
|
+
],
|
|
1749
|
+
] as const) {
|
|
1750
|
+
const expected = schema.safeParse(mutating(effect));
|
|
1751
|
+
const actual = compile(schema).safeParse(mutating(effect));
|
|
1752
|
+
expect(actual.success).toBe(expected.success);
|
|
1753
|
+
if (expected.success)
|
|
1754
|
+
expect(Reflect.ownKeys(actual.data as object)).toEqual(Reflect.ownKeys(expected.data as object));
|
|
1755
|
+
else expect(actual.error!.issues).toEqual(expected.error!.issues);
|
|
1756
|
+
}
|
|
1757
|
+
// a getter that defines an own key under an inherited enumerable name mid-walk: the snapshot predates it, so neither walk visits it, and a union that accepts the record cannot be corrected by a fallback
|
|
1758
|
+
const shadowing = () => {
|
|
1759
|
+
const o = Object.create({ z: 0 });
|
|
1760
|
+
Object.defineProperty(o, "a", {
|
|
1761
|
+
enumerable: true,
|
|
1762
|
+
get() {
|
|
1763
|
+
Object.defineProperty(o, "z", { value: 2, enumerable: true });
|
|
1764
|
+
return 1;
|
|
1765
|
+
},
|
|
1766
|
+
});
|
|
1767
|
+
return o;
|
|
1768
|
+
};
|
|
1769
|
+
const inUnion = z.union([z.record(z.string(), z.number()), z.any()]);
|
|
1770
|
+
expect(compile(inUnion).parse(shadowing())).toStrictEqual(inUnion.parse(shadowing()));
|
|
1771
|
+
expect(compile(inUnion).parse(shadowing())).toStrictEqual({ a: 1 });
|
|
1772
|
+
// a key that is non-enumerable at snapshot time and revealed by an earlier getter is in the snapshot and passes the recheck, like the runtime
|
|
1773
|
+
const revealing = () => {
|
|
1774
|
+
const o: Record<string, unknown> = {};
|
|
1775
|
+
Object.defineProperty(o, "a", {
|
|
1776
|
+
enumerable: true,
|
|
1777
|
+
get() {
|
|
1778
|
+
Object.defineProperty(o, "b", { enumerable: true });
|
|
1779
|
+
return 1;
|
|
1780
|
+
},
|
|
1781
|
+
});
|
|
1782
|
+
Object.defineProperty(o, "b", { value: 2, enumerable: false, configurable: true });
|
|
1783
|
+
return o;
|
|
1784
|
+
};
|
|
1785
|
+
const plain = z.record(z.string(), z.number());
|
|
1786
|
+
expect(compile(plain).parse(revealing())).toStrictEqual(plain.parse(revealing()));
|
|
1787
|
+
expect(compile(plain).parse(revealing())).toStrictEqual({ a: 1, b: 2 });
|
|
1788
|
+
});
|
|
1789
|
+
|
|
1790
|
+
// withParser: a parser Zod did not generate, installed on the same wrapper compile() uses.
|
|
1791
|
+
|
|
1792
|
+
// tags its output so a test fails loudly if the runtime ran instead of the supplied parser
|
|
1793
|
+
function taggedParser(input: unknown) {
|
|
1794
|
+
if (typeof input !== "object" || input === null) return INVALID;
|
|
1795
|
+
const o = input as Record<string, unknown>;
|
|
1796
|
+
if (typeof o.a !== "string") return INVALID;
|
|
1797
|
+
return { a: o.a, tag: "supplied" };
|
|
1798
|
+
}
|
|
1799
|
+
|
|
1800
|
+
const withParserSchema = z.object({ a: z.string() });
|
|
1801
|
+
|
|
1802
|
+
test("withParser installs the supplied parser", () => {
|
|
1803
|
+
const installed = withParser(withParserSchema, taggedParser);
|
|
1804
|
+
expect(installed.parse({ a: "x" })).toStrictEqual({ a: "x", tag: "supplied" });
|
|
1805
|
+
// the clone is a new schema; the original keeps the runtime
|
|
1806
|
+
expect(installed).not.toBe(withParserSchema);
|
|
1807
|
+
expect(withParserSchema.parse({ a: "x" })).toStrictEqual({ a: "x" });
|
|
1808
|
+
});
|
|
1809
|
+
|
|
1810
|
+
test("withParser hands INVALID to the runtime and gets a real ZodError", () => {
|
|
1811
|
+
const installed = withParser(withParserSchema, taggedParser);
|
|
1812
|
+
const result = installed.safeParse({ a: 1 });
|
|
1813
|
+
expect(result.success).toBe(false);
|
|
1814
|
+
expect(result.error!.issues).toEqual(withParserSchema.safeParse({ a: 1 }).error!.issues);
|
|
1815
|
+
});
|
|
1816
|
+
|
|
1817
|
+
test("withParser answers validate with the supplied parser", () => {
|
|
1818
|
+
const installed = withParser(withParserSchema, taggedParser);
|
|
1819
|
+
expect(z.validate(installed, { a: "x" })).toBe(true);
|
|
1820
|
+
expect(z.validate(installed, { a: 1 })).toBe(false);
|
|
1821
|
+
});
|
|
1822
|
+
|
|
1823
|
+
test("withParser bypasses the fast path on async, like compile()", async () => {
|
|
1824
|
+
const installed = withParser(withParserSchema, taggedParser);
|
|
1825
|
+
// async runs on the runtime, so the tag is absent
|
|
1826
|
+
await expect(installed.parseAsync({ a: "x" })).resolves.toStrictEqual({ a: "x" });
|
|
1827
|
+
});
|
|
1828
|
+
|
|
1829
|
+
test("withParser reaches a parse it does not own the call site of", () => {
|
|
1830
|
+
const installed = withParser(withParserSchema, taggedParser);
|
|
1831
|
+
// installing on _zod.run rather than wrapping a call site is the whole point: a framework holding the schema gets the supplied parser through Standard Schema, and so does z.parse
|
|
1832
|
+
expect((installed["~standard"].validate({ a: "x" }) as { value: unknown }).value).toStrictEqual({
|
|
1833
|
+
a: "x",
|
|
1834
|
+
tag: "supplied",
|
|
1835
|
+
});
|
|
1836
|
+
expect(z.parse(installed, { a: "x" })).toStrictEqual({ a: "x", tag: "supplied" });
|
|
1837
|
+
});
|
|
1838
|
+
|
|
1839
|
+
test("withParser refuses a recursive schema", () => {
|
|
1840
|
+
type Node = { next: Node | null };
|
|
1841
|
+
const Node: z.ZodType<Node> = z.object({ next: z.lazy(() => z.nullable(Node)) });
|
|
1842
|
+
expect(() => withParser(Node, () => INVALID)).toThrow(ZodCompileUnsupportedError);
|
|
1843
|
+
});
|
|
1844
|
+
|
|
1845
|
+
test("withParser leaves encode on the runtime", () => {
|
|
1846
|
+
const codec = z.codec(z.string(), z.number(), {
|
|
1847
|
+
decode: (s) => Number(s),
|
|
1848
|
+
encode: (n) => String(n),
|
|
1849
|
+
});
|
|
1850
|
+
const installed = withParser(codec, () => INVALID);
|
|
1851
|
+
expect(z.encode(installed, 5)).toBe("5");
|
|
1852
|
+
});
|
|
1853
|
+
|
|
1854
|
+
test("withParser rejects a parser whose output contradicts the schema", () => {
|
|
1855
|
+
// the returned schema still claims T, so a parser that succeeds with something else would make parse() lie about its own type
|
|
1856
|
+
// @ts-expect-error a number is not the output of z.string()
|
|
1857
|
+
withParser(z.string(), () => 123);
|
|
1858
|
+
expectTypeOf(withParser(z.string(), () => "ok")).toEqualTypeOf<z.ZodString>();
|
|
1859
|
+
});
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { expect, test } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { regexes } from "zod/v4/core";
|
|
4
|
+
|
|
5
|
+
// the lookahead form `regexes.email` had before this rewrite
|
|
6
|
+
const legacy = /^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$/;
|
|
7
|
+
|
|
8
|
+
const table: [string, boolean][] = [
|
|
9
|
+
["a@b.cc", true],
|
|
10
|
+
["first.last@example.com", true],
|
|
11
|
+
["a.b.c.d@b.cc", true],
|
|
12
|
+
["'a@b.cc", true],
|
|
13
|
+
["a'b@b.cc", true],
|
|
14
|
+
["a+b@b.cc", true],
|
|
15
|
+
["a-@b.cc", true],
|
|
16
|
+
["a_@b.cc", true],
|
|
17
|
+
["a@0b.cc", true],
|
|
18
|
+
["a@b.c.dd", true],
|
|
19
|
+
["a@b-.cc", true],
|
|
20
|
+
[".a@b.cc", false],
|
|
21
|
+
["a.@b.cc", false],
|
|
22
|
+
["a..b@b.cc", false],
|
|
23
|
+
["....@b.cc", false],
|
|
24
|
+
["a@b..cc", false],
|
|
25
|
+
["a@.b.cc", false],
|
|
26
|
+
["a@b.cc.", false],
|
|
27
|
+
["a'@b.cc", false],
|
|
28
|
+
["'@b.cc", false],
|
|
29
|
+
["@b.cc", false],
|
|
30
|
+
["a@b.c", false],
|
|
31
|
+
["a@b.c0", false],
|
|
32
|
+
["a@-b.cc", false],
|
|
33
|
+
["a@b.cc@d.ee", false],
|
|
34
|
+
["a b@b.cc", false],
|
|
35
|
+
["café@b.cc", false],
|
|
36
|
+
["😀@b.cc", false],
|
|
37
|
+
["a\0@b.cc", false],
|
|
38
|
+
// `$` is not multiline, so no trailing terminator is tolerated
|
|
39
|
+
["a@b.cc\n", false],
|
|
40
|
+
["a@b.cc\r", false],
|
|
41
|
+
["\na@b.cc", false],
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
test("boundary cases", () => {
|
|
45
|
+
for (const [input, expected] of table) {
|
|
46
|
+
expect([input, regexes.email.test(input)]).toEqual([input, expected]);
|
|
47
|
+
expect([input, legacy.test(input)]).toEqual([input, expected]);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// one representative per character class the two grammars can tell apart
|
|
52
|
+
const classes = ["a", "0", "_", "'", "-", ".", "@", "!", "\n"];
|
|
53
|
+
|
|
54
|
+
test("exhaustive agreement over every string of length <= 6 in the class alphabet", () => {
|
|
55
|
+
const idx: number[] = [];
|
|
56
|
+
let accepted = 0;
|
|
57
|
+
for (let len = 0; len <= 6; len++) {
|
|
58
|
+
idx.length = len;
|
|
59
|
+
idx.fill(0);
|
|
60
|
+
for (;;) {
|
|
61
|
+
let s = "";
|
|
62
|
+
for (let i = 0; i < len; i++) s += classes[idx[i]!];
|
|
63
|
+
const a = legacy.test(s);
|
|
64
|
+
if (a !== regexes.email.test(s)) expect.unreachable(`disagreement on ${JSON.stringify(s)}`);
|
|
65
|
+
if (a) accepted++;
|
|
66
|
+
let p = len - 1;
|
|
67
|
+
while (p >= 0 && ++idx[p]! === classes.length) idx[p--] = 0;
|
|
68
|
+
if (p < 0) break;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// 4 chars can precede `@`, 2 can open a domain label, 1 is a letter for the TLD
|
|
72
|
+
expect(accepted).toBe(8);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
function rng(seed: number) {
|
|
76
|
+
let s = seed >>> 0;
|
|
77
|
+
return () => {
|
|
78
|
+
s = (s + 0x6d2b79f5) >>> 0;
|
|
79
|
+
let t = s;
|
|
80
|
+
t = Math.imul(t ^ (t >>> 15), t | 1);
|
|
81
|
+
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
|
|
82
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const local = "abZ09_'+-.".split("");
|
|
87
|
+
const domain = "abZ09-.".split("");
|
|
88
|
+
const hostile = ["@", ".", "..", "...", "\n", "\r", "\0", "\t", " ", '"', "é", "😀", "\\", "<", ";", "/", "{"];
|
|
89
|
+
const any = [...local, ...domain, ...hostile];
|
|
90
|
+
|
|
91
|
+
function fuzz(r: () => number): string {
|
|
92
|
+
const pick = <T>(xs: T[]): T => xs[Math.floor(r() * xs.length)]!;
|
|
93
|
+
const run = (xs: string[], max: number) => {
|
|
94
|
+
let out = "";
|
|
95
|
+
for (let i = Math.floor(r() * max); i > 0; i--) out += pick(xs);
|
|
96
|
+
return out;
|
|
97
|
+
};
|
|
98
|
+
switch (Math.floor(r() * 8)) {
|
|
99
|
+
case 0:
|
|
100
|
+
return run(any, 40);
|
|
101
|
+
case 1:
|
|
102
|
+
return `${run(local, 24)}@${run(domain, 24)}`;
|
|
103
|
+
case 2:
|
|
104
|
+
return `${run(local, 8)}${".".repeat(1 + Math.floor(r() * 6))}${run(local, 8)}@${run(domain, 12)}`;
|
|
105
|
+
case 3:
|
|
106
|
+
return `${run(local, 8)}@${run(domain, 8)}${".".repeat(1 + Math.floor(r() * 6))}${run(domain, 8)}`;
|
|
107
|
+
case 4: {
|
|
108
|
+
// single-character mutation of a valid address
|
|
109
|
+
const base = `${run("abZ09_'+-".split(""), 10)}@example.com`;
|
|
110
|
+
const i = Math.floor(r() * base.length);
|
|
111
|
+
return Math.floor(r() * 3) === 0
|
|
112
|
+
? base.slice(0, i) + pick(any) + base.slice(i)
|
|
113
|
+
: base.slice(0, i) + (Math.floor(r() * 2) ? pick(any) : "") + base.slice(i + 1);
|
|
114
|
+
}
|
|
115
|
+
case 5:
|
|
116
|
+
return (
|
|
117
|
+
"a".repeat(1 + Math.floor(r() * 60)) +
|
|
118
|
+
".".repeat(Math.floor(r() * 4)) +
|
|
119
|
+
run(local, 4) +
|
|
120
|
+
(r() < 0.5 ? "@" : "") +
|
|
121
|
+
run(domain, 10)
|
|
122
|
+
);
|
|
123
|
+
case 6:
|
|
124
|
+
return `${run(local, 8)}@${run(domain, 6)}@${run(domain, 8)}`;
|
|
125
|
+
default:
|
|
126
|
+
return pick(["", "\n", " "]) + run(local, 8) + "@example.com" + pick(["", "\n", "\r\n", " ", "\0"]);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
test("differential fuzz", () => {
|
|
131
|
+
const r = rng(0x5eed);
|
|
132
|
+
let accepted = 0;
|
|
133
|
+
for (let i = 0; i < 25_000; i++) {
|
|
134
|
+
const s = fuzz(r);
|
|
135
|
+
const a = legacy.test(s);
|
|
136
|
+
if (a !== regexes.email.test(s)) expect.unreachable(`disagreement on ${JSON.stringify(s)}`);
|
|
137
|
+
if (a) accepted++;
|
|
138
|
+
}
|
|
139
|
+
expect(accepted).toBeGreaterThan(500);
|
|
140
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { build, transform } from "esbuild";
|
|
4
|
+
import { expect, test } from "vitest";
|
|
5
|
+
import * as core from "zod/v4/core";
|
|
6
|
+
|
|
7
|
+
// Browser polyfills for node globals land as raw text in the bundle's top scope — an esbuild `banner`, a scope-unaware injector — so the bundler never sees the collision and the browser is the first thing to read both declarations. zod must therefore declare none of these names at module scope. The JSON Schema pass shipped an `export function process` for three minors before #6397 reported the white screen it caused.
|
|
8
|
+
const INJECTED = ["process", "Buffer", "global", "__dirname", "__filename"];
|
|
9
|
+
|
|
10
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const CLASSIC = path.resolve(here, "../../../index.ts");
|
|
12
|
+
const MINI = path.resolve(here, "../../../mini/index.ts");
|
|
13
|
+
|
|
14
|
+
const polyfills = INJECTED.map((name) => `const ${name} = {};`).join("\n");
|
|
15
|
+
|
|
16
|
+
// toJSONSchema has to be reachable: a bundle that only parses a schema tree-shakes the offending module away and would pass no matter what it declares. `z.core.process` is the pre-rename export name, read as a namespace property so the entry itself declares no `process` binding.
|
|
17
|
+
const ENTRY = `import * as z from "%ENTRY%";\nglobalThis.__out = [z.toJSONSchema(z.string()), z.core.process];`;
|
|
18
|
+
|
|
19
|
+
test.each([
|
|
20
|
+
["classic", CLASSIC],
|
|
21
|
+
["mini", MINI],
|
|
22
|
+
])(
|
|
23
|
+
"a %s bundle reaching toJSONSchema parses beside polyfilled node globals",
|
|
24
|
+
async (_flavor, entrypoint) => {
|
|
25
|
+
const result = await build({
|
|
26
|
+
stdin: { contents: ENTRY.replace("%ENTRY%", entrypoint), loader: "ts", resolveDir: here },
|
|
27
|
+
bundle: true,
|
|
28
|
+
format: "esm",
|
|
29
|
+
target: "es2020",
|
|
30
|
+
write: false,
|
|
31
|
+
logLevel: "silent",
|
|
32
|
+
banner: { js: polyfills },
|
|
33
|
+
});
|
|
34
|
+
const out = result.outputFiles[0]!.text;
|
|
35
|
+
|
|
36
|
+
expect(out).toContain("https://json-schema.org/draft/2020-12/schema");
|
|
37
|
+
|
|
38
|
+
// the banner is appended after esbuild has already renamed its own symbols, so this second pass is where a duplicate surfaces: `The symbol "process" has already been declared`
|
|
39
|
+
await expect(transform(out, { loader: "js", format: "esm" })).resolves.toBeTruthy();
|
|
40
|
+
},
|
|
41
|
+
30000
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
test("the pre-rename `process` export still resolves to the helper", () => {
|
|
45
|
+
expect(core.process).toBe(core.processSchema);
|
|
46
|
+
});
|
|
@@ -128,7 +128,7 @@ export interface ToJSONSchemaContext {
|
|
|
128
128
|
* covers both passes in `finalize`: the ref flattening and the `$defs` build.
|
|
129
129
|
*
|
|
130
130
|
* The passes are valid only while nothing they read has changed, so both are cleared in
|
|
131
|
-
* `
|
|
131
|
+
* `processSchema()` when the map grows, and in `JSONSchemaGenerator.emit()`, which can also change
|
|
132
132
|
* the `cycles` and `reused` they branch on.
|
|
133
133
|
*
|
|
134
134
|
* One case is deliberately not covered: an `override` callback that writes to
|
|
@@ -209,7 +209,8 @@ export function handleUnrepresentable(
|
|
|
209
209
|
return true;
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
-
|
|
212
|
+
// never rename this back to `process`: bundler polyfills inject a top-level `const process` that a lexical declaration of the same name collides with (#6397)
|
|
213
|
+
export function processSchema<T extends schemas.$ZodType>(
|
|
213
214
|
schema: T,
|
|
214
215
|
ctx: ToJSONSchemaContext,
|
|
215
216
|
_params: ProcessParams = { path: [], schemaPath: [] }
|
|
@@ -264,7 +265,7 @@ export function process<T extends schemas.$ZodType>(
|
|
|
264
265
|
if (parent) {
|
|
265
266
|
// Also set ref if processor didn't (for inheritance)
|
|
266
267
|
if (!result.ref) result.ref = parent;
|
|
267
|
-
|
|
268
|
+
processSchema(parent, ctx, params);
|
|
268
269
|
ctx.seen.get(parent)!.isParent = true;
|
|
269
270
|
}
|
|
270
271
|
}
|
|
@@ -289,6 +290,9 @@ export function process<T extends schemas.$ZodType>(
|
|
|
289
290
|
return _result.schema;
|
|
290
291
|
}
|
|
291
292
|
|
|
293
|
+
/** @deprecated Renamed to `processSchema`. An export alias declares no binding, so it is safe to keep. */
|
|
294
|
+
export { processSchema as process };
|
|
295
|
+
|
|
292
296
|
// Escape a reference token for use in a JSON Pointer fragment (RFC 6901): `~` becomes `~0` and `/` becomes `~1`. The `~` replacement must run first.
|
|
293
297
|
function encodeJSONPointerSegment(segment: string): string {
|
|
294
298
|
return segment.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
@@ -429,8 +433,6 @@ export function extractDefs<T extends schemas.$ZodType>(
|
|
|
429
433
|
if (seen.count > 1) {
|
|
430
434
|
if (ctx.reused === "ref") {
|
|
431
435
|
extractToDef(entry);
|
|
432
|
-
// biome-ignore lint:
|
|
433
|
-
continue;
|
|
434
436
|
}
|
|
435
437
|
}
|
|
436
438
|
}
|
|
@@ -755,7 +757,7 @@ export function finalize<T extends schemas.$ZodType>(
|
|
|
755
757
|
}
|
|
756
758
|
}
|
|
757
759
|
|
|
758
|
-
function isTransforming(
|
|
760
|
+
export function isTransforming(
|
|
759
761
|
_schema: schemas.$ZodType,
|
|
760
762
|
_ctx?: {
|
|
761
763
|
seen: Set<schemas.$ZodType>;
|
|
@@ -834,7 +836,7 @@ export const createToJSONSchemaMethod =
|
|
|
834
836
|
<T extends schemas.$ZodType>(schema: T, processors: Record<string, Processor> = {}) =>
|
|
835
837
|
(params?: ToJSONSchemaParams): ZodStandardJSONSchemaPayload<T> => {
|
|
836
838
|
const ctx = initializeContext({ ...params, processors });
|
|
837
|
-
|
|
839
|
+
processSchema(schema, ctx);
|
|
838
840
|
extractDefs(ctx, schema);
|
|
839
841
|
return finalize(ctx, schema);
|
|
840
842
|
};
|
|
@@ -849,7 +851,7 @@ export const createStandardJSONSchemaMethod =
|
|
|
849
851
|
(params?: StandardJSONSchemaMethodParams): JSONSchema.BaseSchema => {
|
|
850
852
|
const { libraryOptions, target } = params ?? {};
|
|
851
853
|
const ctx = initializeContext({ ...(libraryOptions ?? {}), target, io, processors });
|
|
852
|
-
|
|
854
|
+
processSchema(schema, ctx);
|
|
853
855
|
extractDefs(ctx, schema);
|
|
854
856
|
return finalize(ctx, schema);
|
|
855
857
|
};
|