@warlock.js/seal 3.0.19 → 3.0.20

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.
Files changed (118) hide show
  1. package/README.md +373 -373
  2. package/cjs/factory/validators.d.ts +2 -1
  3. package/cjs/factory/validators.d.ts.map +1 -1
  4. package/cjs/factory/validators.js +3 -1
  5. package/cjs/factory/validators.js.map +1 -1
  6. package/cjs/helpers/date-helpers.d.ts.map +1 -1
  7. package/cjs/helpers/date-helpers.js +2 -7
  8. package/cjs/helpers/date-helpers.js.map +1 -1
  9. package/cjs/index.js +1 -1
  10. package/cjs/mutators/index.d.ts +1 -0
  11. package/cjs/mutators/index.d.ts.map +1 -1
  12. package/cjs/mutators/scalar-mutators.d.ts +3 -0
  13. package/cjs/mutators/scalar-mutators.d.ts.map +1 -0
  14. package/cjs/mutators/scalar-mutators.js +6 -0
  15. package/cjs/mutators/scalar-mutators.js.map +1 -0
  16. package/cjs/rules/core/index.d.ts +1 -0
  17. package/cjs/rules/core/index.d.ts.map +1 -1
  18. package/cjs/rules/core/union.d.ts +9 -0
  19. package/cjs/rules/core/union.d.ts.map +1 -0
  20. package/cjs/rules/core/union.js +40 -0
  21. package/cjs/rules/core/union.js.map +1 -0
  22. package/cjs/validators/array-validator.d.ts +8 -0
  23. package/cjs/validators/array-validator.d.ts.map +1 -1
  24. package/cjs/validators/array-validator.js +20 -6
  25. package/cjs/validators/array-validator.js.map +1 -1
  26. package/cjs/validators/base-validator.d.ts +42 -0
  27. package/cjs/validators/base-validator.d.ts.map +1 -1
  28. package/cjs/validators/base-validator.js +57 -0
  29. package/cjs/validators/base-validator.js.map +1 -1
  30. package/cjs/validators/boolean-validator.d.ts +4 -0
  31. package/cjs/validators/boolean-validator.d.ts.map +1 -1
  32. package/cjs/validators/boolean-validator.js +6 -0
  33. package/cjs/validators/boolean-validator.js.map +1 -1
  34. package/cjs/validators/date-validator.d.ts +4 -0
  35. package/cjs/validators/date-validator.d.ts.map +1 -1
  36. package/cjs/validators/date-validator.js +7 -1
  37. package/cjs/validators/date-validator.js.map +1 -1
  38. package/cjs/validators/index.d.ts +1 -0
  39. package/cjs/validators/index.d.ts.map +1 -1
  40. package/cjs/validators/number-validator.d.ts +4 -0
  41. package/cjs/validators/number-validator.d.ts.map +1 -1
  42. package/cjs/validators/number-validator.js +6 -0
  43. package/cjs/validators/number-validator.js.map +1 -1
  44. package/cjs/validators/object-validator.d.ts +152 -0
  45. package/cjs/validators/object-validator.d.ts.map +1 -1
  46. package/cjs/validators/object-validator.js +223 -0
  47. package/cjs/validators/object-validator.js.map +1 -1
  48. package/cjs/validators/scalar-validator.d.ts +4 -0
  49. package/cjs/validators/scalar-validator.d.ts.map +1 -1
  50. package/cjs/validators/scalar-validator.js +8 -1
  51. package/cjs/validators/scalar-validator.js.map +1 -1
  52. package/cjs/validators/string-validator.d.ts +4 -0
  53. package/cjs/validators/string-validator.d.ts.map +1 -1
  54. package/cjs/validators/string-validator.js +6 -0
  55. package/cjs/validators/string-validator.js.map +1 -1
  56. package/cjs/validators/union-validator.d.ts +42 -0
  57. package/cjs/validators/union-validator.d.ts.map +1 -0
  58. package/cjs/validators/union-validator.js +44 -0
  59. package/cjs/validators/union-validator.js.map +1 -0
  60. package/esm/factory/validators.d.ts +2 -1
  61. package/esm/factory/validators.d.ts.map +1 -1
  62. package/esm/factory/validators.js +3 -1
  63. package/esm/factory/validators.js.map +1 -1
  64. package/esm/helpers/date-helpers.d.ts.map +1 -1
  65. package/esm/helpers/date-helpers.js +2 -7
  66. package/esm/helpers/date-helpers.js.map +1 -1
  67. package/esm/index.js +1 -1
  68. package/esm/mutators/index.d.ts +1 -0
  69. package/esm/mutators/index.d.ts.map +1 -1
  70. package/esm/mutators/scalar-mutators.d.ts +3 -0
  71. package/esm/mutators/scalar-mutators.d.ts.map +1 -0
  72. package/esm/mutators/scalar-mutators.js +6 -0
  73. package/esm/mutators/scalar-mutators.js.map +1 -0
  74. package/esm/rules/core/index.d.ts +1 -0
  75. package/esm/rules/core/index.d.ts.map +1 -1
  76. package/esm/rules/core/union.d.ts +9 -0
  77. package/esm/rules/core/union.d.ts.map +1 -0
  78. package/esm/rules/core/union.js +40 -0
  79. package/esm/rules/core/union.js.map +1 -0
  80. package/esm/validators/array-validator.d.ts +8 -0
  81. package/esm/validators/array-validator.d.ts.map +1 -1
  82. package/esm/validators/array-validator.js +20 -6
  83. package/esm/validators/array-validator.js.map +1 -1
  84. package/esm/validators/base-validator.d.ts +42 -0
  85. package/esm/validators/base-validator.d.ts.map +1 -1
  86. package/esm/validators/base-validator.js +57 -0
  87. package/esm/validators/base-validator.js.map +1 -1
  88. package/esm/validators/boolean-validator.d.ts +4 -0
  89. package/esm/validators/boolean-validator.d.ts.map +1 -1
  90. package/esm/validators/boolean-validator.js +6 -0
  91. package/esm/validators/boolean-validator.js.map +1 -1
  92. package/esm/validators/date-validator.d.ts +4 -0
  93. package/esm/validators/date-validator.d.ts.map +1 -1
  94. package/esm/validators/date-validator.js +7 -1
  95. package/esm/validators/date-validator.js.map +1 -1
  96. package/esm/validators/index.d.ts +1 -0
  97. package/esm/validators/index.d.ts.map +1 -1
  98. package/esm/validators/number-validator.d.ts +4 -0
  99. package/esm/validators/number-validator.d.ts.map +1 -1
  100. package/esm/validators/number-validator.js +6 -0
  101. package/esm/validators/number-validator.js.map +1 -1
  102. package/esm/validators/object-validator.d.ts +152 -0
  103. package/esm/validators/object-validator.d.ts.map +1 -1
  104. package/esm/validators/object-validator.js +223 -0
  105. package/esm/validators/object-validator.js.map +1 -1
  106. package/esm/validators/scalar-validator.d.ts +4 -0
  107. package/esm/validators/scalar-validator.d.ts.map +1 -1
  108. package/esm/validators/scalar-validator.js +8 -1
  109. package/esm/validators/scalar-validator.js.map +1 -1
  110. package/esm/validators/string-validator.d.ts +4 -0
  111. package/esm/validators/string-validator.d.ts.map +1 -1
  112. package/esm/validators/string-validator.js +6 -0
  113. package/esm/validators/string-validator.js.map +1 -1
  114. package/esm/validators/union-validator.d.ts +42 -0
  115. package/esm/validators/union-validator.d.ts.map +1 -0
  116. package/esm/validators/union-validator.js +44 -0
  117. package/esm/validators/union-validator.js.map +1 -0
  118. package/package.json +23 -2
package/README.md CHANGED
@@ -1,373 +1,373 @@
1
- # 🔮 Warlock Seal
2
-
3
- > Cast validation seals on your schemas to protect your data
4
-
5
- A powerful, type-safe validation library for TypeScript with an intuitive API and framework-agnostic design.
6
-
7
- ## 📦 Installation
8
-
9
- ```bash
10
- npm install @warlock.js/seal
11
- ```
12
-
13
- ```bash
14
- yarn add @warlock.js/seal
15
- ```
16
-
17
- ```bash
18
- pnpm add @warlock.js/seal
19
- ```
20
-
21
- ## 🚀 Quick Start
22
-
23
- ```typescript
24
- import { v, type Infer } from "@warlock.js/seal";
25
-
26
- // Define your validation schema (cast a seal)
27
- const userSeal = v.object({
28
- name: v.string().required().min(3),
29
- email: v.string().email().required(),
30
- age: v.int().min(18),
31
- status: v.string().in(["active", "inactive"]),
32
- });
33
-
34
- // Extract TypeScript type automatically
35
- type User = Infer<typeof userSeal>;
36
- // Result: { name: string; email: string; age: number; status: string }
37
-
38
- // Validate data
39
- const result = await v.validate(userSeal, userData);
40
-
41
- if (result.isValid) {
42
- console.log("Data is sealed! ✅", result.data);
43
- } else {
44
- console.log("Seal broken! ❌", result.errors);
45
- // [
46
- // { error: "The name must be at least 3 characters", path: "name" },
47
- // { error: "The email must be a valid email address", path: "email" }
48
- // ]
49
- }
50
- ```
51
-
52
- ## 🎯 Core Concepts
53
-
54
- ### Three-Layer Validation Pipeline
55
-
56
- Seal uses a unique **three-layer architecture** that separates concerns:
57
-
58
- ```
59
- Input Data
60
-
61
- 🔧 MUTATORS (Prep for Validation)
62
- - Normalize data before validation
63
- - Examples: trim(), lowercase(), toStartOfDay()
64
- - Run BEFORE validation rules
65
-
66
- ✅ VALIDATORS (Check Constraints)
67
- - Validate against rules
68
- - Examples: email(), min(), after()
69
- - Return errors if validation fails
70
-
71
- 🎨 TRANSFORMERS (Format Output)
72
- - Format validated data for output
73
- - Examples: toISOString(), toFormat()
74
- - Run AFTER validation passes
75
-
76
- Output Data
77
- ```
78
-
79
- ### Example: Date Validation
80
-
81
- ```typescript
82
- const schema = v
83
- .date()
84
- .toStartOfDay() // 🔧 Mutator: normalize to 00:00:00
85
- .after("2024-01-01") // ✅ Validator: check Date object
86
- .toISOString(); // 🎨 Transformer: output as ISO string
87
-
88
- const result = await v.validate(schema, "2024-06-15 14:30:00");
89
- // result.data = "2024-06-15T00:00:00.000Z"
90
- ```
91
-
92
- **Why this matters:**
93
-
94
- - Mutators prepare data for validation (no more string comparison issues!)
95
- - Validators check constraints on normalized data
96
- - Transformers format output without affecting validation
97
-
98
- ---
99
-
100
- ## 🌟 Key Features
101
-
102
- ### ✅ Type Inference
103
-
104
- Automatically extract TypeScript types from your schemas:
105
-
106
- ```typescript
107
- const schema = v.object({
108
- name: v.string().required(),
109
- age: v.int(),
110
- tags: v.array(v.string()),
111
- });
112
-
113
- type User = Infer<typeof schema>;
114
- // { name: string; age: number; tags: string[] }
115
- ```
116
-
117
- ### ✅ Intuitive API
118
-
119
- Readable, chainable methods:
120
-
121
- ```typescript
122
- v.string().required().email().min(5).max(100);
123
-
124
- v.int().min(0).max(100).positive();
125
-
126
- v.array(v.string()).minLength(1).unique();
127
- ```
128
-
129
- ### ✅ Conditional Validation
130
-
131
- Apply different validators based on other field values:
132
-
133
- ```typescript
134
- const schema = v.object({
135
- type: v.string().required().in(["admin", "user"]),
136
- role: v.string().when("type", {
137
- is: {
138
- admin: v.string().required().in(["super", "moderator"]),
139
- user: v.string().required().in(["member", "guest"]),
140
- },
141
- }),
142
- });
143
-
144
- // If type is "admin", role must be "super" or "moderator"
145
- // If type is "user", role must be "member" or "guest"
146
- ```
147
-
148
- ### ✅ Field Comparison
149
-
150
- Compare fields against each other (global or sibling scope):
151
-
152
- ```typescript
153
- const schema = v.object({
154
- password: v.string().required().min(8),
155
- confirmPassword: v.string().required().sameAs("password"), // Compare with password field
156
-
157
- startDate: v.date().required(),
158
- endDate: v.date().required().after("startDate"), // Compare with startDate field
159
- });
160
- ```
161
-
162
- ### ✅ Custom Validation
163
-
164
- Add your own validation logic:
165
-
166
- ```typescript
167
- v.string().refine(async value => {
168
- const exists = await checkUsername(value);
169
- if (exists) return "Username already taken";
170
- });
171
- ```
172
-
173
- ### ✅ Mutators & Transformers
174
-
175
- Normalize input and format output:
176
-
177
- ```typescript
178
- // String mutators
179
- v.string()
180
- .trim() // Remove whitespace
181
- .lowercase() // Convert to lowercase
182
- .email() // Validate email
183
- .toJSON(); // Transform to JSON string
184
-
185
- // Date mutators & transformers
186
- v.date()
187
- .toStartOfDay() // Normalize to midnight
188
- .after("2024-01-01")
189
- .toISOString(); // Output as ISO string
190
- ```
191
-
192
- ---
193
-
194
- ## 📚 Documentation
195
-
196
- For complete documentation, visit: **[https://warlock.js.org/seal](https://warlock.js.org/seal)**
197
-
198
- ### Available Validators
199
-
200
- | Validator | Purpose | Example |
201
- | ------------- | ------------------ | -------------------------------- |
202
- | `v.string()` | String validation | `v.string().email().min(3)` |
203
- | `v.int()` | Integer validation | `v.int().min(0).max(100)` |
204
- | `v.float()` | Float validation | `v.float().positive()` |
205
- | `v.number()` | Number validation | `v.number().min(0)` |
206
- | `v.boolean()` | Boolean validation | `v.boolean().accepted()` |
207
- | `v.date()` | Date validation | `v.date().after(new Date())` |
208
- | `v.array()` | Array validation | `v.array(v.string()).min(1)` |
209
- | `v.object()` | Object validation | `v.object({ name: v.string() })` |
210
- | `v.scalar()` | Scalar values | `v.scalar().in([1, "2", true])` |
211
-
212
- ### Common Methods
213
-
214
- Available on all validators:
215
-
216
- | Method | Purpose |
217
- | -------------------------- | -------------------------------- |
218
- | `.required()` | Value must be present |
219
- | `.optional()` | Value is optional |
220
- | `.forbidden()` | Value must not be present |
221
- | `.equals(value)` | Must equal specific value |
222
- | `.default(value)` | Set default value |
223
- | `.allowsEmpty()` | Skip validation if empty |
224
- | `.when(field, conditions)` | Conditional validation |
225
- | `.omit()` | Validate but exclude from output |
226
- | `.refine(callback)` | Custom validation logic |
227
-
228
- ---
229
-
230
- ## 💡 Examples
231
-
232
- ### User Registration
233
-
234
- ```typescript
235
- const registerSchema = v.object({
236
- email: v.string().required().email(),
237
- password: v.string().required().min(8).strongPassword(),
238
- confirmPassword: v.string().required().sameAs("password"),
239
- age: v.int().required().min(18).max(120),
240
- terms: v.boolean().required().accepted(),
241
- });
242
- ```
243
-
244
- ### Form with Conditional Fields
245
-
246
- ```typescript
247
- const formSchema = v.object({
248
- accountType: v.string().required().in(["personal", "business"]),
249
-
250
- // Required only if accountType is "business"
251
- companyName: v.string().requiredIf("accountType", { is: "business" }),
252
-
253
- // Conditional validation
254
- taxId: v.string().when("accountType", {
255
- is: {
256
- business: v
257
- .string()
258
- .required()
259
- .pattern(/^[0-9]{9}$/),
260
- personal: v.string().forbidden(),
261
- },
262
- }),
263
- });
264
- ```
265
-
266
- ### Date Range Validation
267
-
268
- ```typescript
269
- const bookingSchema = v.object({
270
- checkIn: v.date().required().afterToday(),
271
-
272
- checkOut: v
273
- .date()
274
- .required()
275
- .after("checkIn") // Compare with checkIn field
276
- .withinDays(30), // Max 30 days from checkIn
277
- });
278
- ```
279
-
280
- ### Array Validation
281
-
282
- ```typescript
283
- const tagsSchema = v
284
- .array(v.string())
285
- .required()
286
- .minLength(1)
287
- .maxLength(10)
288
- .unique();
289
-
290
- const usersSchema = v
291
- .array(
292
- v.object({
293
- name: v.string().required(),
294
- email: v.string().email(),
295
- }),
296
- )
297
- .minLength(1);
298
- ```
299
-
300
- ---
301
-
302
- ## 🔧 Framework Extensions
303
-
304
- For Warlock.js projects, framework-specific validators are available:
305
-
306
- ```typescript
307
- import { v } from "@warlock.js/core/v";
308
-
309
- const schema = v.object({
310
- email: v.string().email().unique(User), // Database validation
311
- avatar: v.file().image().maxSize(5000000), // File upload validation
312
- uploadId: v.string().uploadable(), // Upload hash validation
313
- });
314
- ```
315
-
316
- ---
317
-
318
- ## 🎨 Why "Seal"?
319
-
320
- 🔮 **Magical Context**
321
- Warlocks use seals to protect and verify. Your validation schemas are seals that protect your data integrity.
322
-
323
- 💻 **Programming Context**
324
- A "seal of approval" - data that passes validation is sealed and verified.
325
-
326
- ✨ **Developer Experience**
327
- Clean, intuitive API that feels natural:
328
-
329
- ```typescript
330
- const seal = v.object({ ... }); // Cast a seal
331
- await v.validate(seal, data); // Verify with the seal
332
- ```
333
-
334
- ---
335
-
336
- ## 🤝 Philosophy
337
-
338
- **Seal** is designed around three principles:
339
-
340
- 1. **Type Safety First** - TypeScript support is not an afterthought
341
- 2. **Framework Agnostic** - Works anywhere JavaScript runs
342
- 3. **Intuitive API** - If it feels right, it probably works
343
-
344
- ---
345
-
346
- ## 📖 Full Documentation
347
-
348
- For complete documentation, visit: **[https://warlock.js.org/seal](https://warlock.js.org/seal)**
349
-
350
- The documentation includes:
351
-
352
- - 📘 [Getting Started Guide](https://warlock.js.org/seal/getting-started/introduction)
353
- - 🎯 [Core Concepts](https://warlock.js.org/seal/concepts/three-layer-architecture)
354
- - 📝 [Validator Reference](https://warlock.js.org/seal/base-validator)
355
- - 🔍 [All Validation Rules](https://warlock.js.org/seal/string-validator)
356
- - 🔌 [Plugin System](https://warlock.js.org/seal/advanced/plugins)
357
- - 🎨 [Custom Rules](https://warlock.js.org/seal/advanced/custom-rules)
358
-
359
- ---
360
-
361
- ## 📄 License
362
-
363
- MIT
364
-
365
- ---
366
-
367
- ## 🤝 Contributing
368
-
369
- See main Warlock.js repository
370
-
371
- ---
372
-
373
- **Cast your seals and protect your data! 🔮✨**
1
+ # 🔮 Warlock Seal
2
+
3
+ > Cast validation seals on your schemas to protect your data
4
+
5
+ A powerful, type-safe validation library for TypeScript with an intuitive API and framework-agnostic design.
6
+
7
+ ## 📦 Installation
8
+
9
+ ```bash
10
+ npm install @warlock.js/seal
11
+ ```
12
+
13
+ ```bash
14
+ yarn add @warlock.js/seal
15
+ ```
16
+
17
+ ```bash
18
+ pnpm add @warlock.js/seal
19
+ ```
20
+
21
+ ## 🚀 Quick Start
22
+
23
+ ```typescript
24
+ import { v, type Infer } from "@warlock.js/seal";
25
+
26
+ // Define your validation schema (cast a seal)
27
+ const userSeal = v.object({
28
+ name: v.string().required().min(3),
29
+ email: v.string().email().required(),
30
+ age: v.int().min(18),
31
+ status: v.string().in(["active", "inactive"]),
32
+ });
33
+
34
+ // Extract TypeScript type automatically
35
+ type User = Infer<typeof userSeal>;
36
+ // Result: { name: string; email: string; age: number; status: string }
37
+
38
+ // Validate data
39
+ const result = await v.validate(userSeal, userData);
40
+
41
+ if (result.isValid) {
42
+ console.log("Data is sealed! ✅", result.data);
43
+ } else {
44
+ console.log("Seal broken! ❌", result.errors);
45
+ // [
46
+ // { error: "The name must be at least 3 characters", path: "name" },
47
+ // { error: "The email must be a valid email address", path: "email" }
48
+ // ]
49
+ }
50
+ ```
51
+
52
+ ## 🎯 Core Concepts
53
+
54
+ ### Three-Layer Validation Pipeline
55
+
56
+ Seal uses a unique **three-layer architecture** that separates concerns:
57
+
58
+ ```
59
+ Input Data
60
+
61
+ 🔧 MUTATORS (Prep for Validation)
62
+ - Normalize data before validation
63
+ - Examples: trim(), lowercase(), toStartOfDay()
64
+ - Run BEFORE validation rules
65
+
66
+ ✅ VALIDATORS (Check Constraints)
67
+ - Validate against rules
68
+ - Examples: email(), min(), after()
69
+ - Return errors if validation fails
70
+
71
+ 🎨 TRANSFORMERS (Format Output)
72
+ - Format validated data for output
73
+ - Examples: toISOString(), toFormat()
74
+ - Run AFTER validation passes
75
+
76
+ Output Data
77
+ ```
78
+
79
+ ### Example: Date Validation
80
+
81
+ ```typescript
82
+ const schema = v
83
+ .date()
84
+ .toStartOfDay() // 🔧 Mutator: normalize to 00:00:00
85
+ .after("2024-01-01") // ✅ Validator: check Date object
86
+ .toISOString(); // 🎨 Transformer: output as ISO string
87
+
88
+ const result = await v.validate(schema, "2024-06-15 14:30:00");
89
+ // result.data = "2024-06-15T00:00:00.000Z"
90
+ ```
91
+
92
+ **Why this matters:**
93
+
94
+ - Mutators prepare data for validation (no more string comparison issues!)
95
+ - Validators check constraints on normalized data
96
+ - Transformers format output without affecting validation
97
+
98
+ ---
99
+
100
+ ## 🌟 Key Features
101
+
102
+ ### ✅ Type Inference
103
+
104
+ Automatically extract TypeScript types from your schemas:
105
+
106
+ ```typescript
107
+ const schema = v.object({
108
+ name: v.string().required(),
109
+ age: v.int(),
110
+ tags: v.array(v.string()),
111
+ });
112
+
113
+ type User = Infer<typeof schema>;
114
+ // { name: string; age: number; tags: string[] }
115
+ ```
116
+
117
+ ### ✅ Intuitive API
118
+
119
+ Readable, chainable methods:
120
+
121
+ ```typescript
122
+ v.string().required().email().min(5).max(100);
123
+
124
+ v.int().min(0).max(100).positive();
125
+
126
+ v.array(v.string()).minLength(1).unique();
127
+ ```
128
+
129
+ ### ✅ Conditional Validation
130
+
131
+ Apply different validators based on other field values:
132
+
133
+ ```typescript
134
+ const schema = v.object({
135
+ type: v.string().required().in(["admin", "user"]),
136
+ role: v.string().when("type", {
137
+ is: {
138
+ admin: v.string().required().in(["super", "moderator"]),
139
+ user: v.string().required().in(["member", "guest"]),
140
+ },
141
+ }),
142
+ });
143
+
144
+ // If type is "admin", role must be "super" or "moderator"
145
+ // If type is "user", role must be "member" or "guest"
146
+ ```
147
+
148
+ ### ✅ Field Comparison
149
+
150
+ Compare fields against each other (global or sibling scope):
151
+
152
+ ```typescript
153
+ const schema = v.object({
154
+ password: v.string().required().min(8),
155
+ confirmPassword: v.string().required().sameAs("password"), // Compare with password field
156
+
157
+ startDate: v.date().required(),
158
+ endDate: v.date().required().after("startDate"), // Compare with startDate field
159
+ });
160
+ ```
161
+
162
+ ### ✅ Custom Validation
163
+
164
+ Add your own validation logic:
165
+
166
+ ```typescript
167
+ v.string().refine(async value => {
168
+ const exists = await checkUsername(value);
169
+ if (exists) return "Username already taken";
170
+ });
171
+ ```
172
+
173
+ ### ✅ Mutators & Transformers
174
+
175
+ Normalize input and format output:
176
+
177
+ ```typescript
178
+ // String mutators
179
+ v.string()
180
+ .trim() // Remove whitespace
181
+ .lowercase() // Convert to lowercase
182
+ .email() // Validate email
183
+ .toJSON(); // Transform to JSON string
184
+
185
+ // Date mutators & transformers
186
+ v.date()
187
+ .toStartOfDay() // Normalize to midnight
188
+ .after("2024-01-01")
189
+ .toISOString(); // Output as ISO string
190
+ ```
191
+
192
+ ---
193
+
194
+ ## 📚 Documentation
195
+
196
+ For complete documentation, visit: **[https://warlock.js.org/seal](https://warlock.js.org/seal)**
197
+
198
+ ### Available Validators
199
+
200
+ | Validator | Purpose | Example |
201
+ | ------------- | ------------------ | -------------------------------- |
202
+ | `v.string()` | String validation | `v.string().email().min(3)` |
203
+ | `v.int()` | Integer validation | `v.int().min(0).max(100)` |
204
+ | `v.float()` | Float validation | `v.float().positive()` |
205
+ | `v.number()` | Number validation | `v.number().min(0)` |
206
+ | `v.boolean()` | Boolean validation | `v.boolean().accepted()` |
207
+ | `v.date()` | Date validation | `v.date().after(new Date())` |
208
+ | `v.array()` | Array validation | `v.array(v.string()).min(1)` |
209
+ | `v.object()` | Object validation | `v.object({ name: v.string() })` |
210
+ | `v.scalar()` | Scalar values | `v.scalar().in([1, "2", true])` |
211
+
212
+ ### Common Methods
213
+
214
+ Available on all validators:
215
+
216
+ | Method | Purpose |
217
+ | -------------------------- | -------------------------------- |
218
+ | `.required()` | Value must be present |
219
+ | `.optional()` | Value is optional |
220
+ | `.forbidden()` | Value must not be present |
221
+ | `.equals(value)` | Must equal specific value |
222
+ | `.default(value)` | Set default value |
223
+ | `.allowsEmpty()` | Skip validation if empty |
224
+ | `.when(field, conditions)` | Conditional validation |
225
+ | `.omit()` | Validate but exclude from output |
226
+ | `.refine(callback)` | Custom validation logic |
227
+
228
+ ---
229
+
230
+ ## 💡 Examples
231
+
232
+ ### User Registration
233
+
234
+ ```typescript
235
+ const registerSchema = v.object({
236
+ email: v.string().required().email(),
237
+ password: v.string().required().min(8).strongPassword(),
238
+ confirmPassword: v.string().required().sameAs("password"),
239
+ age: v.int().required().min(18).max(120),
240
+ terms: v.boolean().required().accepted(),
241
+ });
242
+ ```
243
+
244
+ ### Form with Conditional Fields
245
+
246
+ ```typescript
247
+ const formSchema = v.object({
248
+ accountType: v.string().required().in(["personal", "business"]),
249
+
250
+ // Required only if accountType is "business"
251
+ companyName: v.string().requiredIf("accountType", { is: "business" }),
252
+
253
+ // Conditional validation
254
+ taxId: v.string().when("accountType", {
255
+ is: {
256
+ business: v
257
+ .string()
258
+ .required()
259
+ .pattern(/^[0-9]{9}$/),
260
+ personal: v.string().forbidden(),
261
+ },
262
+ }),
263
+ });
264
+ ```
265
+
266
+ ### Date Range Validation
267
+
268
+ ```typescript
269
+ const bookingSchema = v.object({
270
+ checkIn: v.date().required().afterToday(),
271
+
272
+ checkOut: v
273
+ .date()
274
+ .required()
275
+ .after("checkIn") // Compare with checkIn field
276
+ .withinDays(30), // Max 30 days from checkIn
277
+ });
278
+ ```
279
+
280
+ ### Array Validation
281
+
282
+ ```typescript
283
+ const tagsSchema = v
284
+ .array(v.string())
285
+ .required()
286
+ .minLength(1)
287
+ .maxLength(10)
288
+ .unique();
289
+
290
+ const usersSchema = v
291
+ .array(
292
+ v.object({
293
+ name: v.string().required(),
294
+ email: v.string().email(),
295
+ })
296
+ )
297
+ .minLength(1);
298
+ ```
299
+
300
+ ---
301
+
302
+ ## 🔧 Framework Extensions
303
+
304
+ For Warlock.js projects, framework-specific validators are available:
305
+
306
+ ```typescript
307
+ import { v } from "@warlock.js/core/v";
308
+
309
+ const schema = v.object({
310
+ email: v.string().email().unique(User), // Database validation
311
+ avatar: v.file().image().maxSize(5000000), // File upload validation
312
+ uploadId: v.string().uploadable(), // Upload hash validation
313
+ });
314
+ ```
315
+
316
+ ---
317
+
318
+ ## 🎨 Why "Seal"?
319
+
320
+ 🔮 **Magical Context**
321
+ Warlocks use seals to protect and verify. Your validation schemas are seals that protect your data integrity.
322
+
323
+ 💻 **Programming Context**
324
+ A "seal of approval" - data that passes validation is sealed and verified.
325
+
326
+ ✨ **Developer Experience**
327
+ Clean, intuitive API that feels natural:
328
+
329
+ ```typescript
330
+ const seal = v.object({ ... }); // Cast a seal
331
+ await v.validate(seal, data); // Verify with the seal
332
+ ```
333
+
334
+ ---
335
+
336
+ ## 🤝 Philosophy
337
+
338
+ **Seal** is designed around three principles:
339
+
340
+ 1. **Type Safety First** - TypeScript support is not an afterthought
341
+ 2. **Framework Agnostic** - Works anywhere JavaScript runs
342
+ 3. **Intuitive API** - If it feels right, it probably works
343
+
344
+ ---
345
+
346
+ ## 📖 Full Documentation
347
+
348
+ For complete documentation, visit: **[https://warlock.js.org/seal](https://warlock.js.org/seal)**
349
+
350
+ The documentation includes:
351
+
352
+ - 📘 [Getting Started Guide](https://warlock.js.org/seal/getting-started/introduction)
353
+ - 🎯 [Core Concepts](https://warlock.js.org/seal/concepts/three-layer-architecture)
354
+ - 📝 [Validator Reference](https://warlock.js.org/seal/base-validator)
355
+ - 🔍 [All Validation Rules](https://warlock.js.org/seal/string-validator)
356
+ - 🔌 [Plugin System](https://warlock.js.org/seal/advanced/plugins)
357
+ - 🎨 [Custom Rules](https://warlock.js.org/seal/advanced/custom-rules)
358
+
359
+ ---
360
+
361
+ ## 📄 License
362
+
363
+ MIT
364
+
365
+ ---
366
+
367
+ ## 🤝 Contributing
368
+
369
+ See main Warlock.js repository
370
+
371
+ ---
372
+
373
+ **Cast your seals and protect your data! 🔮✨**