zod 4.5.3 → 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 +316 -0
- package/src/v4/classic/tests/default.test.ts +46 -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 +162 -36
- 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 +204 -36
- package/v4/core/memoizer.js +162 -36
- 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/src/v4/core/util.ts
CHANGED
|
@@ -98,11 +98,29 @@ type ToZodKeyMismatch<Expected, Received> = schemas.$ZodType & {
|
|
|
98
98
|
"types do not match": { expected: Expected; received: Received };
|
|
99
99
|
};
|
|
100
100
|
|
|
101
|
+
// An enum reference and the union of exactly its members are mutually assignable but not identical, so `AssertEqual` alone rejects `z.enum(SomeEnum)` against a `SomeEnum` target. Unioning each side with a private dummy forces the union to be rebuilt, which collapses that one difference and nothing else — plain literals against an enum, member subsets, brands and `any` all still fail. The symbol is not exported, so no user type can smuggle it in and cancel a real difference.
|
|
102
|
+
declare const toZodDummy: unique symbol;
|
|
103
|
+
|
|
104
|
+
// Homomorphic, so `readonly` and optional modifiers survive the rebuild and only leaves are normalized. An intersection flattens here, which is why an intersection target and the flat object with the same keys match each other. A callable stops the walk because `keyof` a function is `never`, so mapping one would erase its signature and make every function compare equal.
|
|
105
|
+
type ToZodNormalize<T> = [T] extends [(...args: any[]) => any]
|
|
106
|
+
? T
|
|
107
|
+
: [T] extends [object]
|
|
108
|
+
? { [K in keyof T]: ToZodNormalize<T[K]> }
|
|
109
|
+
: T | typeof toZodDummy;
|
|
110
|
+
|
|
111
|
+
type ToZodEqual<Output, T> = AssertEqual<Output, T> extends true
|
|
112
|
+
? true
|
|
113
|
+
: IsAny<Output> extends true
|
|
114
|
+
? false
|
|
115
|
+
: IsAny<T> extends true
|
|
116
|
+
? false
|
|
117
|
+
: AssertEqual<ToZodNormalize<Output>, ToZodNormalize<T>>;
|
|
118
|
+
|
|
101
119
|
// Rebuilds the shape with a marker on each key that disagrees, so the diagnostic names the key instead of failing the whole schema at the top level. A key the target lacks reports `expected: never`; a key the schema lacks reports `received: never`.
|
|
102
120
|
type ToZodShape<Shape, T> = {
|
|
103
121
|
[K in keyof Shape]: Shape[K] extends schemas.$ZodType
|
|
104
122
|
? K extends keyof T
|
|
105
|
-
?
|
|
123
|
+
? ToZodEqual<Shape[K]["_zod"]["output"], T[K]> extends true
|
|
106
124
|
? Shape[K]
|
|
107
125
|
: ToZodKeyMismatch<T[K], Shape[K]["_zod"]["output"]>
|
|
108
126
|
: ToZodKeyMismatch<never, Shape[K]["_zod"]["output"]>
|
|
@@ -129,6 +147,17 @@ export type MakeRequired<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K
|
|
|
129
147
|
export type Exactly<T, X> = T & Record<Exclude<keyof X, keyof T>, never>;
|
|
130
148
|
export type NoUndefined<T> = T extends undefined ? never : T;
|
|
131
149
|
export type Whatever = {} | undefined | null;
|
|
150
|
+
// literal inputs widen to their primitive so a property check over `"https:"` accepts a `string` property
|
|
151
|
+
export type Widen<T> = T extends string
|
|
152
|
+
? string
|
|
153
|
+
: T extends number
|
|
154
|
+
? number
|
|
155
|
+
: T extends boolean
|
|
156
|
+
? boolean
|
|
157
|
+
: T extends bigint
|
|
158
|
+
? bigint
|
|
159
|
+
: T;
|
|
160
|
+
|
|
132
161
|
export type LoosePartial<T extends object> = InexactPartial<T> & {
|
|
133
162
|
[k: string]: unknown;
|
|
134
163
|
};
|
|
@@ -232,7 +261,7 @@ export function assertNotEqual<A, B>(val: AssertNotEqual<A, B>): AssertNotEqual<
|
|
|
232
261
|
}
|
|
233
262
|
|
|
234
263
|
export function toZod<T>(): <S extends schemas.$ZodType>(
|
|
235
|
-
schema:
|
|
264
|
+
schema: ToZodEqual<S["_zod"]["output"], T> extends true ? S : ToZodTarget<S, T>
|
|
236
265
|
) => S {
|
|
237
266
|
return (schema) => schema as any;
|
|
238
267
|
}
|
|
@@ -261,18 +290,28 @@ export function jsonStringifyReplacer(_: string, value: any): any {
|
|
|
261
290
|
return value;
|
|
262
291
|
}
|
|
263
292
|
|
|
293
|
+
// the accessor lives on a shared prototype: an own accessor makes every box a dictionary-mode object (~360 B and a slow load per read against ~100 B and an inlined getter here)
|
|
294
|
+
class Cached<T> {
|
|
295
|
+
_getter: (() => T) | undefined;
|
|
296
|
+
_value: T | undefined;
|
|
297
|
+
|
|
298
|
+
constructor(getter: () => T) {
|
|
299
|
+
this._getter = getter;
|
|
300
|
+
this._value = undefined;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
get value(): T {
|
|
304
|
+
const getter = this._getter;
|
|
305
|
+
if (getter !== undefined) {
|
|
306
|
+
this._value = getter();
|
|
307
|
+
this._getter = undefined;
|
|
308
|
+
}
|
|
309
|
+
return this._value as T;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
264
313
|
export function cached<T>(getter: () => T): { value: T } {
|
|
265
|
-
|
|
266
|
-
return {
|
|
267
|
-
get value() {
|
|
268
|
-
if (!set) {
|
|
269
|
-
const value = getter();
|
|
270
|
-
Object.defineProperty(this, "value", { value });
|
|
271
|
-
return value;
|
|
272
|
-
}
|
|
273
|
-
throw new Error("cached value already set");
|
|
274
|
-
},
|
|
275
|
-
};
|
|
314
|
+
return new Cached(getter);
|
|
276
315
|
}
|
|
277
316
|
|
|
278
317
|
export function nullish(input: any): boolean {
|
|
@@ -338,6 +377,80 @@ export function assignProp<T extends object, K extends PropertyKey>(
|
|
|
338
377
|
});
|
|
339
378
|
}
|
|
340
379
|
|
|
380
|
+
/** A def's `shape` accessor, carrying whichever object it currently answers from. */
|
|
381
|
+
export interface ShapeGetter {
|
|
382
|
+
(): Record<PropertyKey, any>;
|
|
383
|
+
raw: Record<PropertyKey, any>;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Whichever object a def's `shape` currently answers from: the one the caller passed until the first read, the frozen copy after it.
|
|
388
|
+
*
|
|
389
|
+
* Its keys and descriptors read without invoking anything, which is what lets a discriminated union check its discriminator, and the cycle walk read a shape, without resolving a getter that references the schema being constructed. A def that answers `shape` from an accessor of its own has none.
|
|
390
|
+
*/
|
|
391
|
+
export function rawShape(def: any): Record<PropertyKey, any> | undefined {
|
|
392
|
+
const desc = Object.getOwnPropertyDescriptor(def, "shape");
|
|
393
|
+
return desc?.get ? (desc.get as ShapeGetter).raw : desc?.value;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// where a builder reads its source's keys and descriptors, resolving only a shape a def answers for itself. A shape resolves by object spread, so only its enumerable keys are ever part of it.
|
|
397
|
+
function sourceShape(schema: schemas.$ZodObject): Record<PropertyKey, any> {
|
|
398
|
+
return rawShape(schema._zod.def) ?? (schema._zod.def.shape as any);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// a key whose value is not settled yet, self-caching so every read after the first gets the same one
|
|
402
|
+
function deferProp(target: object, key: PropertyKey, getter: () => any): void {
|
|
403
|
+
Object.defineProperty(target, key, {
|
|
404
|
+
get(this: any) {
|
|
405
|
+
const value = getter();
|
|
406
|
+
assignProp(this, key as any, value);
|
|
407
|
+
return value;
|
|
408
|
+
},
|
|
409
|
+
enumerable: true,
|
|
410
|
+
configurable: true,
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Writes a settled key. A plain assignment is much cheaper than `defineProperty` and produces the same descriptor, but it runs whatever setter already answers to the key — an accessor this shape deferred, or an inherited one, which `__proto__` has on every object and prototype pollution can add for any name.
|
|
415
|
+
function putProp(target: any, key: PropertyKey, value: any): void {
|
|
416
|
+
if (key in target) assignProp(target, key as any, value);
|
|
417
|
+
else target[key] = value;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Copies `keys` of `source`'s shape onto `target`, each value passed through `wrap`.
|
|
422
|
+
*
|
|
423
|
+
* A key the source has resolved is copied through now, so the derived shape states it outright and nothing has to resolve it to learn what it holds. A key the source still defers stays deferred, and reads back through the source's own `shape`, so it resolves once and both shapes get that one schema.
|
|
424
|
+
*/
|
|
425
|
+
function mirrorShape(
|
|
426
|
+
target: object,
|
|
427
|
+
source: schemas.$ZodObject,
|
|
428
|
+
keys: PropertyKey[],
|
|
429
|
+
wrap?: ((value: any, key: PropertyKey) => any) | null
|
|
430
|
+
): void {
|
|
431
|
+
const raw = sourceShape(source);
|
|
432
|
+
for (const key of keys) {
|
|
433
|
+
const desc = Object.getOwnPropertyDescriptor(raw, key)!;
|
|
434
|
+
if (!desc.enumerable) continue;
|
|
435
|
+
if (desc.get) {
|
|
436
|
+
deferProp(target, key, () => {
|
|
437
|
+
const value = (source._zod.def.shape as any)[key];
|
|
438
|
+
return wrap ? wrap(value, key) : value;
|
|
439
|
+
});
|
|
440
|
+
} else putProp(target, key, wrap ? wrap(desc.value, key) : desc.value);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// same, for a plain shape a caller passed rather than a schema's
|
|
445
|
+
function mirrorProps(target: object, source: Record<PropertyKey, any>): void {
|
|
446
|
+
for (const key of Reflect.ownKeys(source)) {
|
|
447
|
+
const desc = Object.getOwnPropertyDescriptor(source, key)!;
|
|
448
|
+
if (!desc.enumerable) continue;
|
|
449
|
+
if (desc.get) deferProp(target, key, () => source[key as any]);
|
|
450
|
+
else putProp(target, key, desc.value);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
341
454
|
export function mergeDefs(...defs: Record<string, any>[]): any {
|
|
342
455
|
const mergedDescriptors: Record<string, PropertyDescriptor> = {};
|
|
343
456
|
|
|
@@ -647,25 +760,24 @@ export function pick(schema: schemas.$ZodObject, mask: Record<string, unknown>):
|
|
|
647
760
|
throw new Error(".pick() cannot be used on object schemas containing refinements");
|
|
648
761
|
}
|
|
649
762
|
|
|
650
|
-
const
|
|
651
|
-
|
|
652
|
-
const newShape: Writeable<schemas.$ZodShape> = {};
|
|
653
|
-
// `for...in` skips symbols, so a symbol in the mask would select nothing
|
|
654
|
-
for (const key of Reflect.ownKeys(mask)) {
|
|
655
|
-
if (!Object.prototype.hasOwnProperty.call(currDef.shape, key)) {
|
|
656
|
-
throw new Error(`Unrecognized key: "${String(key)}"`);
|
|
657
|
-
}
|
|
658
|
-
if (!mask[key as string]) continue;
|
|
659
|
-
assignProp(newShape, key as string, (currDef.shape as any)[key]!);
|
|
660
|
-
}
|
|
763
|
+
const newShape: Writeable<schemas.$ZodShape> = {};
|
|
764
|
+
mirrorShape(newShape, schema, maskedKeys(schema, mask));
|
|
661
765
|
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
},
|
|
665
|
-
checks: [],
|
|
666
|
-
});
|
|
766
|
+
return clone(schema, mergeDefs(currDef, { shape: newShape, checks: [] })) as any;
|
|
767
|
+
}
|
|
667
768
|
|
|
668
|
-
|
|
769
|
+
// the mask keys that select something, checked against the source's shape without resolving it
|
|
770
|
+
function maskedKeys(schema: schemas.$ZodObject, mask: object): PropertyKey[] {
|
|
771
|
+
const raw = sourceShape(schema);
|
|
772
|
+
const keys: PropertyKey[] = [];
|
|
773
|
+
// `for...in` skips symbols, so a symbol in the mask would select nothing
|
|
774
|
+
for (const key of Reflect.ownKeys(mask)) {
|
|
775
|
+
if (!Object.getOwnPropertyDescriptor(raw, key)?.enumerable) {
|
|
776
|
+
throw new Error(`Unrecognized key: "${String(key)}"`);
|
|
777
|
+
}
|
|
778
|
+
if ((mask as any)[key]) keys.push(key);
|
|
779
|
+
}
|
|
780
|
+
return keys;
|
|
669
781
|
}
|
|
670
782
|
|
|
671
783
|
export function omit(schema: schemas.$ZodObject, mask: object): any {
|
|
@@ -677,24 +789,15 @@ export function omit(schema: schemas.$ZodObject, mask: object): any {
|
|
|
677
789
|
throw new Error(".omit() cannot be used on object schemas containing refinements");
|
|
678
790
|
}
|
|
679
791
|
|
|
680
|
-
const
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
if (!(mask as any)[key]) continue;
|
|
688
|
-
|
|
689
|
-
delete newShape[key as string];
|
|
690
|
-
}
|
|
691
|
-
assignProp(this, "shape", newShape); // self-caching
|
|
692
|
-
return newShape;
|
|
693
|
-
},
|
|
694
|
-
checks: [],
|
|
695
|
-
});
|
|
792
|
+
const omitted = new Set(maskedKeys(schema, mask));
|
|
793
|
+
const newShape: Writeable<schemas.$ZodShape> = {};
|
|
794
|
+
mirrorShape(
|
|
795
|
+
newShape,
|
|
796
|
+
schema,
|
|
797
|
+
Reflect.ownKeys(sourceShape(schema)).filter((key) => !omitted.has(key))
|
|
798
|
+
);
|
|
696
799
|
|
|
697
|
-
return clone(schema,
|
|
800
|
+
return clone(schema, mergeDefs(currDef, { shape: newShape, checks: [] }));
|
|
698
801
|
}
|
|
699
802
|
|
|
700
803
|
export function extend(schema: schemas.$ZodObject, shape: schemas.$ZodShape): any {
|
|
@@ -706,7 +809,7 @@ export function extend(schema: schemas.$ZodObject, shape: schemas.$ZodShape): an
|
|
|
706
809
|
const hasChecks = checks && checks.length > 0;
|
|
707
810
|
if (hasChecks) {
|
|
708
811
|
// Only throw if new shape overlaps with existing shape. Use getOwnPropertyDescriptor to check key existence without accessing values
|
|
709
|
-
const existingShape = schema
|
|
812
|
+
const existingShape = sourceShape(schema);
|
|
710
813
|
for (const key of Reflect.ownKeys(shape)) {
|
|
711
814
|
if (Object.getOwnPropertyDescriptor(existingShape, key) !== undefined) {
|
|
712
815
|
throw new Error("Cannot overwrite keys on object schemas containing refinements. Use `.safeExtend()` instead.");
|
|
@@ -714,28 +817,22 @@ export function extend(schema: schemas.$ZodObject, shape: schemas.$ZodShape): an
|
|
|
714
817
|
}
|
|
715
818
|
}
|
|
716
819
|
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
820
|
+
return clone(schema, mergeDefs(schema._zod.def, { shape: extended(schema, shape) })) as any;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// the source's keys, then the caller's overlaid on top
|
|
824
|
+
function extended(schema: schemas.$ZodObject, shape: schemas.$ZodShape): schemas.$ZodShape {
|
|
825
|
+
const newShape: Writeable<schemas.$ZodShape> = {};
|
|
826
|
+
mirrorShape(newShape, schema, Reflect.ownKeys(sourceShape(schema)));
|
|
827
|
+
mirrorProps(newShape, shape);
|
|
828
|
+
return newShape;
|
|
725
829
|
}
|
|
726
830
|
|
|
727
831
|
export function safeExtend(schema: schemas.$ZodObject, shape: schemas.$ZodShape): any {
|
|
728
832
|
if (!isPlainObject(shape)) {
|
|
729
833
|
throw new Error("Invalid input to safeExtend: expected a plain object");
|
|
730
834
|
}
|
|
731
|
-
|
|
732
|
-
get shape() {
|
|
733
|
-
const _shape = { ...schema._zod.def.shape, ...shape };
|
|
734
|
-
assignProp(this, "shape", _shape); // self-caching
|
|
735
|
-
return _shape;
|
|
736
|
-
},
|
|
737
|
-
});
|
|
738
|
-
return clone(schema, def) as any;
|
|
835
|
+
return clone(schema, mergeDefs(schema._zod.def, { shape: extended(schema, shape) })) as any;
|
|
739
836
|
}
|
|
740
837
|
|
|
741
838
|
export function merge(a: schemas.$ZodObject, b: schemas.$ZodObject): any {
|
|
@@ -745,12 +842,12 @@ export function merge(a: schemas.$ZodObject, b: schemas.$ZodObject): any {
|
|
|
745
842
|
if (a._zod.def.checks?.length) {
|
|
746
843
|
throw new Error(".merge() cannot be used on object schemas containing refinements. Use .safeExtend() instead.");
|
|
747
844
|
}
|
|
845
|
+
const newShape: Writeable<schemas.$ZodShape> = {};
|
|
846
|
+
mirrorShape(newShape, a, Reflect.ownKeys(sourceShape(a)));
|
|
847
|
+
mirrorShape(newShape, b, Reflect.ownKeys(sourceShape(b)));
|
|
848
|
+
|
|
748
849
|
const def = mergeDefs(a._zod.def, {
|
|
749
|
-
|
|
750
|
-
const _shape = { ...a._zod.def.shape, ...b._zod.def.shape };
|
|
751
|
-
assignProp(this, "shape", _shape); // self-caching
|
|
752
|
-
return _shape;
|
|
753
|
-
},
|
|
850
|
+
shape: newShape,
|
|
754
851
|
get catchall() {
|
|
755
852
|
return b._zod.def.catchall;
|
|
756
853
|
},
|
|
@@ -773,45 +870,17 @@ export function partial(
|
|
|
773
870
|
throw new Error(`.${name}() cannot be used on object schemas containing refinements`);
|
|
774
871
|
}
|
|
775
872
|
|
|
776
|
-
const
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
}
|
|
786
|
-
if (!(mask as any)[key]) continue;
|
|
787
|
-
// if (oldShape[key]!._zod.optin === "optional") continue;
|
|
788
|
-
(shape as any)[key] = Class
|
|
789
|
-
? new Class({
|
|
790
|
-
type: "optional",
|
|
791
|
-
innerType: (oldShape as any)[key]!,
|
|
792
|
-
})
|
|
793
|
-
: (oldShape as any)[key]!;
|
|
794
|
-
}
|
|
795
|
-
} else {
|
|
796
|
-
// the spread copies symbol keys; `for...in` would not reach them
|
|
797
|
-
for (const key of Reflect.ownKeys(oldShape)) {
|
|
798
|
-
// if (oldShape[key]!._zod.optin === "optional") continue;
|
|
799
|
-
(shape as any)[key] = Class
|
|
800
|
-
? new Class({
|
|
801
|
-
type: "optional",
|
|
802
|
-
innerType: (oldShape as any)[key]!,
|
|
803
|
-
})
|
|
804
|
-
: (oldShape as any)[key]!;
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
assignProp(this, "shape", shape); // self-caching
|
|
809
|
-
return shape;
|
|
810
|
-
},
|
|
811
|
-
checks: [],
|
|
812
|
-
});
|
|
873
|
+
const selected = mask ? new Set(maskedKeys(schema, mask)) : undefined;
|
|
874
|
+
const newShape: Writeable<schemas.$ZodShape> = {};
|
|
875
|
+
mirrorShape(
|
|
876
|
+
newShape,
|
|
877
|
+
schema,
|
|
878
|
+
Reflect.ownKeys(sourceShape(schema)),
|
|
879
|
+
Class &&
|
|
880
|
+
((value, key) => (selected && !selected.has(key) ? value : new Class({ type: "optional", innerType: value })))
|
|
881
|
+
);
|
|
813
882
|
|
|
814
|
-
return clone(schema, def) as any;
|
|
883
|
+
return clone(schema, mergeDefs(schema._zod.def, { shape: newShape, checks: [] })) as any;
|
|
815
884
|
}
|
|
816
885
|
|
|
817
886
|
export function required(
|
|
@@ -819,39 +888,14 @@ export function required(
|
|
|
819
888
|
schema: schemas.$ZodObject,
|
|
820
889
|
mask: object | undefined
|
|
821
890
|
): any {
|
|
822
|
-
const
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
for (const key of Reflect.ownKeys(mask)) {
|
|
829
|
-
if (!Object.prototype.hasOwnProperty.call(shape, key)) {
|
|
830
|
-
throw new Error(`Unrecognized key: "${String(key)}"`);
|
|
831
|
-
}
|
|
832
|
-
if (!(mask as any)[key]) continue;
|
|
833
|
-
// overwrite with non-optional
|
|
834
|
-
(shape as any)[key] = new Class({
|
|
835
|
-
type: "nonoptional",
|
|
836
|
-
innerType: (oldShape as any)[key]!,
|
|
837
|
-
});
|
|
838
|
-
}
|
|
839
|
-
} else {
|
|
840
|
-
for (const key of Reflect.ownKeys(oldShape)) {
|
|
841
|
-
// overwrite with non-optional
|
|
842
|
-
(shape as any)[key] = new Class({
|
|
843
|
-
type: "nonoptional",
|
|
844
|
-
innerType: (oldShape as any)[key]!,
|
|
845
|
-
});
|
|
846
|
-
}
|
|
847
|
-
}
|
|
891
|
+
const selected = mask ? new Set(maskedKeys(schema, mask)) : undefined;
|
|
892
|
+
const newShape: Writeable<schemas.$ZodShape> = {};
|
|
893
|
+
mirrorShape(newShape, schema, Reflect.ownKeys(sourceShape(schema)), (value, key) =>
|
|
894
|
+
// overwrite with non-optional
|
|
895
|
+
selected && !selected.has(key) ? value : new Class({ type: "nonoptional", innerType: value })
|
|
896
|
+
);
|
|
848
897
|
|
|
849
|
-
|
|
850
|
-
return shape;
|
|
851
|
-
},
|
|
852
|
-
});
|
|
853
|
-
|
|
854
|
-
return clone(schema, def) as any;
|
|
898
|
+
return clone(schema, mergeDefs(schema._zod.def, { shape: newShape })) as any;
|
|
855
899
|
}
|
|
856
900
|
|
|
857
901
|
export type Constructor<T, Def extends any[] = any[]> = new (...args: Def) => T;
|
|
@@ -920,13 +964,18 @@ export function finalizeIssue(
|
|
|
920
964
|
unwrapMessage(config.localeError?.(iss)) ??
|
|
921
965
|
"Invalid input");
|
|
922
966
|
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
967
|
+
// an explicit own-key copy beats object rest with excluded keys, which v8 routes through a generic runtime call; Object.keys rather than for-in so an issue pushed with a prototype does not leak inherited keys, and an own __proto__ key is dropped rather than assigned through the setter
|
|
968
|
+
const full: any = {};
|
|
969
|
+
for (const k of Object.keys(iss)) {
|
|
970
|
+
if (k === "inst" || k === "schema" || k === "continue" || k === "input" || k === "__proto__") continue;
|
|
971
|
+
full[k] = (iss as any)[k];
|
|
972
|
+
}
|
|
973
|
+
full.path ??= [];
|
|
974
|
+
full.message = message;
|
|
926
975
|
if (ctx?.reportInput) {
|
|
927
|
-
|
|
976
|
+
full.input = iss.input;
|
|
928
977
|
}
|
|
929
|
-
return
|
|
978
|
+
return full;
|
|
930
979
|
}
|
|
931
980
|
|
|
932
981
|
export function getSizableOrigin(input: any): "set" | "map" | "file" | "unknown" {
|
|
@@ -1076,20 +1125,46 @@ export function members(proto: object, table: object): void {
|
|
|
1076
1125
|
// a method materializes bound on first read, which is what keeps a detached member working: `const opt = schema.optional; opt()`
|
|
1077
1126
|
else defineBound(proto, key, desc.value);
|
|
1078
1127
|
}
|
|
1128
|
+
// for..in sees no symbol keys, so well-known members like Symbol.iterator install here
|
|
1129
|
+
for (const sym of Object.getOwnPropertySymbols(table)) {
|
|
1130
|
+
defineBound(proto, sym, (table as any)[sym]);
|
|
1131
|
+
}
|
|
1079
1132
|
}
|
|
1080
1133
|
|
|
1081
1134
|
/** Shadows a prototype member with an own value, so a getter that builds from the instance runs once. */
|
|
1082
|
-
export function own<T>(inst: object, key:
|
|
1135
|
+
export function own<T>(inst: object, key: PropertyKey, value: T, enumerable = true): T {
|
|
1083
1136
|
Object.defineProperty(inst, key, { configurable: true, writable: true, enumerable, value });
|
|
1084
1137
|
return value;
|
|
1085
1138
|
}
|
|
1086
1139
|
|
|
1087
1140
|
/** Like {@link own}, for a member that was never an own data property and has to stay out of `Object.keys`. */
|
|
1088
|
-
export function hide<T>(inst: object, key:
|
|
1141
|
+
export function hide<T>(inst: object, key: PropertyKey, value: T): T {
|
|
1089
1142
|
return own(inst, key, value, false);
|
|
1090
1143
|
}
|
|
1091
1144
|
|
|
1092
|
-
|
|
1145
|
+
/** Adds members a table derives from the instance: each builds on first read and shadows as own data, and assignment shadows the same way, as when these were own properties. */
|
|
1146
|
+
export /*@__NO_SIDE_EFFECTS__*/ function derived<T>(
|
|
1147
|
+
computes: { [K in keyof T]?: (inst: T) => T[K] },
|
|
1148
|
+
table: ProtoOf<T>
|
|
1149
|
+
): ProtoOf<T> {
|
|
1150
|
+
for (const key in computes) {
|
|
1151
|
+
const compute = computes[key]!;
|
|
1152
|
+
// an object literal's accessor is configurable and enumerable, and `members` copies the descriptor as written
|
|
1153
|
+
Object.defineProperty(table, key, {
|
|
1154
|
+
configurable: true,
|
|
1155
|
+
enumerable: true,
|
|
1156
|
+
get(this: T) {
|
|
1157
|
+
return own(this as object, key, compute(this));
|
|
1158
|
+
},
|
|
1159
|
+
set(this: T, value: T[typeof key]) {
|
|
1160
|
+
own(this as object, key, value);
|
|
1161
|
+
},
|
|
1162
|
+
});
|
|
1163
|
+
}
|
|
1164
|
+
return table;
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
function defineBound(proto: object, key: PropertyKey, fn: AnyFunc): void {
|
|
1093
1168
|
Object.defineProperty(proto, key, {
|
|
1094
1169
|
configurable: true,
|
|
1095
1170
|
get(this: any) {
|
package/src/v4/core/versions.ts
CHANGED
package/src/v4/core/visit.ts
CHANGED
|
@@ -158,6 +158,17 @@ export function visit(schema: schemas.SomeType, fnOrHandlers: VisitFn | VisitHan
|
|
|
158
158
|
const { _cachedInner, ...rest } = def;
|
|
159
159
|
return clone(s, { ...rest, getter: () => run(original()) });
|
|
160
160
|
}
|
|
161
|
+
case "properties": {
|
|
162
|
+
const oldShape = def.shape as Record<string | symbol, AnyZod>;
|
|
163
|
+
let changed = false;
|
|
164
|
+
const newShape: Record<string | symbol, AnyZod> = {};
|
|
165
|
+
for (const k of Reflect.ownKeys(oldShape)) {
|
|
166
|
+
const mapped = run(oldShape[k]!);
|
|
167
|
+
if (mapped !== oldShape[k]) changed = true;
|
|
168
|
+
newShape[k] = mapped;
|
|
169
|
+
}
|
|
170
|
+
return changed ? clone(s, { ...def, shape: newShape }) : s;
|
|
171
|
+
}
|
|
161
172
|
// A leaf by choice: `parts` are regex fragments, not data positions.
|
|
162
173
|
case "template_literal":
|
|
163
174
|
// Leaves.
|
package/src/v4/locales/ar.ts
CHANGED
package/src/v4/locales/az.ts
CHANGED
package/src/v4/locales/be.ts
CHANGED
package/src/v4/locales/bg.ts
CHANGED
package/src/v4/locales/bn.ts
CHANGED
package/src/v4/locales/ca.ts
CHANGED
package/src/v4/locales/ckb.ts
CHANGED
package/src/v4/locales/cs.ts
CHANGED
package/src/v4/locales/da.ts
CHANGED
package/src/v4/locales/de.ts
CHANGED
package/src/v4/locales/el.ts
CHANGED
package/src/v4/locales/en.ts
CHANGED
package/src/v4/locales/eo.ts
CHANGED
package/src/v4/locales/es.ts
CHANGED
package/src/v4/locales/fa.ts
CHANGED
package/src/v4/locales/fi.ts
CHANGED