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
package/compile.cjs
CHANGED
|
@@ -75,3 +75,22 @@ core.globalConfig.postProcessor = (inst) => {
|
|
|
75
75
|
shim.__originalRun = originalRun;
|
|
76
76
|
inst._zod.run = shim;
|
|
77
77
|
};
|
|
78
|
+
|
|
79
|
+
// seal-cjs-exports
|
|
80
|
+
(function () {
|
|
81
|
+
var keys = Object.getOwnPropertyNames(exports);
|
|
82
|
+
for (var i = 0; i < keys.length; i++) {
|
|
83
|
+
var desc = Object.getOwnPropertyDescriptor(exports, keys[i]);
|
|
84
|
+
if (!desc || !desc.get || !desc.configurable) continue;
|
|
85
|
+
var value;
|
|
86
|
+
try {
|
|
87
|
+
value = desc.get();
|
|
88
|
+
} catch (e) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
// a circular require may not have settled this one yet, so leave it live
|
|
92
|
+
if (value === undefined) continue;
|
|
93
|
+
Object.defineProperty(exports, keys[i], { value: value, writable: false, enumerable: desc.enumerable, configurable: false });
|
|
94
|
+
}
|
|
95
|
+
Object.freeze(exports);
|
|
96
|
+
})();
|
package/index.cjs
CHANGED
|
@@ -31,3 +31,22 @@ const z = __importStar(require("./v4/classic/external.cjs"));
|
|
|
31
31
|
exports.z = z;
|
|
32
32
|
exports.default = z;
|
|
33
33
|
__exportStar(require("./v4/classic/external.cjs"), exports);
|
|
34
|
+
|
|
35
|
+
// seal-cjs-exports
|
|
36
|
+
(function () {
|
|
37
|
+
var keys = Object.getOwnPropertyNames(exports);
|
|
38
|
+
for (var i = 0; i < keys.length; i++) {
|
|
39
|
+
var desc = Object.getOwnPropertyDescriptor(exports, keys[i]);
|
|
40
|
+
if (!desc || !desc.get || !desc.configurable) continue;
|
|
41
|
+
var value;
|
|
42
|
+
try {
|
|
43
|
+
value = desc.get();
|
|
44
|
+
} catch (e) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
// a circular require may not have settled this one yet, so leave it live
|
|
48
|
+
if (value === undefined) continue;
|
|
49
|
+
Object.defineProperty(exports, keys[i], { value: value, writable: false, enumerable: desc.enumerable, configurable: false });
|
|
50
|
+
}
|
|
51
|
+
Object.freeze(exports);
|
|
52
|
+
})();
|
package/locales/index.cjs
CHANGED
|
@@ -15,3 +15,22 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("../v4/locales/index.cjs"), exports);
|
|
18
|
+
|
|
19
|
+
// seal-cjs-exports
|
|
20
|
+
(function () {
|
|
21
|
+
var keys = Object.getOwnPropertyNames(exports);
|
|
22
|
+
for (var i = 0; i < keys.length; i++) {
|
|
23
|
+
var desc = Object.getOwnPropertyDescriptor(exports, keys[i]);
|
|
24
|
+
if (!desc || !desc.get || !desc.configurable) continue;
|
|
25
|
+
var value;
|
|
26
|
+
try {
|
|
27
|
+
value = desc.get();
|
|
28
|
+
} catch (e) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
// a circular require may not have settled this one yet, so leave it live
|
|
32
|
+
if (value === undefined) continue;
|
|
33
|
+
Object.defineProperty(exports, keys[i], { value: value, writable: false, enumerable: desc.enumerable, configurable: false });
|
|
34
|
+
}
|
|
35
|
+
Object.freeze(exports);
|
|
36
|
+
})();
|
package/mini/index.cjs
CHANGED
|
@@ -30,3 +30,22 @@ exports.z = void 0;
|
|
|
30
30
|
const z = __importStar(require("../v4/mini/external.cjs"));
|
|
31
31
|
exports.z = z;
|
|
32
32
|
__exportStar(require("../v4/mini/external.cjs"), exports);
|
|
33
|
+
|
|
34
|
+
// seal-cjs-exports
|
|
35
|
+
(function () {
|
|
36
|
+
var keys = Object.getOwnPropertyNames(exports);
|
|
37
|
+
for (var i = 0; i < keys.length; i++) {
|
|
38
|
+
var desc = Object.getOwnPropertyDescriptor(exports, keys[i]);
|
|
39
|
+
if (!desc || !desc.get || !desc.configurable) continue;
|
|
40
|
+
var value;
|
|
41
|
+
try {
|
|
42
|
+
value = desc.get();
|
|
43
|
+
} catch (e) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
// a circular require may not have settled this one yet, so leave it live
|
|
47
|
+
if (value === undefined) continue;
|
|
48
|
+
Object.defineProperty(exports, keys[i], { value: value, writable: false, enumerable: desc.enumerable, configurable: false });
|
|
49
|
+
}
|
|
50
|
+
Object.freeze(exports);
|
|
51
|
+
})();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zod",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.6.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Colin McDonnell <zod@colinhacks.com>",
|
|
@@ -52,7 +52,8 @@
|
|
|
52
52
|
},
|
|
53
53
|
"conditions": {
|
|
54
54
|
"@zod/source": "src"
|
|
55
|
-
}
|
|
55
|
+
},
|
|
56
|
+
"sealCjsExports": true
|
|
56
57
|
},
|
|
57
58
|
"exports": {
|
|
58
59
|
"./package.json": "./package.json",
|
|
@@ -137,10 +138,10 @@
|
|
|
137
138
|
},
|
|
138
139
|
"scripts": {
|
|
139
140
|
"clean": "git clean -xdf . -e node_modules",
|
|
140
|
-
"build": "zshy --project tsconfig.build.json",
|
|
141
|
-
"postbuild": "
|
|
142
|
-
"test:watch": "
|
|
143
|
-
"test": "
|
|
144
|
-
"prepublishOnly": "
|
|
141
|
+
"build": "nub exec --node zshy --project tsconfig.build.json",
|
|
142
|
+
"postbuild": "nub ../../scripts/write-stub-package-jsons.ts && nub exec --node biome check --write .",
|
|
143
|
+
"test:watch": "nub exec --node vitest",
|
|
144
|
+
"test": "nub exec --node vitest run",
|
|
145
|
+
"prepublishOnly": "nub ../../scripts/check-versions.ts"
|
|
145
146
|
}
|
|
146
147
|
}
|
|
@@ -2,7 +2,7 @@ export namespace errorUtil {
|
|
|
2
2
|
export type ErrMessage = string | { message?: string | undefined };
|
|
3
3
|
export const errToObj = (message?: ErrMessage): { message?: string | undefined } =>
|
|
4
4
|
typeof message === "string" ? { message } : message || {};
|
|
5
|
-
// biome-ignore lint:
|
|
5
|
+
// biome-ignore lint/suspicious/noShadowRestrictedNames: renaming churns 31 v3 call sites
|
|
6
6
|
export const toString = (message?: ErrMessage): string | undefined =>
|
|
7
7
|
typeof message === "string" ? message : message?.message;
|
|
8
8
|
}
|
package/src/v4/classic/checks.ts
CHANGED
|
@@ -155,34 +155,225 @@ function resolveRef(ref: string, ctx: ConversionContext): JSONSchema.JSONSchema
|
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
/**
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
158
|
+
* Enforces the keywords that constrain an object's own keys — `propertyNames`,
|
|
159
|
+
* `minProperties`, `maxProperties` — before `objectSchema` runs. The guard has
|
|
160
|
+
* to see the raw input: an object parse drops `__proto__` and can add keys from
|
|
161
|
+
* a property `default`, so its output is not the set of names the instance
|
|
162
|
+
* actually carried.
|
|
162
163
|
*/
|
|
163
|
-
function
|
|
164
|
+
function checkObjectGuards(
|
|
165
|
+
objectSchema: ZodType,
|
|
166
|
+
guards: { keySchema?: ZodType | undefined; minProperties?: number | undefined; maxProperties?: number | undefined }
|
|
167
|
+
): ZodType {
|
|
164
168
|
// An identity transform, not z.any(), so `toJSONSchema` reports the object on both the input and the output side of the pipe.
|
|
165
169
|
const guard = z
|
|
166
170
|
.transform((value: unknown) => value)
|
|
167
171
|
.check((payload) => {
|
|
168
172
|
const value = payload.value;
|
|
169
173
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return;
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
if (result.success) continue;
|
|
174
|
+
const keys = Object.getOwnPropertyNames(value);
|
|
175
|
+
if (guards.minProperties !== undefined && keys.length < guards.minProperties) {
|
|
173
176
|
payload.issues.push({
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
177
|
+
origin: "object",
|
|
178
|
+
code: "too_small",
|
|
179
|
+
minimum: guards.minProperties,
|
|
180
|
+
inclusive: true,
|
|
181
|
+
message: `Too small: expected object to have >=${guards.minProperties} properties`,
|
|
182
|
+
input: value,
|
|
183
|
+
inst: objectSchema,
|
|
179
184
|
continue: true,
|
|
180
185
|
});
|
|
181
186
|
}
|
|
187
|
+
if (guards.maxProperties !== undefined && keys.length > guards.maxProperties) {
|
|
188
|
+
payload.issues.push({
|
|
189
|
+
origin: "object",
|
|
190
|
+
code: "too_big",
|
|
191
|
+
maximum: guards.maxProperties,
|
|
192
|
+
inclusive: true,
|
|
193
|
+
message: `Too big: expected object to have <=${guards.maxProperties} properties`,
|
|
194
|
+
input: value,
|
|
195
|
+
inst: objectSchema,
|
|
196
|
+
continue: true,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
if (guards.keySchema) {
|
|
200
|
+
for (const key of keys) {
|
|
201
|
+
const result = guards.keySchema.safeParse(key);
|
|
202
|
+
if (result.success) continue;
|
|
203
|
+
payload.issues.push({
|
|
204
|
+
code: "invalid_key",
|
|
205
|
+
origin: "record",
|
|
206
|
+
issues: result.error.issues,
|
|
207
|
+
input: key,
|
|
208
|
+
path: [key],
|
|
209
|
+
continue: true,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
}
|
|
182
213
|
});
|
|
183
214
|
return guard.pipe(objectSchema);
|
|
184
215
|
}
|
|
185
216
|
|
|
217
|
+
/**
|
|
218
|
+
* An injective string for JSON data: two values share a key exactly when `uniqueItems` calls them
|
|
219
|
+
* equal, so duplicate detection is a Map lookup rather than a pairwise walk. Strings and keys are
|
|
220
|
+
* length-prefixed so no value can spell another one. `null` means "never equal to anything" — a
|
|
221
|
+
* cycle or a NaN, neither of which JSON can express.
|
|
222
|
+
*/
|
|
223
|
+
function canonicalKey(value: unknown, seen: Set<object>): string | null {
|
|
224
|
+
if (value === null) return "z";
|
|
225
|
+
const type = typeof value;
|
|
226
|
+
if (type !== "object") {
|
|
227
|
+
if (type === "number" && Number.isNaN(value)) return null;
|
|
228
|
+
const raw = String(value);
|
|
229
|
+
return `${type[0]}${raw.length}:${raw}`;
|
|
230
|
+
}
|
|
231
|
+
if (seen.has(value as object)) return null;
|
|
232
|
+
seen.add(value as object);
|
|
233
|
+
try {
|
|
234
|
+
if (Array.isArray(value)) {
|
|
235
|
+
const parts: string[] = [];
|
|
236
|
+
for (const item of value) {
|
|
237
|
+
const key = canonicalKey(item, seen);
|
|
238
|
+
if (key === null) return null;
|
|
239
|
+
parts.push(key);
|
|
240
|
+
}
|
|
241
|
+
return `a${parts.length}:[${parts.join(",")}]`;
|
|
242
|
+
}
|
|
243
|
+
const keys = Object.keys(value as object).sort();
|
|
244
|
+
const parts: string[] = [];
|
|
245
|
+
for (const k of keys) {
|
|
246
|
+
const key = canonicalKey((value as any)[k], seen);
|
|
247
|
+
if (key === null) return null;
|
|
248
|
+
parts.push(`${k.length}:${k}=${key}`);
|
|
249
|
+
}
|
|
250
|
+
return `o${parts.length}:{${parts.join(",")}}`;
|
|
251
|
+
} finally {
|
|
252
|
+
seen.delete(value as object);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// keywords whose value is a schema or an array of them
|
|
257
|
+
const SCHEMA_KEYWORDS = /*@__PURE__*/ new Set([
|
|
258
|
+
"items",
|
|
259
|
+
"prefixItems",
|
|
260
|
+
"additionalItems",
|
|
261
|
+
"additionalProperties",
|
|
262
|
+
"contains",
|
|
263
|
+
"propertyNames",
|
|
264
|
+
"not",
|
|
265
|
+
"if",
|
|
266
|
+
"then",
|
|
267
|
+
"else",
|
|
268
|
+
"allOf",
|
|
269
|
+
"anyOf",
|
|
270
|
+
"oneOf",
|
|
271
|
+
"unevaluatedItems",
|
|
272
|
+
"unevaluatedProperties",
|
|
273
|
+
"contentSchema",
|
|
274
|
+
]);
|
|
275
|
+
|
|
276
|
+
// keywords whose value maps names to schemas. draft-7 `dependencies` also allows an array of property names, which holds no schema to walk
|
|
277
|
+
const SCHEMA_MAP_KEYWORDS = /*@__PURE__*/ new Set([
|
|
278
|
+
"properties",
|
|
279
|
+
"patternProperties",
|
|
280
|
+
"dependentSchemas",
|
|
281
|
+
"dependencies",
|
|
282
|
+
"$defs",
|
|
283
|
+
"definitions",
|
|
284
|
+
]);
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* True when a subschema holds a `$ref` anywhere a schema can appear. Only those positions are
|
|
288
|
+
* walked: `$ref` under `default` or an `x-` annotation is instance data with an ordinary key, and
|
|
289
|
+
* reading it as a reference would drop a constraint that resolves perfectly well.
|
|
290
|
+
*/
|
|
291
|
+
function containsRef(value: unknown): boolean {
|
|
292
|
+
if (typeof value !== "object" || value === null) return false;
|
|
293
|
+
if (Array.isArray(value)) return value.some(containsRef);
|
|
294
|
+
if (typeof (value as any).$ref === "string") return true;
|
|
295
|
+
return Object.entries(value).some(([key, sub]) => {
|
|
296
|
+
if (SCHEMA_KEYWORDS.has(key)) return containsRef(sub);
|
|
297
|
+
if (!SCHEMA_MAP_KEYWORDS.has(key) || typeof sub !== "object" || sub === null) return false;
|
|
298
|
+
return Object.values(sub).some(containsRef);
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function plural(n: number): string {
|
|
303
|
+
return n === 1 ? "element" : "elements";
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Enforces `uniqueItems` and the `contains` family before `arraySchema` runs, for the same reason
|
|
308
|
+
* `checkObjectGuards` runs pre-pipe: an item parse can apply a nested `default`, so the parsed
|
|
309
|
+
* array is not the instance the keywords are defined over. A guard issue aborts the pipe, so
|
|
310
|
+
* `minItems`/`maxItems` are not also reported on the same parse — instance correctness is worth
|
|
311
|
+
* more than co-reporting two issues.
|
|
312
|
+
*/
|
|
313
|
+
function checkArrayGuards(
|
|
314
|
+
arraySchema: ZodType,
|
|
315
|
+
guards: {
|
|
316
|
+
uniqueItems?: boolean | undefined;
|
|
317
|
+
containsSchema?: ZodType | undefined;
|
|
318
|
+
minContains?: number | undefined;
|
|
319
|
+
maxContains?: number | undefined;
|
|
320
|
+
}
|
|
321
|
+
): ZodType {
|
|
322
|
+
// An identity transform, not z.any(), so `toJSONSchema` reports the array on both the input and the output side of the pipe.
|
|
323
|
+
const guard = z
|
|
324
|
+
.transform((value: unknown) => value)
|
|
325
|
+
.check((payload) => {
|
|
326
|
+
const items = payload.value;
|
|
327
|
+
if (!Array.isArray(items)) return;
|
|
328
|
+
if (guards.uniqueItems === true) {
|
|
329
|
+
const firstSeen = new Map<string, number>();
|
|
330
|
+
for (let i = 0; i < items.length; i++) {
|
|
331
|
+
const key = canonicalKey(items[i], new Set());
|
|
332
|
+
if (key === null) continue;
|
|
333
|
+
const first = firstSeen.get(key);
|
|
334
|
+
if (first === undefined) {
|
|
335
|
+
firstSeen.set(key, i);
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
payload.issues.push({
|
|
339
|
+
code: "custom",
|
|
340
|
+
message: `Array items must be unique: element at index ${i} duplicates the one at index ${first}`,
|
|
341
|
+
input: items,
|
|
342
|
+
path: [i],
|
|
343
|
+
continue: true,
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
if (guards.containsSchema) {
|
|
348
|
+
const minContains = guards.minContains ?? 1;
|
|
349
|
+
// one past the ceiling already proves the failure, and nothing above it changes the verdict
|
|
350
|
+
const ceiling = guards.maxContains !== undefined ? guards.maxContains + 1 : Number.POSITIVE_INFINITY;
|
|
351
|
+
let matches = 0;
|
|
352
|
+
for (const item of items) {
|
|
353
|
+
if (guards.containsSchema.safeParse(item).success && ++matches >= ceiling) break;
|
|
354
|
+
}
|
|
355
|
+
if (matches < minContains) {
|
|
356
|
+
// the scan ran to the end, so this count is exact
|
|
357
|
+
payload.issues.push({
|
|
358
|
+
code: "custom",
|
|
359
|
+
message: `Array must contain at least ${minContains} matching ${plural(minContains)}; found ${matches}`,
|
|
360
|
+
input: items,
|
|
361
|
+
continue: true,
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
if (guards.maxContains !== undefined && matches > guards.maxContains) {
|
|
365
|
+
payload.issues.push({
|
|
366
|
+
code: "custom",
|
|
367
|
+
message: `Array must contain at most ${guards.maxContains} matching ${plural(guards.maxContains)}`,
|
|
368
|
+
input: items,
|
|
369
|
+
continue: true,
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
return guard.pipe(arraySchema);
|
|
375
|
+
}
|
|
376
|
+
|
|
186
377
|
function getTupleRest(restSchema: JSONSchema._JSONSchema | undefined, ctx: ConversionContext): ZodType | undefined {
|
|
187
378
|
if (restSchema === false) {
|
|
188
379
|
return undefined;
|
|
@@ -351,6 +542,8 @@ function convertBaseSchema(schema: JSONSchema.JSONSchema, ctx: ConversionContext
|
|
|
351
542
|
stringSchema = stringSchema.check(z.e164());
|
|
352
543
|
} else if (format === "credit_card") {
|
|
353
544
|
stringSchema = stringSchema.check(z.creditCard());
|
|
545
|
+
} else if (format === "iban") {
|
|
546
|
+
stringSchema = stringSchema.check(z.iban());
|
|
354
547
|
} else if (format === "jwt") {
|
|
355
548
|
stringSchema = stringSchema.check(z.jwt());
|
|
356
549
|
} else if (format === "emoji") {
|
|
@@ -519,20 +712,25 @@ function convertBaseSchema(schema: JSONSchema.JSONSchema, ctx: ConversionContext
|
|
|
519
712
|
}
|
|
520
713
|
|
|
521
714
|
// propertyNames constrains key *names* only, and says nothing about which keys are required or how their values validate. Layering it on top of the result keeps properties/patternProperties/additionalProperties composing underneath. `true` allows every name, so it needs no guard.
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
715
|
+
const hasKeyGuard = schema.propertyNames !== undefined && schema.propertyNames !== true;
|
|
716
|
+
const minProperties = typeof schema.minProperties === "number" ? schema.minProperties : undefined;
|
|
717
|
+
const maxProperties = typeof schema.maxProperties === "number" ? schema.maxProperties : undefined;
|
|
718
|
+
if (hasKeyGuard || minProperties !== undefined || maxProperties !== undefined) {
|
|
719
|
+
let keySchema: ZodType | undefined;
|
|
720
|
+
if (hasKeyGuard) {
|
|
721
|
+
// Keys are always strings, so a propertyNames subschema that omits `type` still constrains them — without this it would convert to z.any().
|
|
722
|
+
const keyJSONSchema =
|
|
723
|
+
typeof schema.propertyNames === "object" && schema.propertyNames.type === undefined
|
|
724
|
+
? { type: "string", ...schema.propertyNames }
|
|
725
|
+
: schema.propertyNames;
|
|
726
|
+
keySchema = convertSchema(keyJSONSchema as JSONSchema.JSONSchema, ctx);
|
|
727
|
+
}
|
|
728
|
+
zodSchema = checkObjectGuards(zodSchema, { keySchema, minProperties, maxProperties });
|
|
529
729
|
}
|
|
530
730
|
break;
|
|
531
731
|
}
|
|
532
732
|
|
|
533
733
|
case "array": {
|
|
534
|
-
// TODO: uniqueItems and contains/minContains/maxContains are not supported
|
|
535
|
-
|
|
536
734
|
// Check if this is a tuple (prefixItems or items as array)
|
|
537
735
|
const prefixItems = schema.prefixItems;
|
|
538
736
|
const items = schema.items;
|
|
@@ -585,6 +783,18 @@ function convertBaseSchema(schema: JSONSchema.JSONSchema, ctx: ConversionContext
|
|
|
585
783
|
// No items specified - array of any
|
|
586
784
|
zodSchema = z.array(z.any());
|
|
587
785
|
}
|
|
786
|
+
|
|
787
|
+
// minContains/maxContains only constrain anything when `contains` itself is present
|
|
788
|
+
if (schema.uniqueItems === true || schema.contains !== undefined) {
|
|
789
|
+
zodSchema = checkArrayGuards(zodSchema, {
|
|
790
|
+
uniqueItems: schema.uniqueItems === true,
|
|
791
|
+
containsSchema:
|
|
792
|
+
schema.contains !== undefined ? convertSchema(schema.contains as JSONSchema.JSONSchema, ctx) : undefined,
|
|
793
|
+
minContains: typeof schema.minContains === "number" ? schema.minContains : undefined,
|
|
794
|
+
maxContains: typeof schema.maxContains === "number" ? schema.maxContains : undefined,
|
|
795
|
+
});
|
|
796
|
+
}
|
|
797
|
+
|
|
588
798
|
break;
|
|
589
799
|
}
|
|
590
800
|
|
|
@@ -666,9 +876,22 @@ function convertSchema(schema: JSONSchema.JSONSchema | boolean, ctx: ConversionC
|
|
|
666
876
|
}
|
|
667
877
|
}
|
|
668
878
|
|
|
669
|
-
// `propertyNames`
|
|
670
|
-
if (schema.
|
|
671
|
-
|
|
879
|
+
// `propertyNames` and `contains` are enforced by a guard, which `toJSONSchema` cannot infer, so the original keyword is carried as metadata to keep the round-trip lossless. Only where it was actually applied: on any other type it is inert, and on a `$ref` the metadata would land on the target every reference shares. A carried subschema is copied verbatim while the root `$defs` stay behind, so one holding a `$ref` is dropped rather than emitted as a dangling reference.
|
|
880
|
+
if (schema.type === "object" && schema.$ref === undefined) {
|
|
881
|
+
if (schema.propertyNames !== undefined && !containsRef(schema.propertyNames)) {
|
|
882
|
+
extraMeta.propertyNames = schema.propertyNames;
|
|
883
|
+
}
|
|
884
|
+
for (const key of ["minProperties", "maxProperties"] as const) {
|
|
885
|
+
if (schema[key] !== undefined) extraMeta[key] = schema[key];
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
if (schema.type === "array" && schema.$ref === undefined) {
|
|
889
|
+
if (schema.contains !== undefined && !containsRef(schema.contains)) {
|
|
890
|
+
extraMeta.contains = schema.contains;
|
|
891
|
+
}
|
|
892
|
+
for (const key of ["uniqueItems", "minContains", "maxContains"] as const) {
|
|
893
|
+
if (schema[key] !== undefined) extraMeta[key] = schema[key];
|
|
894
|
+
}
|
|
672
895
|
}
|
|
673
896
|
|
|
674
897
|
for (const key of Object.keys(schema)) {
|