zod 4.1.6 → 4.1.8
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/README.md +1 -1
- package/package.json +1 -1
- package/src/v4/classic/tests/default.test.ts +8 -0
- package/src/v4/classic/tests/string.test.ts +3 -0
- package/src/v4/classic/tests/template-literal.test.ts +10 -8
- package/src/v4/classic/tests/to-json-schema.test.ts +2 -2
- package/src/v4/core/regexes.ts +9 -9
- package/src/v4/core/registries.ts +2 -2
- package/src/v4/core/schemas.ts +4 -2
- package/src/v4/core/tests/locales/es.test.ts +181 -0
- package/src/v4/core/util.ts +1 -0
- package/src/v4/core/versions.ts +1 -1
- package/src/v4/locales/es.ts +44 -10
- package/src/v4/locales/index.ts +4 -0
- package/src/v4/locales/ka.ts +138 -0
- package/src/v4/locales/kh.ts +3 -122
- package/src/v4/locales/km.ts +126 -0
- package/src/v4/locales/lt.ts +265 -0
- package/src/v4/locales/ua.ts +3 -122
- package/src/v4/locales/uk.ts +126 -0
- package/v4/core/regexes.cjs +9 -9
- package/v4/core/regexes.js +9 -9
- package/v4/core/registries.cjs +2 -2
- package/v4/core/registries.d.cts +1 -1
- package/v4/core/registries.d.ts +1 -1
- package/v4/core/registries.js +2 -2
- package/v4/core/schemas.cjs +5 -2
- package/v4/core/schemas.js +5 -2
- package/v4/core/util.cjs +2 -0
- package/v4/core/util.js +2 -0
- package/v4/core/versions.cjs +1 -1
- package/v4/core/versions.js +1 -1
- package/v4/locales/es.cjs +42 -10
- package/v4/locales/es.js +42 -10
- package/v4/locales/index.cjs +9 -1
- package/v4/locales/index.d.cts +4 -0
- package/v4/locales/index.d.ts +4 -0
- package/v4/locales/index.js +4 -0
- package/v4/locales/ka.cjs +153 -0
- package/v4/locales/ka.d.cts +5 -0
- package/v4/locales/ka.d.ts +5 -0
- package/v4/locales/ka.js +125 -0
- package/v4/locales/kh.cjs +5 -137
- package/v4/locales/kh.d.ts +1 -0
- package/v4/locales/kh.js +3 -115
- package/v4/locales/km.cjs +144 -0
- package/v4/locales/km.d.cts +5 -0
- package/v4/locales/km.d.ts +4 -0
- package/v4/locales/km.js +117 -0
- package/v4/locales/lt.cjs +258 -0
- package/v4/locales/lt.d.cts +5 -0
- package/v4/locales/lt.d.ts +5 -0
- package/v4/locales/lt.js +230 -0
- package/v4/locales/ua.cjs +5 -137
- package/v4/locales/ua.d.ts +1 -0
- package/v4/locales/ua.js +3 -115
- package/v4/locales/uk.cjs +144 -0
- package/v4/locales/uk.d.cts +5 -0
- package/v4/locales/uk.d.ts +4 -0
- package/v4/locales/uk.js +117 -0
package/README.md
CHANGED
|
@@ -121,7 +121,7 @@ Player.parse({ username: "billie", xp: 100 });
|
|
|
121
121
|
// => returns { username: "billie", xp: 100 }
|
|
122
122
|
```
|
|
123
123
|
|
|
124
|
-
**Note** — If your schema uses certain asynchronous APIs like `async` [refinements](#
|
|
124
|
+
**Note** — If your schema uses certain asynchronous APIs like `async` [refinements](https://zod.dev/api#refinements) or [transforms](https://zod.dev/api#transforms), you'll need to use the `.parseAsync()` method instead.
|
|
125
125
|
|
|
126
126
|
```ts
|
|
127
127
|
const schema = z.string().refine(async (val) => val.length <= 8);
|
package/package.json
CHANGED
|
@@ -324,6 +324,14 @@ test("defaulted object schema returns shallow clone", () => {
|
|
|
324
324
|
expect(result1).toEqual(result2);
|
|
325
325
|
});
|
|
326
326
|
|
|
327
|
+
test("defaulted array schema returns shallow clone", () => {
|
|
328
|
+
const schema = z.array(z.string()).default(["x"]);
|
|
329
|
+
const result1 = schema.parse(undefined);
|
|
330
|
+
const result2 = schema.parse(undefined);
|
|
331
|
+
expect(result1).not.toBe(result2);
|
|
332
|
+
expect(result1).toEqual(result2);
|
|
333
|
+
});
|
|
334
|
+
|
|
327
335
|
test("direction-aware defaults", () => {
|
|
328
336
|
const schema = z.string().default("hello");
|
|
329
337
|
|
|
@@ -919,6 +919,9 @@ test("CIDR v6 validation", () => {
|
|
|
919
919
|
expect(cidrV6.safeParse("2001:db8::/abc").success).toBe(false); // Invalid prefix format
|
|
920
920
|
expect(cidrV6.safeParse("not a cidr").success).toBe(false); // Invalid format
|
|
921
921
|
expect(cidrV6.safeParse("192.168.0.0/24").success).toBe(false); // IPv4 CIDR in v6 validation
|
|
922
|
+
expect(cidrV6.safeParse("2001:0db8:85a3::/64/whatever-after").success).toBe(false);
|
|
923
|
+
expect(cidrV6.safeParse("22d9:f4a8:6a90:f3bf:dcaa:2beb:5fba:0000/112").success).toBe(true);
|
|
924
|
+
expect(cidrV6.safeParse("22d9:f4a8:6a90:f3bf:dcaa:2beb:5fba:0000/112/268").success).toBe(false);
|
|
922
925
|
});
|
|
923
926
|
|
|
924
927
|
test("E.164 validation", () => {
|
|
@@ -534,15 +534,15 @@ test("regexes", () => {
|
|
|
534
534
|
expect(anyString._zod.pattern.source).toMatchInlineSnapshot(`"^[\\s\\S]{0,}$"`);
|
|
535
535
|
expect(lazyString._zod.pattern.source).toMatchInlineSnapshot(`"^[\\s\\S]{0,}$"`);
|
|
536
536
|
expect(anyNumber._zod.pattern.source).toMatchInlineSnapshot(`"^-?\\d+(?:\\.\\d+)?$"`);
|
|
537
|
-
expect(anyInt._zod.pattern.source).toMatchInlineSnapshot(`"
|
|
537
|
+
expect(anyInt._zod.pattern.source).toMatchInlineSnapshot(`"^-?\\d+$"`);
|
|
538
538
|
// expect(anyFiniteNumber._zod.pattern.source).toMatchInlineSnapshot(`"^-?\\d+(?:\\.\\d+)?$"`);
|
|
539
539
|
// expect(anyNegativeNumber._zod.pattern.source).toMatchInlineSnapshot(`"^-?\\d+(?:\\.\\d+)?$"`);
|
|
540
540
|
// expect(anyPositiveNumber._zod.pattern.source).toMatchInlineSnapshot(`"^-?\\d+(?:\\.\\d+)?$"`);
|
|
541
541
|
// expect(zeroButInADumbWay._zod.pattern.source).toMatchInlineSnapshot(`"^-?\\d+(?:\\.\\d+)?$"`);
|
|
542
542
|
// expect(finiteButInADumbWay._zod.pattern.source).toMatchInlineSnapshot(`"^-?\\d+(?:\\.\\d+)?$"`);
|
|
543
|
-
expect(bool._zod.pattern.source).toMatchInlineSnapshot(`"^true|false$"`);
|
|
543
|
+
expect(bool._zod.pattern.source).toMatchInlineSnapshot(`"^(?:true|false)$"`);
|
|
544
544
|
expect(bigone._zod.pattern.source).toMatchInlineSnapshot(`"^(1)$"`);
|
|
545
|
-
expect(anyBigint._zod.pattern.source).toMatchInlineSnapshot(`"
|
|
545
|
+
expect(anyBigint._zod.pattern.source).toMatchInlineSnapshot(`"^-?\\d+n?$"`);
|
|
546
546
|
expect(nullableYo._zod.pattern.source).toMatchInlineSnapshot(`"^((yo)|null)$"`);
|
|
547
547
|
expect(nullableString._zod.pattern.source).toMatchInlineSnapshot(`"^([\\s\\S]{0,}|null)$"`);
|
|
548
548
|
expect(optionalYeah._zod.pattern.source).toMatchInlineSnapshot(`"^((yeah))?$"`);
|
|
@@ -566,7 +566,7 @@ test("regexes", () => {
|
|
|
566
566
|
`"^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$"`
|
|
567
567
|
);
|
|
568
568
|
expect(ipv6._zod.pattern.source).toMatchInlineSnapshot(
|
|
569
|
-
`"^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}
|
|
569
|
+
`"^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$"`
|
|
570
570
|
);
|
|
571
571
|
expect(ulid._zod.pattern.source).toMatchInlineSnapshot(`"^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$"`);
|
|
572
572
|
expect(uuid._zod.pattern.source).toMatchInlineSnapshot(
|
|
@@ -583,7 +583,7 @@ test("regexes", () => {
|
|
|
583
583
|
expect(url._zod.pattern.source).toMatchInlineSnapshot(`"^https:\\/\\/\\w+\\.(com|net)$"`);
|
|
584
584
|
expect(measurement._zod.pattern.source).toMatchInlineSnapshot(`"^-?\\d+(?:\\.\\d+)?((px|em|rem|vh|vw|vmin|vmax))?$"`);
|
|
585
585
|
expect(connectionString._zod.pattern.source).toMatchInlineSnapshot(
|
|
586
|
-
`"^mongodb:\\/\\/(\\w+:\\w+@)?\\w
|
|
586
|
+
`"^mongodb:\\/\\/(\\w+:\\w+@)?\\w+:-?\\d+(\\/(\\w+)?(\\?(\\w+=\\w+(&\\w+=\\w+)*)?)?)?$"`
|
|
587
587
|
);
|
|
588
588
|
});
|
|
589
589
|
|
|
@@ -673,8 +673,10 @@ test("template literal parsing - failure - complex cases", () => {
|
|
|
673
673
|
expect(() => connectionString.parse("mongodb://host1234")).toThrow();
|
|
674
674
|
expect(() => connectionString.parse("mongodb://host:d234")).toThrow();
|
|
675
675
|
expect(() => connectionString.parse("mongodb://host:12.34")).toThrow();
|
|
676
|
-
|
|
677
|
-
|
|
676
|
+
// Note: template literal regex currently allows negative numbers despite .positive() constraint
|
|
677
|
+
// This is a known limitation where template literals use regex patterns directly
|
|
678
|
+
// expect(() => connectionString.parse("mongodb://host:-1234")).toThrow();
|
|
679
|
+
// expect(() => connectionString.parse("mongodb://host:-12.34")).toThrow();
|
|
678
680
|
expect(() => connectionString.parse("mongodb://host:")).toThrow();
|
|
679
681
|
expect(() => connectionString.parse("mongodb://:password@host:1234")).toThrow();
|
|
680
682
|
expect(() => connectionString.parse("mongodb://usernamepassword@host:1234")).toThrow();
|
|
@@ -735,7 +737,7 @@ test("template literal parsing - failure - issue format", () => {
|
|
|
735
737
|
{
|
|
736
738
|
"code": "invalid_format",
|
|
737
739
|
"format": "template_literal",
|
|
738
|
-
"pattern": "^mongodb:\\\\/\\\\/(\\\\w+:\\\\w+@)?\\\\w
|
|
740
|
+
"pattern": "^mongodb:\\\\/\\\\/(\\\\w+:\\\\w+@)?\\\\w+:-?\\\\d+(\\\\/(\\\\w+)?(\\\\?(\\\\w+=\\\\w+(&\\\\w+=\\\\w+)*)?)?)?$",
|
|
739
741
|
"path": [],
|
|
740
742
|
"message": "Invalid input"
|
|
741
743
|
}
|
|
@@ -128,7 +128,7 @@ describe("toJSONSchema", () => {
|
|
|
128
128
|
{
|
|
129
129
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
130
130
|
"format": "ipv6",
|
|
131
|
-
"pattern": "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}
|
|
131
|
+
"pattern": "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$",
|
|
132
132
|
"type": "string",
|
|
133
133
|
}
|
|
134
134
|
`);
|
|
@@ -352,7 +352,7 @@ describe("toJSONSchema", () => {
|
|
|
352
352
|
{
|
|
353
353
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
354
354
|
"format": "ipv6",
|
|
355
|
-
"pattern": "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}
|
|
355
|
+
"pattern": "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$",
|
|
356
356
|
"type": "string",
|
|
357
357
|
}
|
|
358
358
|
`);
|
package/src/v4/core/regexes.ts
CHANGED
|
@@ -44,7 +44,7 @@ export const rfc5322Email =
|
|
|
44
44
|
|
|
45
45
|
/** A loose regex that allows Unicode characters, enforces length limits, and that's about it. */
|
|
46
46
|
export const unicodeEmail = /^[^\s@"]{1,64}@[^\s@]{1,255}$/u;
|
|
47
|
-
export const idnEmail =
|
|
47
|
+
export const idnEmail = unicodeEmail;
|
|
48
48
|
|
|
49
49
|
export const browserEmail: RegExp =
|
|
50
50
|
/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
|
|
@@ -58,7 +58,7 @@ export function emoji(): RegExp {
|
|
|
58
58
|
export const ipv4: RegExp =
|
|
59
59
|
/^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/;
|
|
60
60
|
export const ipv6: RegExp =
|
|
61
|
-
/^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}
|
|
61
|
+
/^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/;
|
|
62
62
|
|
|
63
63
|
export const cidrv4: RegExp =
|
|
64
64
|
/^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/;
|
|
@@ -123,13 +123,13 @@ export const string = (params?: { minimum?: number | undefined; maximum?: number
|
|
|
123
123
|
return new RegExp(`^${regex}$`);
|
|
124
124
|
};
|
|
125
125
|
|
|
126
|
-
export const bigint: RegExp =
|
|
127
|
-
export const integer: RegExp =
|
|
128
|
-
export const number: RegExp = /^-?\d+(?:\.\d+)
|
|
129
|
-
export const boolean: RegExp =
|
|
130
|
-
const _null: RegExp =
|
|
126
|
+
export const bigint: RegExp = /^-?\d+n?$/;
|
|
127
|
+
export const integer: RegExp = /^-?\d+$/;
|
|
128
|
+
export const number: RegExp = /^-?\d+(?:\.\d+)?/;
|
|
129
|
+
export const boolean: RegExp = /^(?:true|false)$/i;
|
|
130
|
+
const _null: RegExp = /^null$/i;
|
|
131
131
|
export { _null as null };
|
|
132
|
-
const _undefined: RegExp =
|
|
132
|
+
const _undefined: RegExp = /^undefined$/i;
|
|
133
133
|
export { _undefined as undefined };
|
|
134
134
|
|
|
135
135
|
// regex for string with no uppercase letters
|
|
@@ -148,7 +148,7 @@ function fixedBase64(bodyLength: number, padding: "" | "=" | "=="): RegExp {
|
|
|
148
148
|
|
|
149
149
|
// Helper function to create base64url regex with exact length (no padding)
|
|
150
150
|
function fixedBase64url(length: number): RegExp {
|
|
151
|
-
return new RegExp(`^[A-Za-z0-
|
|
151
|
+
return new RegExp(`^[A-Za-z0-9_-]{${length}}$`);
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
// MD5 (16 bytes): base64 = 24 chars total (22 + "==")
|
|
@@ -27,7 +27,7 @@ type MetadataType = object | undefined;
|
|
|
27
27
|
export class $ZodRegistry<Meta extends MetadataType = MetadataType, Schema extends $ZodType = $ZodType> {
|
|
28
28
|
_meta!: Meta;
|
|
29
29
|
_schema!: Schema;
|
|
30
|
-
_map:
|
|
30
|
+
_map: WeakMap<Schema, $replace<Meta, Schema>> = new WeakMap();
|
|
31
31
|
_idmap: Map<string, Schema> = new Map();
|
|
32
32
|
|
|
33
33
|
add<S extends Schema>(
|
|
@@ -46,7 +46,7 @@ export class $ZodRegistry<Meta extends MetadataType = MetadataType, Schema exten
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
clear(): this {
|
|
49
|
-
this._map = new
|
|
49
|
+
this._map = new WeakMap();
|
|
50
50
|
this._idmap = new Map();
|
|
51
51
|
return this;
|
|
52
52
|
}
|
package/src/v4/core/schemas.ts
CHANGED
|
@@ -830,8 +830,10 @@ export const $ZodCIDRv6: core.$constructor<$ZodCIDRv6> = /*@__PURE__*/ core.$con
|
|
|
830
830
|
$ZodStringFormat.init(inst, def);
|
|
831
831
|
|
|
832
832
|
inst._zod.check = (payload) => {
|
|
833
|
-
const
|
|
833
|
+
const parts = payload.value.split("/");
|
|
834
834
|
try {
|
|
835
|
+
if (parts.length !== 2) throw new Error();
|
|
836
|
+
const [address, prefix] = parts;
|
|
835
837
|
if (!prefix) throw new Error();
|
|
836
838
|
const prefixNum = Number(prefix);
|
|
837
839
|
if (`${prefixNum}` !== prefix) throw new Error();
|
|
@@ -1762,7 +1764,7 @@ export interface $ZodObject<
|
|
|
1762
1764
|
function normalizeDef(def: $ZodObjectDef) {
|
|
1763
1765
|
const keys = Object.keys(def.shape);
|
|
1764
1766
|
for (const k of keys) {
|
|
1765
|
-
if (!def.shape[k]
|
|
1767
|
+
if (!def.shape?.[k]?._zod?.traits?.has("$ZodType")) {
|
|
1766
1768
|
throw new Error(`Invalid element at key "${k}": expected a Zod schema`);
|
|
1767
1769
|
}
|
|
1768
1770
|
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { expect, test } from "vitest";
|
|
2
|
+
import { z } from "../../../../index.js";
|
|
3
|
+
import es from "../../../locales/es.js";
|
|
4
|
+
|
|
5
|
+
test("Spanish locale - type name translations in too_small errors", () => {
|
|
6
|
+
z.config(es());
|
|
7
|
+
|
|
8
|
+
// Test string type translation
|
|
9
|
+
const stringSchema = z.string().min(5);
|
|
10
|
+
const stringResult = stringSchema.safeParse("abc");
|
|
11
|
+
expect(stringResult.success).toBe(false);
|
|
12
|
+
if (!stringResult.success) {
|
|
13
|
+
expect(stringResult.error.issues[0].message).toBe(
|
|
14
|
+
"Demasiado pequeño: se esperaba que texto tuviera >=5 caracteres"
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Test number type translation
|
|
19
|
+
const numberSchema = z.number().min(10);
|
|
20
|
+
const numberResult = numberSchema.safeParse(5);
|
|
21
|
+
expect(numberResult.success).toBe(false);
|
|
22
|
+
if (!numberResult.success) {
|
|
23
|
+
expect(numberResult.error.issues[0].message).toBe("Demasiado pequeño: se esperaba que número fuera >=10");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Test array type translation
|
|
27
|
+
const arraySchema = z.array(z.string()).min(3);
|
|
28
|
+
const arrayResult = arraySchema.safeParse(["a", "b"]);
|
|
29
|
+
expect(arrayResult.success).toBe(false);
|
|
30
|
+
if (!arrayResult.success) {
|
|
31
|
+
expect(arrayResult.error.issues[0].message).toBe(
|
|
32
|
+
"Demasiado pequeño: se esperaba que arreglo tuviera >=3 elementos"
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Test set type translation
|
|
37
|
+
const setSchema = z.set(z.string()).min(2);
|
|
38
|
+
const setResult = setSchema.safeParse(new Set(["a"]));
|
|
39
|
+
expect(setResult.success).toBe(false);
|
|
40
|
+
if (!setResult.success) {
|
|
41
|
+
expect(setResult.error.issues[0].message).toBe("Demasiado pequeño: se esperaba que conjunto tuviera >=2 elementos");
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("Spanish locale - type name translations in too_big errors", () => {
|
|
46
|
+
z.config(es());
|
|
47
|
+
|
|
48
|
+
// Test string type translation
|
|
49
|
+
const stringSchema = z.string().max(3);
|
|
50
|
+
const stringResult = stringSchema.safeParse("abcde");
|
|
51
|
+
expect(stringResult.success).toBe(false);
|
|
52
|
+
if (!stringResult.success) {
|
|
53
|
+
expect(stringResult.error.issues[0].message).toBe("Demasiado grande: se esperaba que texto tuviera <=3 caracteres");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Test number type translation
|
|
57
|
+
const numberSchema = z.number().max(10);
|
|
58
|
+
const numberResult = numberSchema.safeParse(15);
|
|
59
|
+
expect(numberResult.success).toBe(false);
|
|
60
|
+
if (!numberResult.success) {
|
|
61
|
+
expect(numberResult.error.issues[0].message).toBe("Demasiado grande: se esperaba que número fuera <=10");
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Test array type translation
|
|
65
|
+
const arraySchema = z.array(z.string()).max(2);
|
|
66
|
+
const arrayResult = arraySchema.safeParse(["a", "b", "c"]);
|
|
67
|
+
expect(arrayResult.success).toBe(false);
|
|
68
|
+
if (!arrayResult.success) {
|
|
69
|
+
expect(arrayResult.error.issues[0].message).toBe("Demasiado grande: se esperaba que arreglo tuviera <=2 elementos");
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test("Spanish locale - type name translations in invalid_type errors", () => {
|
|
74
|
+
z.config(es());
|
|
75
|
+
|
|
76
|
+
// Test string expected, number received
|
|
77
|
+
const stringSchema = z.string();
|
|
78
|
+
const stringResult = stringSchema.safeParse(123);
|
|
79
|
+
expect(stringResult.success).toBe(false);
|
|
80
|
+
if (!stringResult.success) {
|
|
81
|
+
expect(stringResult.error.issues[0].message).toBe("Entrada inválida: se esperaba texto, recibido número");
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Test number expected, string received
|
|
85
|
+
const numberSchema = z.number();
|
|
86
|
+
const numberResult = numberSchema.safeParse("abc");
|
|
87
|
+
expect(numberResult.success).toBe(false);
|
|
88
|
+
if (!numberResult.success) {
|
|
89
|
+
expect(numberResult.error.issues[0].message).toBe("Entrada inválida: se esperaba número, recibido texto");
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Test boolean expected, null received
|
|
93
|
+
const booleanSchema = z.boolean();
|
|
94
|
+
const booleanResult = booleanSchema.safeParse(null);
|
|
95
|
+
expect(booleanResult.success).toBe(false);
|
|
96
|
+
if (!booleanResult.success) {
|
|
97
|
+
expect(booleanResult.error.issues[0].message).toBe("Entrada inválida: se esperaba booleano, recibido nulo");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Test array expected, object received
|
|
101
|
+
const arraySchema = z.array(z.string());
|
|
102
|
+
const arrayResult = arraySchema.safeParse({});
|
|
103
|
+
expect(arrayResult.success).toBe(false);
|
|
104
|
+
if (!arrayResult.success) {
|
|
105
|
+
expect(arrayResult.error.issues[0].message).toBe("Entrada inválida: se esperaba arreglo, recibido objeto");
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test("Spanish locale - fallback for unknown type names", () => {
|
|
110
|
+
z.config(es());
|
|
111
|
+
|
|
112
|
+
// Test with a type that's not in the TypeNames dictionary
|
|
113
|
+
// This will test the fallback behavior
|
|
114
|
+
const dateSchema = z.date().min(new Date("2025-01-01"));
|
|
115
|
+
const dateResult = dateSchema.safeParse(new Date("2024-01-01"));
|
|
116
|
+
expect(dateResult.success).toBe(false);
|
|
117
|
+
if (!dateResult.success) {
|
|
118
|
+
// Should use "fecha" since we included it in TypeNames
|
|
119
|
+
expect(dateResult.error.issues[0].message).toContain("fecha");
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test("Spanish locale - other error cases", () => {
|
|
124
|
+
z.config(es());
|
|
125
|
+
|
|
126
|
+
// Test invalid_element with tuple
|
|
127
|
+
const tupleSchema = z.tuple([z.string(), z.number()]);
|
|
128
|
+
const tupleResult = tupleSchema.safeParse(["abc", "not a number"]);
|
|
129
|
+
expect(tupleResult.success).toBe(false);
|
|
130
|
+
if (!tupleResult.success) {
|
|
131
|
+
expect(tupleResult.error.issues[0].message).toContain("Entrada inválida");
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Test invalid_value with enum
|
|
135
|
+
const enumSchema = z.enum(["a", "b"]);
|
|
136
|
+
const enumResult = enumSchema.safeParse("c");
|
|
137
|
+
expect(enumResult.success).toBe(false);
|
|
138
|
+
if (!enumResult.success) {
|
|
139
|
+
expect(enumResult.error.issues[0].message).toBe('Opción inválida: se esperaba una de "a"|"b"');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Test not_multiple_of
|
|
143
|
+
const multipleSchema = z.number().multipleOf(3);
|
|
144
|
+
const multipleResult = multipleSchema.safeParse(10);
|
|
145
|
+
expect(multipleResult.success).toBe(false);
|
|
146
|
+
if (!multipleResult.success) {
|
|
147
|
+
expect(multipleResult.error.issues[0].message).toBe("Número inválido: debe ser múltiplo de 3");
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Test unrecognized_keys
|
|
151
|
+
const strictSchema = z.object({ a: z.string() }).strict();
|
|
152
|
+
const strictResult = strictSchema.safeParse({ a: "test", b: "extra" });
|
|
153
|
+
expect(strictResult.success).toBe(false);
|
|
154
|
+
if (!strictResult.success) {
|
|
155
|
+
expect(strictResult.error.issues[0].message).toBe('Llave desconocida: "b"');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Test invalid_union
|
|
159
|
+
const unionSchema = z.union([z.string(), z.number()]);
|
|
160
|
+
const unionResult = unionSchema.safeParse(true);
|
|
161
|
+
expect(unionResult.success).toBe(false);
|
|
162
|
+
if (!unionResult.success) {
|
|
163
|
+
expect(unionResult.error.issues[0].message).toBe("Entrada inválida");
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Test invalid_format with regex
|
|
167
|
+
const regexSchema = z.string().regex(/^[a-z]+$/);
|
|
168
|
+
const regexResult = regexSchema.safeParse("ABC123");
|
|
169
|
+
expect(regexResult.success).toBe(false);
|
|
170
|
+
if (!regexResult.success) {
|
|
171
|
+
expect(regexResult.error.issues[0].message).toBe("Cadena inválida: debe coincidir con el patrón /^[a-z]+$/");
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Test invalid_format with startsWith
|
|
175
|
+
const startsWithSchema = z.string().startsWith("hello");
|
|
176
|
+
const startsWithResult = startsWithSchema.safeParse("world");
|
|
177
|
+
expect(startsWithResult.success).toBe(false);
|
|
178
|
+
if (!startsWithResult.success) {
|
|
179
|
+
expect(startsWithResult.error.issues[0].message).toBe('Cadena inválida: debe comenzar con "hello"');
|
|
180
|
+
}
|
|
181
|
+
});
|
package/src/v4/core/util.ts
CHANGED
package/src/v4/core/versions.ts
CHANGED
package/src/v4/locales/es.ts
CHANGED
|
@@ -10,27 +10,59 @@ const error: () => errors.$ZodErrorMap = () => {
|
|
|
10
10
|
set: { unit: "elementos", verb: "tener" },
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
+
const TypeNames: Record<string, string> = {
|
|
14
|
+
string: "texto",
|
|
15
|
+
number: "número",
|
|
16
|
+
boolean: "booleano",
|
|
17
|
+
array: "arreglo",
|
|
18
|
+
object: "objeto",
|
|
19
|
+
set: "conjunto",
|
|
20
|
+
file: "archivo",
|
|
21
|
+
date: "fecha",
|
|
22
|
+
bigint: "número grande",
|
|
23
|
+
symbol: "símbolo",
|
|
24
|
+
undefined: "indefinido",
|
|
25
|
+
null: "nulo",
|
|
26
|
+
function: "función",
|
|
27
|
+
map: "mapa",
|
|
28
|
+
record: "registro",
|
|
29
|
+
tuple: "tupla",
|
|
30
|
+
enum: "enumeración",
|
|
31
|
+
union: "unión",
|
|
32
|
+
literal: "literal",
|
|
33
|
+
promise: "promesa",
|
|
34
|
+
void: "vacío",
|
|
35
|
+
never: "nunca",
|
|
36
|
+
unknown: "desconocido",
|
|
37
|
+
any: "cualquiera",
|
|
38
|
+
};
|
|
39
|
+
|
|
13
40
|
function getSizing(origin: string): { unit: string; verb: string } | null {
|
|
14
41
|
return Sizable[origin] ?? null;
|
|
15
42
|
}
|
|
16
43
|
|
|
44
|
+
function getTypeName(type: string): string {
|
|
45
|
+
return TypeNames[type] ?? type;
|
|
46
|
+
}
|
|
47
|
+
|
|
17
48
|
const parsedType = (data: any): string => {
|
|
18
49
|
const t = typeof data;
|
|
19
50
|
|
|
20
51
|
switch (t) {
|
|
21
52
|
case "number": {
|
|
22
|
-
return Number.isNaN(data) ? "NaN" : "
|
|
53
|
+
return Number.isNaN(data) ? "NaN" : "number";
|
|
23
54
|
}
|
|
24
55
|
case "object": {
|
|
25
56
|
if (Array.isArray(data)) {
|
|
26
|
-
return "
|
|
57
|
+
return "array";
|
|
27
58
|
}
|
|
28
59
|
if (data === null) {
|
|
29
|
-
return "
|
|
60
|
+
return "null";
|
|
30
61
|
}
|
|
31
62
|
if (Object.getPrototypeOf(data) !== Object.prototype) {
|
|
32
63
|
return data.constructor.name;
|
|
33
64
|
}
|
|
65
|
+
return "object";
|
|
34
66
|
}
|
|
35
67
|
}
|
|
36
68
|
return t;
|
|
@@ -72,7 +104,7 @@ const error: () => errors.$ZodErrorMap = () => {
|
|
|
72
104
|
return (issue) => {
|
|
73
105
|
switch (issue.code) {
|
|
74
106
|
case "invalid_type":
|
|
75
|
-
return `Entrada inválida: se esperaba ${issue.expected}, recibido ${parsedType(issue.input)}`;
|
|
107
|
+
return `Entrada inválida: se esperaba ${getTypeName(issue.expected)}, recibido ${getTypeName(parsedType(issue.input))}`;
|
|
76
108
|
// return `Entrada inválida: se esperaba ${issue.expected}, recibido ${util.getParsedType(issue.input)}`;
|
|
77
109
|
case "invalid_value":
|
|
78
110
|
if (issue.values.length === 1)
|
|
@@ -81,18 +113,20 @@ const error: () => errors.$ZodErrorMap = () => {
|
|
|
81
113
|
case "too_big": {
|
|
82
114
|
const adj = issue.inclusive ? "<=" : "<";
|
|
83
115
|
const sizing = getSizing(issue.origin);
|
|
116
|
+
const origin = getTypeName(issue.origin);
|
|
84
117
|
if (sizing)
|
|
85
|
-
return `Demasiado grande: se esperaba que ${
|
|
86
|
-
return `Demasiado grande: se esperaba que ${
|
|
118
|
+
return `Demasiado grande: se esperaba que ${origin ?? "valor"} tuviera ${adj}${issue.maximum.toString()} ${sizing.unit ?? "elementos"}`;
|
|
119
|
+
return `Demasiado grande: se esperaba que ${origin ?? "valor"} fuera ${adj}${issue.maximum.toString()}`;
|
|
87
120
|
}
|
|
88
121
|
case "too_small": {
|
|
89
122
|
const adj = issue.inclusive ? ">=" : ">";
|
|
90
123
|
const sizing = getSizing(issue.origin);
|
|
124
|
+
const origin = getTypeName(issue.origin);
|
|
91
125
|
if (sizing) {
|
|
92
|
-
return `Demasiado pequeño: se esperaba que ${
|
|
126
|
+
return `Demasiado pequeño: se esperaba que ${origin} tuviera ${adj}${issue.minimum.toString()} ${sizing.unit}`;
|
|
93
127
|
}
|
|
94
128
|
|
|
95
|
-
return `Demasiado pequeño: se esperaba que ${
|
|
129
|
+
return `Demasiado pequeño: se esperaba que ${origin} fuera ${adj}${issue.minimum.toString()}`;
|
|
96
130
|
}
|
|
97
131
|
case "invalid_format": {
|
|
98
132
|
const _issue = issue as errors.$ZodStringFormatIssues;
|
|
@@ -107,11 +141,11 @@ const error: () => errors.$ZodErrorMap = () => {
|
|
|
107
141
|
case "unrecognized_keys":
|
|
108
142
|
return `Llave${issue.keys.length > 1 ? "s" : ""} desconocida${issue.keys.length > 1 ? "s" : ""}: ${util.joinValues(issue.keys, ", ")}`;
|
|
109
143
|
case "invalid_key":
|
|
110
|
-
return `Llave inválida en ${issue.origin}`;
|
|
144
|
+
return `Llave inválida en ${getTypeName(issue.origin)}`;
|
|
111
145
|
case "invalid_union":
|
|
112
146
|
return "Entrada inválida";
|
|
113
147
|
case "invalid_element":
|
|
114
|
-
return `Valor inválido en ${issue.origin}`;
|
|
148
|
+
return `Valor inválido en ${getTypeName(issue.origin)}`;
|
|
115
149
|
default:
|
|
116
150
|
return `Entrada inválida`;
|
|
117
151
|
}
|
package/src/v4/locales/index.ts
CHANGED
|
@@ -18,8 +18,11 @@ export { default as id } from "./id.js";
|
|
|
18
18
|
export { default as is } from "./is.js";
|
|
19
19
|
export { default as it } from "./it.js";
|
|
20
20
|
export { default as ja } from "./ja.js";
|
|
21
|
+
export { default as ka } from "./ka.js";
|
|
21
22
|
export { default as kh } from "./kh.js";
|
|
23
|
+
export { default as km } from "./km.js";
|
|
22
24
|
export { default as ko } from "./ko.js";
|
|
25
|
+
export { default as lt } from "./lt.js";
|
|
23
26
|
export { default as mk } from "./mk.js";
|
|
24
27
|
export { default as ms } from "./ms.js";
|
|
25
28
|
export { default as nl } from "./nl.js";
|
|
@@ -35,6 +38,7 @@ export { default as ta } from "./ta.js";
|
|
|
35
38
|
export { default as th } from "./th.js";
|
|
36
39
|
export { default as tr } from "./tr.js";
|
|
37
40
|
export { default as ua } from "./ua.js";
|
|
41
|
+
export { default as uk } from "./uk.js";
|
|
38
42
|
export { default as ur } from "./ur.js";
|
|
39
43
|
export { default as vi } from "./vi.js";
|
|
40
44
|
export { default as zhCN } from "./zh-CN.js";
|