zod 4.2.0-canary.20251118T062010 → 4.2.0-canary.20251118T063547
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/package.json
CHANGED
|
@@ -786,6 +786,37 @@ test("isPlainObject", () => {
|
|
|
786
786
|
expect(z.core.util.isPlainObject("string")).toEqual(false);
|
|
787
787
|
expect(z.core.util.isPlainObject(123)).toEqual(false);
|
|
788
788
|
expect(z.core.util.isPlainObject(Symbol())).toEqual(false);
|
|
789
|
+
expect(z.core.util.isPlainObject({ constructor: "string" })).toEqual(true);
|
|
790
|
+
expect(z.core.util.isPlainObject({ constructor: 123 })).toEqual(true);
|
|
791
|
+
expect(z.core.util.isPlainObject({ constructor: null })).toEqual(true);
|
|
792
|
+
expect(z.core.util.isPlainObject({ constructor: undefined })).toEqual(true);
|
|
793
|
+
expect(z.core.util.isPlainObject({ constructor: true })).toEqual(true);
|
|
794
|
+
expect(z.core.util.isPlainObject({ constructor: {} })).toEqual(true);
|
|
795
|
+
expect(z.core.util.isPlainObject({ constructor: [] })).toEqual(true);
|
|
796
|
+
});
|
|
797
|
+
|
|
798
|
+
test("shallowClone with constructor field", () => {
|
|
799
|
+
const objWithConstructor = { constructor: "string", key: "value" };
|
|
800
|
+
const cloned = z.core.util.shallowClone(objWithConstructor);
|
|
801
|
+
|
|
802
|
+
expect(cloned).toEqual(objWithConstructor);
|
|
803
|
+
expect(cloned).not.toBe(objWithConstructor);
|
|
804
|
+
expect(cloned.constructor).toBe("string");
|
|
805
|
+
expect(cloned.key).toBe("value");
|
|
806
|
+
|
|
807
|
+
const testCases = [
|
|
808
|
+
{ constructor: 123, data: "test" },
|
|
809
|
+
{ constructor: null, data: "test" },
|
|
810
|
+
{ constructor: true, data: "test" },
|
|
811
|
+
{ constructor: {}, data: "test" },
|
|
812
|
+
{ constructor: [], data: "test" },
|
|
813
|
+
];
|
|
814
|
+
|
|
815
|
+
for (const testCase of testCases) {
|
|
816
|
+
const clonedCase = z.core.util.shallowClone(testCase);
|
|
817
|
+
expect(clonedCase).toEqual(testCase);
|
|
818
|
+
expect(clonedCase).not.toBe(testCase);
|
|
819
|
+
}
|
|
789
820
|
});
|
|
790
821
|
|
|
791
822
|
test("def typing", () => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { test } from "vitest";
|
|
1
|
+
import { expect, test } from "vitest";
|
|
2
2
|
import * as z from "zod/v4";
|
|
3
3
|
|
|
4
4
|
test("extend chaining preserves and overrides properties", () => {
|
|
@@ -16,3 +16,44 @@ test("extend chaining preserves and overrides properties", () => {
|
|
|
16
16
|
|
|
17
17
|
schema3.parse({ email: "test@example.com" });
|
|
18
18
|
});
|
|
19
|
+
|
|
20
|
+
test("extend with constructor field in shape", () => {
|
|
21
|
+
const baseSchema = z.object({
|
|
22
|
+
name: z.string(),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const extendedSchema = baseSchema.extend({
|
|
26
|
+
constructor: z.string(),
|
|
27
|
+
age: z.number(),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const result = extendedSchema.parse({
|
|
31
|
+
name: "John",
|
|
32
|
+
constructor: "Person",
|
|
33
|
+
age: 30,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
expect(result).toEqual({
|
|
37
|
+
name: "John",
|
|
38
|
+
constructor: "Person",
|
|
39
|
+
age: 30,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const testCases = [
|
|
43
|
+
{ name: "Test", constructor: 123, age: 25 },
|
|
44
|
+
{ name: "Test", constructor: null, age: 25 },
|
|
45
|
+
{ name: "Test", constructor: true, age: 25 },
|
|
46
|
+
{ name: "Test", constructor: {}, age: 25 },
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
for (const testCase of testCases) {
|
|
50
|
+
const anyConstructorSchema = baseSchema.extend({
|
|
51
|
+
constructor: z.any(),
|
|
52
|
+
age: z.number(),
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
expect(() => anyConstructorSchema.parse(testCase)).not.toThrow();
|
|
56
|
+
const parsed = anyConstructorSchema.parse(testCase);
|
|
57
|
+
expect(parsed).toEqual(testCase);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { expect, test } from "vitest";
|
|
2
|
+
import * as z from "zod/v4";
|
|
3
|
+
|
|
4
|
+
test("record should parse objects with non-function constructor field", () => {
|
|
5
|
+
const schema = z.record(z.string(), z.any());
|
|
6
|
+
|
|
7
|
+
expect(() => schema.parse({ constructor: "string", key: "value" })).not.toThrow();
|
|
8
|
+
|
|
9
|
+
const result1 = schema.parse({ constructor: "string", key: "value" });
|
|
10
|
+
expect(result1).toEqual({ constructor: "string", key: "value" });
|
|
11
|
+
|
|
12
|
+
expect(() => schema.parse({ constructor: 123, key: "value" })).not.toThrow();
|
|
13
|
+
|
|
14
|
+
const result2 = schema.parse({ constructor: 123, key: "value" });
|
|
15
|
+
expect(result2).toEqual({ constructor: 123, key: "value" });
|
|
16
|
+
|
|
17
|
+
expect(() => schema.parse({ constructor: null, key: "value" })).not.toThrow();
|
|
18
|
+
|
|
19
|
+
const result3 = schema.parse({ constructor: null, key: "value" });
|
|
20
|
+
expect(result3).toEqual({ constructor: null, key: "value" });
|
|
21
|
+
|
|
22
|
+
expect(() => schema.parse({ constructor: {}, key: "value" })).not.toThrow();
|
|
23
|
+
|
|
24
|
+
const result4 = schema.parse({ constructor: {}, key: "value" });
|
|
25
|
+
expect(result4).toEqual({ constructor: {}, key: "value" });
|
|
26
|
+
|
|
27
|
+
expect(() => schema.parse({ constructor: [], key: "value" })).not.toThrow();
|
|
28
|
+
|
|
29
|
+
const result5 = schema.parse({ constructor: [], key: "value" });
|
|
30
|
+
expect(result5).toEqual({ constructor: [], key: "value" });
|
|
31
|
+
|
|
32
|
+
expect(() => schema.parse({ constructor: true, key: "value" })).not.toThrow();
|
|
33
|
+
|
|
34
|
+
const result6 = schema.parse({ constructor: true, key: "value" });
|
|
35
|
+
expect(result6).toEqual({ constructor: true, key: "value" });
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test("record should still work with normal objects", () => {
|
|
39
|
+
const schema = z.record(z.string(), z.string());
|
|
40
|
+
|
|
41
|
+
expect(() => schema.parse({ normalKey: "value" })).not.toThrow();
|
|
42
|
+
|
|
43
|
+
const result1 = schema.parse({ normalKey: "value" });
|
|
44
|
+
expect(result1).toEqual({ normalKey: "value" });
|
|
45
|
+
|
|
46
|
+
expect(() => schema.parse({ key1: "value1", key2: "value2" })).not.toThrow();
|
|
47
|
+
|
|
48
|
+
const result2 = schema.parse({ key1: "value1", key2: "value2" });
|
|
49
|
+
expect(result2).toEqual({ key1: "value1", key2: "value2" });
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("record should validate values according to schema even with constructor field", () => {
|
|
53
|
+
const stringSchema = z.record(z.string(), z.string());
|
|
54
|
+
|
|
55
|
+
expect(() => stringSchema.parse({ constructor: "string", key: "value" })).not.toThrow();
|
|
56
|
+
|
|
57
|
+
expect(() => stringSchema.parse({ constructor: 123, key: "value" })).toThrow();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("record should work with different key types and constructor field", () => {
|
|
61
|
+
const enumSchema = z.record(z.enum(["constructor", "key"]), z.string());
|
|
62
|
+
|
|
63
|
+
expect(() => enumSchema.parse({ constructor: "value1", key: "value2" })).not.toThrow();
|
|
64
|
+
|
|
65
|
+
const result = enumSchema.parse({ constructor: "value1", key: "value2" });
|
|
66
|
+
expect(result).toEqual({ constructor: "value1", key: "value2" });
|
|
67
|
+
});
|
package/src/v4/core/util.ts
CHANGED
|
@@ -381,6 +381,8 @@ export function isPlainObject(o: any): o is Record<PropertyKey, unknown> {
|
|
|
381
381
|
const ctor = o.constructor;
|
|
382
382
|
if (ctor === undefined) return true;
|
|
383
383
|
|
|
384
|
+
if (typeof ctor !== "function") return true;
|
|
385
|
+
|
|
384
386
|
// modified prototype
|
|
385
387
|
const prot = ctor.prototype;
|
|
386
388
|
if (isObject(prot) === false) return false;
|
package/v4/core/util.cjs
CHANGED
package/v4/core/util.js
CHANGED
|
@@ -160,6 +160,8 @@ export function isPlainObject(o) {
|
|
|
160
160
|
const ctor = o.constructor;
|
|
161
161
|
if (ctor === undefined)
|
|
162
162
|
return true;
|
|
163
|
+
if (typeof ctor !== "function")
|
|
164
|
+
return true;
|
|
163
165
|
// modified prototype
|
|
164
166
|
const prot = ctor.prototype;
|
|
165
167
|
if (isObject(prot) === false)
|