@hy_ong/zod-kit 0.0.6 → 0.1.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/.claude/settings.local.json +4 -1
- package/dist/index.cjs +93 -89
- package/dist/index.d.cts +235 -169
- package/dist/index.d.ts +235 -169
- package/dist/index.js +93 -89
- package/package.json +2 -1
- package/src/validators/common/boolean.ts +17 -14
- package/src/validators/common/date.ts +21 -14
- package/src/validators/common/datetime.ts +21 -14
- package/src/validators/common/email.ts +18 -15
- package/src/validators/common/file.ts +20 -13
- package/src/validators/common/id.ts +14 -14
- package/src/validators/common/number.ts +18 -15
- package/src/validators/common/password.ts +21 -14
- package/src/validators/common/text.ts +21 -17
- package/src/validators/common/time.ts +21 -14
- package/src/validators/common/url.ts +22 -15
- package/src/validators/taiwan/business-id.ts +18 -11
- package/src/validators/taiwan/fax.ts +23 -14
- package/src/validators/taiwan/mobile.ts +23 -14
- package/src/validators/taiwan/national-id.ts +11 -12
- package/src/validators/taiwan/postal-code.ts +16 -17
- package/src/validators/taiwan/tel.ts +23 -14
- package/tests/common/boolean.test.ts +38 -38
- package/tests/common/date.test.ts +65 -65
- package/tests/common/datetime.test.ts +100 -118
- package/tests/common/email.test.ts +24 -28
- package/tests/common/file.test.ts +47 -51
- package/tests/common/id.test.ts +80 -113
- package/tests/common/number.test.ts +24 -25
- package/tests/common/password.test.ts +28 -35
- package/tests/common/text.test.ts +36 -37
- package/tests/common/time.test.ts +64 -82
- package/tests/common/url.test.ts +67 -67
- package/tests/taiwan/business-id.test.ts +22 -22
- package/tests/taiwan/fax.test.ts +33 -42
- package/tests/taiwan/mobile.test.ts +32 -41
- package/tests/taiwan/national-id.test.ts +31 -31
- package/tests/taiwan/postal-code.test.ts +142 -96
- package/tests/taiwan/tel.test.ts +33 -42
- package/debug.js +0 -21
- package/debug.ts +0 -16
|
@@ -1,31 +1,31 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach } from "vitest"
|
|
2
2
|
import { email, setLocale } from "../../src"
|
|
3
3
|
|
|
4
|
-
describe("email() features", () => {
|
|
4
|
+
describe("email(true) features", () => {
|
|
5
5
|
beforeEach(() => setLocale("en"))
|
|
6
6
|
|
|
7
7
|
describe("multiple domain support", () => {
|
|
8
8
|
it("should accept multiple allowed domains", () => {
|
|
9
|
-
const schema = email({ domain: ["example.com", "company.org"] })
|
|
9
|
+
const schema = email(true, { domain: ["example.com", "company.org"] })
|
|
10
10
|
expect(schema.parse("test@example.com")).toBe("test@example.com")
|
|
11
11
|
expect(schema.parse("user@company.org")).toBe("user@company.org")
|
|
12
12
|
})
|
|
13
13
|
|
|
14
14
|
it("should reject domains not in whitelist", () => {
|
|
15
|
-
const schema = email({ domain: ["example.com", "company.org"] })
|
|
15
|
+
const schema = email(true, { domain: ["example.com", "company.org"] })
|
|
16
16
|
expect(() => schema.parse("test@notallowed.com")).toThrow("Must be from domain: example.com, company.org")
|
|
17
17
|
})
|
|
18
18
|
})
|
|
19
19
|
|
|
20
20
|
describe("subdomain support", () => {
|
|
21
21
|
it("should allow subdomains by default", () => {
|
|
22
|
-
const schema = email({ domain: "example.com" })
|
|
22
|
+
const schema = email(true, { domain: "example.com" })
|
|
23
23
|
expect(schema.parse("test@mail.example.com")).toBe("test@mail.example.com")
|
|
24
24
|
expect(schema.parse("user@api.example.com")).toBe("user@api.example.com")
|
|
25
25
|
})
|
|
26
26
|
|
|
27
27
|
it("should reject subdomains when allowSubdomains=false", () => {
|
|
28
|
-
const schema = email({ domain: "example.com", allowSubdomains: false })
|
|
28
|
+
const schema = email(true, { domain: "example.com", allowSubdomains: false })
|
|
29
29
|
expect(schema.parse("test@example.com")).toBe("test@example.com")
|
|
30
30
|
expect(() => schema.parse("test@mail.example.com")).toThrow("Must be from domain: example.com")
|
|
31
31
|
})
|
|
@@ -33,21 +33,21 @@ describe("email() features", () => {
|
|
|
33
33
|
|
|
34
34
|
describe("domain blacklist", () => {
|
|
35
35
|
it("should reject blacklisted domains", () => {
|
|
36
|
-
const schema = email({ domainBlacklist: ["spam.com", "fake.org"] })
|
|
36
|
+
const schema = email(true, { domainBlacklist: ["spam.com", "fake.org"] })
|
|
37
37
|
expect(schema.parse("test@example.com")).toBe("test@example.com")
|
|
38
38
|
expect(() => schema.parse("test@spam.com")).toThrow("Domain spam.com is not allowed")
|
|
39
39
|
expect(() => schema.parse("user@fake.org")).toThrow("Domain fake.org is not allowed")
|
|
40
40
|
})
|
|
41
41
|
|
|
42
42
|
it("should reject blacklisted subdomains when allowSubdomains=true", () => {
|
|
43
|
-
const schema = email({ domainBlacklist: ["spam.com"], allowSubdomains: true })
|
|
43
|
+
const schema = email(true, { domainBlacklist: ["spam.com"], allowSubdomains: true })
|
|
44
44
|
expect(() => schema.parse("test@mail.spam.com")).toThrow("Domain mail.spam.com is not allowed")
|
|
45
45
|
})
|
|
46
46
|
})
|
|
47
47
|
|
|
48
48
|
describe("business email validation", () => {
|
|
49
49
|
it("should reject free email providers when businessOnly=true", () => {
|
|
50
|
-
const schema = email({ businessOnly: true })
|
|
50
|
+
const schema = email(true, { businessOnly: true })
|
|
51
51
|
expect(schema.parse("john@company.com")).toBe("john@company.com")
|
|
52
52
|
expect(() => schema.parse("john@gmail.com")).toThrow("Only business email addresses are allowed")
|
|
53
53
|
expect(() => schema.parse("jane@yahoo.com")).toThrow("Only business email addresses are allowed")
|
|
@@ -57,7 +57,7 @@ describe("email() features", () => {
|
|
|
57
57
|
|
|
58
58
|
describe("disposable email detection", () => {
|
|
59
59
|
it("should reject disposable email addresses when noDisposable=true", () => {
|
|
60
|
-
const schema = email({ noDisposable: true })
|
|
60
|
+
const schema = email(true, { noDisposable: true })
|
|
61
61
|
expect(schema.parse("john@company.com")).toBe("john@company.com")
|
|
62
62
|
expect(() => schema.parse("test@10minutemail.com")).toThrow("Disposable email addresses are not allowed")
|
|
63
63
|
expect(() => schema.parse("user@tempmail.org")).toThrow("Disposable email addresses are not allowed")
|
|
@@ -67,13 +67,13 @@ describe("email() features", () => {
|
|
|
67
67
|
|
|
68
68
|
describe("case handling", () => {
|
|
69
69
|
it("should convert to lowercase by default", () => {
|
|
70
|
-
const schema = email()
|
|
70
|
+
const schema = email(true)
|
|
71
71
|
expect(schema.parse("Test@EXAMPLE.COM")).toBe("test@example.com")
|
|
72
72
|
expect(schema.parse("USER@Company.Org")).toBe("user@company.org")
|
|
73
73
|
})
|
|
74
74
|
|
|
75
75
|
it("should preserve case when lowercase=false", () => {
|
|
76
|
-
const schema = email({ lowercase: false })
|
|
76
|
+
const schema = email(true, { lowercase: false })
|
|
77
77
|
expect(schema.parse("Test@EXAMPLE.COM")).toBe("Test@EXAMPLE.COM")
|
|
78
78
|
expect(schema.parse("USER@Company.Org")).toBe("USER@Company.Org")
|
|
79
79
|
})
|
|
@@ -81,14 +81,14 @@ describe("email() features", () => {
|
|
|
81
81
|
|
|
82
82
|
describe("excludes functionality", () => {
|
|
83
83
|
it("should reject emails containing excluded strings", () => {
|
|
84
|
-
const schema = email({ excludes: ["test", "demo"] })
|
|
84
|
+
const schema = email(true, { excludes: ["test", "demo"] })
|
|
85
85
|
expect(schema.parse("john@example.com")).toBe("john@example.com")
|
|
86
86
|
expect(() => schema.parse("test@example.com")).toThrow("Must include test")
|
|
87
87
|
expect(() => schema.parse("demo.user@example.com")).toThrow("Must include demo")
|
|
88
88
|
})
|
|
89
89
|
|
|
90
90
|
it("should handle excludes as array", () => {
|
|
91
|
-
const schema = email({ excludes: ["spam", "fake", "test"] })
|
|
91
|
+
const schema = email(true, { excludes: ["spam", "fake", "test"] })
|
|
92
92
|
expect(() => schema.parse("spam@example.com")).toThrow("Must include spam")
|
|
93
93
|
expect(() => schema.parse("fake.user@example.com")).toThrow("Must include fake")
|
|
94
94
|
expect(() => schema.parse("user@test.com")).toThrow("Must include test")
|
|
@@ -97,7 +97,7 @@ describe("email() features", () => {
|
|
|
97
97
|
|
|
98
98
|
describe("transform functionality", () => {
|
|
99
99
|
it("should apply transform function", () => {
|
|
100
|
-
const schema = email({
|
|
100
|
+
const schema = email(true, {
|
|
101
101
|
transform: (val) => val.replace(/test/g, "user"), // Replace test with user
|
|
102
102
|
})
|
|
103
103
|
expect(schema.parse("test@example.com")).toBe("user@example.com")
|
|
@@ -105,7 +105,7 @@ describe("email() features", () => {
|
|
|
105
105
|
})
|
|
106
106
|
|
|
107
107
|
it("should apply transform after lowercase", () => {
|
|
108
|
-
const schema = email({
|
|
108
|
+
const schema = email(true, {
|
|
109
109
|
lowercase: true,
|
|
110
110
|
transform: (val) => val.replace(/\+[^@]*/, ""), // Remove + aliases
|
|
111
111
|
})
|
|
@@ -115,14 +115,14 @@ describe("email() features", () => {
|
|
|
115
115
|
|
|
116
116
|
describe("default value functionality", () => {
|
|
117
117
|
it("should use defaultValue for empty input when required", () => {
|
|
118
|
-
const schema = email({ defaultValue: "default@example.com" })
|
|
118
|
+
const schema = email(true, { defaultValue: "default@example.com" })
|
|
119
119
|
expect(schema.parse("")).toBe("default@example.com")
|
|
120
120
|
expect(schema.parse(null)).toBe("default@example.com")
|
|
121
121
|
expect(schema.parse(undefined)).toBe("default@example.com")
|
|
122
122
|
})
|
|
123
123
|
|
|
124
124
|
it("should use defaultValue for empty input when not required", () => {
|
|
125
|
-
const schema = email(
|
|
125
|
+
const schema = email(false, { defaultValue: "default@example.com" })
|
|
126
126
|
expect(schema.parse("")).toBe("default@example.com")
|
|
127
127
|
expect(schema.parse(null)).toBe("default@example.com")
|
|
128
128
|
expect(schema.parse(undefined)).toBe("default@example.com")
|
|
@@ -131,7 +131,7 @@ describe("email() features", () => {
|
|
|
131
131
|
|
|
132
132
|
describe("custom i18n messages", () => {
|
|
133
133
|
it("should use custom messages when provided", () => {
|
|
134
|
-
const schema = email({
|
|
134
|
+
const schema = email(true, {
|
|
135
135
|
domain: "company.com",
|
|
136
136
|
businessOnly: true,
|
|
137
137
|
i18n: {
|
|
@@ -154,7 +154,7 @@ describe("email() features", () => {
|
|
|
154
154
|
})
|
|
155
155
|
|
|
156
156
|
it("should fallback to default messages when custom not provided", () => {
|
|
157
|
-
const schema = email({
|
|
157
|
+
const schema = email(true, {
|
|
158
158
|
noDisposable: true,
|
|
159
159
|
i18n: {
|
|
160
160
|
en: {
|
|
@@ -172,7 +172,7 @@ describe("email() features", () => {
|
|
|
172
172
|
|
|
173
173
|
it("should use correct locale for custom messages", () => {
|
|
174
174
|
setLocale("en")
|
|
175
|
-
const schemaEn = email({
|
|
175
|
+
const schemaEn = email(true, {
|
|
176
176
|
businessOnly: true,
|
|
177
177
|
i18n: {
|
|
178
178
|
en: {
|
|
@@ -186,7 +186,7 @@ describe("email() features", () => {
|
|
|
186
186
|
expect(() => schemaEn.parse("test@gmail.com")).toThrow("English business message")
|
|
187
187
|
|
|
188
188
|
setLocale("zh-TW")
|
|
189
|
-
const schemaZh = email({
|
|
189
|
+
const schemaZh = email(true, {
|
|
190
190
|
businessOnly: true,
|
|
191
191
|
i18n: {
|
|
192
192
|
en: {
|
|
@@ -203,7 +203,7 @@ describe("email() features", () => {
|
|
|
203
203
|
|
|
204
204
|
describe("complex scenarios", () => {
|
|
205
205
|
it("should work with multiple validations", () => {
|
|
206
|
-
const schema = email({
|
|
206
|
+
const schema = email(true, {
|
|
207
207
|
domain: ["company.com", "business.org"],
|
|
208
208
|
minLength: 10,
|
|
209
209
|
maxLength: 30,
|
|
@@ -222,11 +222,7 @@ describe("email() features", () => {
|
|
|
222
222
|
})
|
|
223
223
|
|
|
224
224
|
it("should handle null values correctly when not required", () => {
|
|
225
|
-
const schema = email({
|
|
226
|
-
required: false,
|
|
227
|
-
domain: "example.com",
|
|
228
|
-
minLength: 10,
|
|
229
|
-
})
|
|
225
|
+
const schema = email(false, { domain: "example.com", minLength: 10 })
|
|
230
226
|
|
|
231
227
|
expect(schema.parse(null)).toBe(null)
|
|
232
228
|
expect(schema.parse("")).toBe(null)
|
|
@@ -235,7 +231,7 @@ describe("email() features", () => {
|
|
|
235
231
|
})
|
|
236
232
|
|
|
237
233
|
it("should work with transform, lowercase, and domain validation together", () => {
|
|
238
|
-
const schema = email({
|
|
234
|
+
const schema = email(true, {
|
|
239
235
|
domain: "company.com",
|
|
240
236
|
lowercase: true,
|
|
241
237
|
transform: (val) => val.replace(/\+[^@]*/, ""), // Remove + aliases
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach } from "vitest"
|
|
2
2
|
import { file, setLocale } from "../../src"
|
|
3
3
|
|
|
4
|
-
describe("file() features", () => {
|
|
4
|
+
describe("file(true) features", () => {
|
|
5
5
|
beforeEach(() => setLocale("en"))
|
|
6
6
|
|
|
7
7
|
// Helper function to create mock files for testing
|
|
@@ -12,11 +12,11 @@ describe("file() features", () => {
|
|
|
12
12
|
const file = new File([blob], name, { type })
|
|
13
13
|
|
|
14
14
|
// Mock the size property since File constructor doesn't always set the exact size
|
|
15
|
-
Object.defineProperty(file,
|
|
15
|
+
Object.defineProperty(file, "size", {
|
|
16
16
|
value: size,
|
|
17
17
|
writable: false,
|
|
18
18
|
enumerable: true,
|
|
19
|
-
configurable: false
|
|
19
|
+
configurable: false,
|
|
20
20
|
})
|
|
21
21
|
|
|
22
22
|
return file
|
|
@@ -24,27 +24,27 @@ describe("file() features", () => {
|
|
|
24
24
|
|
|
25
25
|
describe("basic file validation", () => {
|
|
26
26
|
it("should accept valid File objects", () => {
|
|
27
|
-
const schema = file()
|
|
27
|
+
const schema = file(true)
|
|
28
28
|
const mockFile = createMockFile("test.txt", 1024, "text/plain")
|
|
29
29
|
expect(schema.parse(mockFile)).toBe(mockFile)
|
|
30
30
|
})
|
|
31
31
|
|
|
32
32
|
it("should reject non-File objects", () => {
|
|
33
|
-
const schema = file()
|
|
33
|
+
const schema = file(true)
|
|
34
34
|
expect(() => schema.parse("not a file")).toThrow()
|
|
35
35
|
expect(() => schema.parse(123)).toThrow()
|
|
36
36
|
expect(() => schema.parse({})).toThrow()
|
|
37
37
|
})
|
|
38
38
|
|
|
39
39
|
it("should handle required validation", () => {
|
|
40
|
-
const schema = file()
|
|
40
|
+
const schema = file(true)
|
|
41
41
|
expect(() => schema.parse(null)).toThrow("Required")
|
|
42
42
|
expect(() => schema.parse(undefined)).toThrow("Required")
|
|
43
43
|
expect(() => schema.parse("")).toThrow("Required")
|
|
44
44
|
})
|
|
45
45
|
|
|
46
46
|
it("should allow null when not required", () => {
|
|
47
|
-
const schema = file(
|
|
47
|
+
const schema = file(false)
|
|
48
48
|
expect(schema.parse(null)).toBe(null)
|
|
49
49
|
expect(schema.parse(undefined)).toBe(null)
|
|
50
50
|
expect(schema.parse("")).toBe(null)
|
|
@@ -53,7 +53,7 @@ describe("file() features", () => {
|
|
|
53
53
|
|
|
54
54
|
describe("file size validation", () => {
|
|
55
55
|
it("should validate maximum file size", () => {
|
|
56
|
-
const schema = file({ maxSize: 1024 }) // 1KB
|
|
56
|
+
const schema = file(true, { maxSize: 1024 }) // 1KB
|
|
57
57
|
const smallFile = createMockFile("small.txt", 512, "text/plain")
|
|
58
58
|
const largeFile = createMockFile("large.txt", 2048, "text/plain")
|
|
59
59
|
|
|
@@ -62,7 +62,7 @@ describe("file() features", () => {
|
|
|
62
62
|
})
|
|
63
63
|
|
|
64
64
|
it("should validate minimum file size", () => {
|
|
65
|
-
const schema = file({ minSize: 1024 }) // 1KB
|
|
65
|
+
const schema = file(true, { minSize: 1024 }) // 1KB
|
|
66
66
|
const smallFile = createMockFile("small.txt", 512, "text/plain")
|
|
67
67
|
const largeFile = createMockFile("large.txt", 2048, "text/plain")
|
|
68
68
|
|
|
@@ -71,7 +71,7 @@ describe("file() features", () => {
|
|
|
71
71
|
})
|
|
72
72
|
|
|
73
73
|
it("should validate both min and max size", () => {
|
|
74
|
-
const schema = file({ minSize: 1024, maxSize: 4096 }) // 1KB - 4KB
|
|
74
|
+
const schema = file(true, { minSize: 1024, maxSize: 4096 }) // 1KB - 4KB
|
|
75
75
|
const tooSmall = createMockFile("small.txt", 512, "text/plain")
|
|
76
76
|
const justRight = createMockFile("medium.txt", 2048, "text/plain")
|
|
77
77
|
const tooLarge = createMockFile("large.txt", 8192, "text/plain")
|
|
@@ -84,7 +84,7 @@ describe("file() features", () => {
|
|
|
84
84
|
|
|
85
85
|
describe("file type validation", () => {
|
|
86
86
|
it("should accept allowed MIME types", () => {
|
|
87
|
-
const schema = file({ type: "text/plain" })
|
|
87
|
+
const schema = file(true, { type: "text/plain" })
|
|
88
88
|
const textFile = createMockFile("test.txt", 1024, "text/plain")
|
|
89
89
|
const imageFile = createMockFile("test.jpg", 1024, "image/jpeg")
|
|
90
90
|
|
|
@@ -93,7 +93,7 @@ describe("file() features", () => {
|
|
|
93
93
|
})
|
|
94
94
|
|
|
95
95
|
it("should accept multiple allowed MIME types", () => {
|
|
96
|
-
const schema = file({ type: ["text/plain", "image/jpeg", "application/pdf"] })
|
|
96
|
+
const schema = file(true, { type: ["text/plain", "image/jpeg", "application/pdf"] })
|
|
97
97
|
const textFile = createMockFile("test.txt", 1024, "text/plain")
|
|
98
98
|
const imageFile = createMockFile("test.jpg", 1024, "image/jpeg")
|
|
99
99
|
const pdfFile = createMockFile("test.pdf", 1024, "application/pdf")
|
|
@@ -106,7 +106,7 @@ describe("file() features", () => {
|
|
|
106
106
|
})
|
|
107
107
|
|
|
108
108
|
it("should reject blacklisted MIME types", () => {
|
|
109
|
-
const schema = file({ typeBlacklist: ["application/x-executable", "application/x-virus"] })
|
|
109
|
+
const schema = file(true, { typeBlacklist: ["application/x-executable", "application/x-virus"] })
|
|
110
110
|
const textFile = createMockFile("test.txt", 1024, "text/plain")
|
|
111
111
|
const exeFile = createMockFile("test.exe", 1024, "application/x-executable")
|
|
112
112
|
|
|
@@ -117,7 +117,7 @@ describe("file() features", () => {
|
|
|
117
117
|
|
|
118
118
|
describe("file extension validation", () => {
|
|
119
119
|
it("should validate single file extension", () => {
|
|
120
|
-
const schema = file({ extension: ".txt" })
|
|
120
|
+
const schema = file(true, { extension: ".txt" })
|
|
121
121
|
const txtFile = createMockFile("test.txt", 1024, "text/plain")
|
|
122
122
|
const jpgFile = createMockFile("test.jpg", 1024, "image/jpeg")
|
|
123
123
|
|
|
@@ -126,7 +126,7 @@ describe("file() features", () => {
|
|
|
126
126
|
})
|
|
127
127
|
|
|
128
128
|
it("should validate multiple file extensions", () => {
|
|
129
|
-
const schema = file({ extension: [".txt", ".pdf", ".doc"] })
|
|
129
|
+
const schema = file(true, { extension: [".txt", ".pdf", ".doc"] })
|
|
130
130
|
const txtFile = createMockFile("test.txt", 1024, "text/plain")
|
|
131
131
|
const pdfFile = createMockFile("test.pdf", 1024, "application/pdf")
|
|
132
132
|
const jpgFile = createMockFile("test.jpg", 1024, "image/jpeg")
|
|
@@ -137,7 +137,7 @@ describe("file() features", () => {
|
|
|
137
137
|
})
|
|
138
138
|
|
|
139
139
|
it("should handle extensions without dots", () => {
|
|
140
|
-
const schema = file({ extension: ["txt", "pdf"] })
|
|
140
|
+
const schema = file(true, { extension: ["txt", "pdf"] })
|
|
141
141
|
const txtFile = createMockFile("test.txt", 1024, "text/plain")
|
|
142
142
|
const pdfFile = createMockFile("test.pdf", 1024, "application/pdf")
|
|
143
143
|
|
|
@@ -146,7 +146,7 @@ describe("file() features", () => {
|
|
|
146
146
|
})
|
|
147
147
|
|
|
148
148
|
it("should reject blacklisted extensions", () => {
|
|
149
|
-
const schema = file({ extensionBlacklist: [".exe", ".bat", ".cmd"] })
|
|
149
|
+
const schema = file(true, { extensionBlacklist: [".exe", ".bat", ".cmd"] })
|
|
150
150
|
const txtFile = createMockFile("test.txt", 1024, "text/plain")
|
|
151
151
|
const exeFile = createMockFile("virus.exe", 1024, "application/x-executable")
|
|
152
152
|
|
|
@@ -155,8 +155,8 @@ describe("file() features", () => {
|
|
|
155
155
|
})
|
|
156
156
|
|
|
157
157
|
it("should handle case sensitivity", () => {
|
|
158
|
-
const caseSensitiveSchema = file({ extension: [".txt"], caseSensitive: true })
|
|
159
|
-
const caseInsensitiveSchema = file({ extension: [".txt"], caseSensitive: false })
|
|
158
|
+
const caseSensitiveSchema = file(true, { extension: [".txt"], caseSensitive: true })
|
|
159
|
+
const caseInsensitiveSchema = file(true, { extension: [".txt"], caseSensitive: false })
|
|
160
160
|
const upperCaseFile = createMockFile("test.TXT", 1024, "text/plain")
|
|
161
161
|
|
|
162
162
|
expect(() => caseSensitiveSchema.parse(upperCaseFile)).toThrow("File extension must be one of: .txt")
|
|
@@ -166,7 +166,7 @@ describe("file() features", () => {
|
|
|
166
166
|
|
|
167
167
|
describe("file name validation", () => {
|
|
168
168
|
it("should validate file name patterns", () => {
|
|
169
|
-
const schema = file({ namePattern: /^[a-zA-Z0-9_-]+\.(txt|pdf)$/ })
|
|
169
|
+
const schema = file(true, { namePattern: /^[a-zA-Z0-9_-]+\.(txt|pdf)$/ })
|
|
170
170
|
const validFile = createMockFile("valid_file-123.txt", 1024, "text/plain")
|
|
171
171
|
const invalidFile = createMockFile("invalid file!.txt", 1024, "text/plain")
|
|
172
172
|
|
|
@@ -175,7 +175,7 @@ describe("file() features", () => {
|
|
|
175
175
|
})
|
|
176
176
|
|
|
177
177
|
it("should validate file name patterns with strings", () => {
|
|
178
|
-
const schema = file({ namePattern: "^report_\\d{4}\\.pdf$" })
|
|
178
|
+
const schema = file(true, { namePattern: "^report_\\d{4}\\.pdf$" })
|
|
179
179
|
const validFile = createMockFile("report_2023.pdf", 1024, "application/pdf")
|
|
180
180
|
const invalidFile = createMockFile("report_abc.pdf", 1024, "application/pdf")
|
|
181
181
|
|
|
@@ -184,7 +184,7 @@ describe("file() features", () => {
|
|
|
184
184
|
})
|
|
185
185
|
|
|
186
186
|
it("should reject blacklisted name patterns", () => {
|
|
187
|
-
const schema = file({ nameBlacklist: [/temp/i, /^test/] })
|
|
187
|
+
const schema = file(true, { nameBlacklist: [/temp/i, /^test/] })
|
|
188
188
|
const goodFile = createMockFile("document.pdf", 1024, "application/pdf")
|
|
189
189
|
const tempFile = createMockFile("TempFile.txt", 1024, "text/plain")
|
|
190
190
|
const testFile = createMockFile("test_data.csv", 1024, "text/csv")
|
|
@@ -195,7 +195,7 @@ describe("file() features", () => {
|
|
|
195
195
|
})
|
|
196
196
|
|
|
197
197
|
it("should handle multiple blacklist patterns", () => {
|
|
198
|
-
const schema = file({ nameBlacklist: ["virus", /malware/i, /\.(exe|bat)$/] })
|
|
198
|
+
const schema = file(true, { nameBlacklist: ["virus", /malware/i, /\.(exe|bat)$/] })
|
|
199
199
|
const goodFile = createMockFile("document.pdf", 1024, "application/pdf")
|
|
200
200
|
const virusFile = createMockFile("virus.txt", 1024, "text/plain")
|
|
201
201
|
const malwareFile = createMockFile("MALWARE_test.pdf", 1024, "application/pdf")
|
|
@@ -210,7 +210,7 @@ describe("file() features", () => {
|
|
|
210
210
|
|
|
211
211
|
describe("file category validation", () => {
|
|
212
212
|
it("should validate image files only", () => {
|
|
213
|
-
const schema = file({ imageOnly: true })
|
|
213
|
+
const schema = file(true, { imageOnly: true })
|
|
214
214
|
const imageFile = createMockFile("photo.jpg", 1024, "image/jpeg")
|
|
215
215
|
const textFile = createMockFile("document.txt", 1024, "text/plain")
|
|
216
216
|
|
|
@@ -219,7 +219,7 @@ describe("file() features", () => {
|
|
|
219
219
|
})
|
|
220
220
|
|
|
221
221
|
it("should validate document files only", () => {
|
|
222
|
-
const schema = file({ documentOnly: true })
|
|
222
|
+
const schema = file(true, { documentOnly: true })
|
|
223
223
|
const pdfFile = createMockFile("document.pdf", 1024, "application/pdf")
|
|
224
224
|
const imageFile = createMockFile("photo.jpg", 1024, "image/jpeg")
|
|
225
225
|
|
|
@@ -228,7 +228,7 @@ describe("file() features", () => {
|
|
|
228
228
|
})
|
|
229
229
|
|
|
230
230
|
it("should validate video files only", () => {
|
|
231
|
-
const schema = file({ videoOnly: true })
|
|
231
|
+
const schema = file(true, { videoOnly: true })
|
|
232
232
|
const videoFile = createMockFile("movie.mp4", 1024, "video/mp4")
|
|
233
233
|
const audioFile = createMockFile("song.mp3", 1024, "audio/mpeg")
|
|
234
234
|
|
|
@@ -237,7 +237,7 @@ describe("file() features", () => {
|
|
|
237
237
|
})
|
|
238
238
|
|
|
239
239
|
it("should validate audio files only", () => {
|
|
240
|
-
const schema = file({ audioOnly: true })
|
|
240
|
+
const schema = file(true, { audioOnly: true })
|
|
241
241
|
const audioFile = createMockFile("song.mp3", 1024, "audio/mpeg")
|
|
242
242
|
const videoFile = createMockFile("movie.mp4", 1024, "video/mp4")
|
|
243
243
|
|
|
@@ -246,7 +246,7 @@ describe("file() features", () => {
|
|
|
246
246
|
})
|
|
247
247
|
|
|
248
248
|
it("should validate archive files only", () => {
|
|
249
|
-
const schema = file({ archiveOnly: true })
|
|
249
|
+
const schema = file(true, { archiveOnly: true })
|
|
250
250
|
const zipFile = createMockFile("archive.zip", 1024, "application/zip")
|
|
251
251
|
const textFile = createMockFile("document.txt", 1024, "text/plain")
|
|
252
252
|
|
|
@@ -257,10 +257,10 @@ describe("file() features", () => {
|
|
|
257
257
|
|
|
258
258
|
describe("transform functionality", () => {
|
|
259
259
|
it("should apply transform function", () => {
|
|
260
|
-
const schema = file({
|
|
260
|
+
const schema = file(true, {
|
|
261
261
|
transform: (file) => {
|
|
262
262
|
return new File([file], file.name.toLowerCase(), { type: file.type })
|
|
263
|
-
}
|
|
263
|
+
},
|
|
264
264
|
})
|
|
265
265
|
const originalFile = createMockFile("TEST.TXT", 1024, "text/plain")
|
|
266
266
|
const result = schema.parse(originalFile)
|
|
@@ -273,7 +273,7 @@ describe("file() features", () => {
|
|
|
273
273
|
describe("default value functionality", () => {
|
|
274
274
|
it("should use defaultValue for empty input when required", () => {
|
|
275
275
|
const defaultFile = createMockFile("default.txt", 1024, "text/plain")
|
|
276
|
-
const schema = file({ defaultValue: defaultFile })
|
|
276
|
+
const schema = file(true, { defaultValue: defaultFile })
|
|
277
277
|
|
|
278
278
|
expect(schema.parse("")).toBe(defaultFile)
|
|
279
279
|
expect(schema.parse(null)).toBe(defaultFile)
|
|
@@ -282,7 +282,7 @@ describe("file() features", () => {
|
|
|
282
282
|
|
|
283
283
|
it("should use defaultValue for empty input when not required", () => {
|
|
284
284
|
const defaultFile = createMockFile("default.txt", 1024, "text/plain")
|
|
285
|
-
const schema = file(
|
|
285
|
+
const schema = file(false, { defaultValue: defaultFile })
|
|
286
286
|
|
|
287
287
|
expect(schema.parse("")).toBe(defaultFile)
|
|
288
288
|
expect(schema.parse(null)).toBe(defaultFile)
|
|
@@ -292,7 +292,7 @@ describe("file() features", () => {
|
|
|
292
292
|
|
|
293
293
|
describe("custom i18n messages", () => {
|
|
294
294
|
it("should use custom messages when provided", () => {
|
|
295
|
-
const schema = file({
|
|
295
|
+
const schema = file(true, {
|
|
296
296
|
maxSize: 1024,
|
|
297
297
|
extension: [".pdf"],
|
|
298
298
|
imageOnly: true,
|
|
@@ -323,7 +323,7 @@ describe("file() features", () => {
|
|
|
323
323
|
})
|
|
324
324
|
|
|
325
325
|
it("should fallback to default messages when custom not provided", () => {
|
|
326
|
-
const schema = file({
|
|
326
|
+
const schema = file(true, {
|
|
327
327
|
videoOnly: true,
|
|
328
328
|
i18n: {
|
|
329
329
|
en: {
|
|
@@ -343,7 +343,7 @@ describe("file() features", () => {
|
|
|
343
343
|
|
|
344
344
|
it("should use correct locale for custom messages", () => {
|
|
345
345
|
setLocale("en")
|
|
346
|
-
const schemaEn = file({
|
|
346
|
+
const schemaEn = file(true, {
|
|
347
347
|
imageOnly: true,
|
|
348
348
|
i18n: {
|
|
349
349
|
en: {
|
|
@@ -358,7 +358,7 @@ describe("file() features", () => {
|
|
|
358
358
|
expect(() => schemaEn.parse(nonImageFile)).toThrow("English image message")
|
|
359
359
|
|
|
360
360
|
setLocale("zh-TW")
|
|
361
|
-
const schemaZh = file({
|
|
361
|
+
const schemaZh = file(true, {
|
|
362
362
|
imageOnly: true,
|
|
363
363
|
i18n: {
|
|
364
364
|
en: {
|
|
@@ -375,7 +375,7 @@ describe("file() features", () => {
|
|
|
375
375
|
|
|
376
376
|
describe("complex scenarios", () => {
|
|
377
377
|
it("should work with multiple validations", () => {
|
|
378
|
-
const schema = file({
|
|
378
|
+
const schema = file(true, {
|
|
379
379
|
maxSize: 5 * 1024 * 1024, // 5MB
|
|
380
380
|
minSize: 1024, // 1KB
|
|
381
381
|
extension: [".jpg", ".png", ".pdf"],
|
|
@@ -397,11 +397,7 @@ describe("file() features", () => {
|
|
|
397
397
|
})
|
|
398
398
|
|
|
399
399
|
it("should handle null values correctly when not required", () => {
|
|
400
|
-
const schema = file({
|
|
401
|
-
required: false,
|
|
402
|
-
maxSize: 1024,
|
|
403
|
-
extension: [".txt"],
|
|
404
|
-
})
|
|
400
|
+
const schema = file(false, { maxSize: 1024, extension: [".txt"] })
|
|
405
401
|
|
|
406
402
|
expect(schema.parse(null)).toBe(null)
|
|
407
403
|
expect(schema.parse("")).toBe(null)
|
|
@@ -412,7 +408,7 @@ describe("file() features", () => {
|
|
|
412
408
|
})
|
|
413
409
|
|
|
414
410
|
it("should work with transform and all validations together", () => {
|
|
415
|
-
const schema = file({
|
|
411
|
+
const schema = file(true, {
|
|
416
412
|
maxSize: 2048,
|
|
417
413
|
extension: [".txt"],
|
|
418
414
|
namePattern: /^[a-z0-9_-]+\.txt$/,
|
|
@@ -429,7 +425,7 @@ describe("file() features", () => {
|
|
|
429
425
|
})
|
|
430
426
|
|
|
431
427
|
it("should validate predefined file categories with specific types", () => {
|
|
432
|
-
const imageSchema = file({ imageOnly: true, extension: [".jpg", ".png"] })
|
|
428
|
+
const imageSchema = file(true, { imageOnly: true, extension: [".jpg", ".png"] })
|
|
433
429
|
const jpegFile = createMockFile("photo.jpg", 1024, "image/jpeg")
|
|
434
430
|
const pngFile = createMockFile("image.png", 1024, "image/png")
|
|
435
431
|
const gifFile = createMockFile("animated.gif", 1024, "image/gif") // Valid image type but wrong extension
|
|
@@ -442,30 +438,30 @@ describe("file() features", () => {
|
|
|
442
438
|
|
|
443
439
|
describe("edge cases", () => {
|
|
444
440
|
it("should handle files without extensions", () => {
|
|
445
|
-
const schema = file({ extension: [".txt"] })
|
|
441
|
+
const schema = file(true, { extension: [".txt"] })
|
|
446
442
|
const noExtFile = createMockFile("README", 1024, "text/plain")
|
|
447
443
|
|
|
448
444
|
expect(() => schema.parse(noExtFile)).toThrow("File extension must be one of: .txt")
|
|
449
445
|
})
|
|
450
446
|
|
|
451
447
|
it("should handle empty file names", () => {
|
|
452
|
-
const schema = file({ namePattern: /^.+$/ }) // Must have at least one character
|
|
448
|
+
const schema = file(true, { namePattern: /^.+$/ }) // Must have at least one character
|
|
453
449
|
const emptyNameFile = createMockFile("", 1024, "text/plain")
|
|
454
450
|
|
|
455
451
|
expect(() => schema.parse(emptyNameFile)).toThrow("File name must match pattern")
|
|
456
452
|
})
|
|
457
453
|
|
|
458
454
|
it("should handle zero-sized files", () => {
|
|
459
|
-
const schema = file({ minSize: 1 })
|
|
455
|
+
const schema = file(true, { minSize: 1 })
|
|
460
456
|
const emptyFile = createMockFile("empty.txt", 0, "text/plain")
|
|
461
457
|
|
|
462
458
|
expect(() => schema.parse(emptyFile)).toThrow("File size must be at least 1 B")
|
|
463
459
|
})
|
|
464
460
|
|
|
465
461
|
it("should format file sizes correctly", () => {
|
|
466
|
-
const smallSchema = file({ maxSize: 1024 })
|
|
467
|
-
const mediumSchema = file({ maxSize: 1024 * 1024 })
|
|
468
|
-
const largeSchema = file({ maxSize: 1024 * 1024 * 1024 })
|
|
462
|
+
const smallSchema = file(true, { maxSize: 1024 })
|
|
463
|
+
const mediumSchema = file(true, { maxSize: 1024 * 1024 })
|
|
464
|
+
const largeSchema = file(true, { maxSize: 1024 * 1024 * 1024 })
|
|
469
465
|
|
|
470
466
|
const tooLargeSmall = createMockFile("file.txt", 2048, "text/plain")
|
|
471
467
|
const tooLargeMedium = createMockFile("file.txt", 2 * 1024 * 1024, "text/plain")
|
|
@@ -476,4 +472,4 @@ describe("file() features", () => {
|
|
|
476
472
|
expect(() => largeSchema.parse(tooLargeLarge)).toThrow("File size must not exceed 1 GB")
|
|
477
473
|
})
|
|
478
474
|
})
|
|
479
|
-
})
|
|
475
|
+
})
|