Skip to content

Commit a4f87dd

Browse files
chore: update readme.md
1 parent e9d9c0e commit a4f87dd

File tree

1 file changed

+223
-42
lines changed

1 file changed

+223
-42
lines changed

README.md

Lines changed: 223 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ A lightweight, type-safe validation library for TypeScript with blazing-fast per
1919
- 🧩 **Extendable** - Easy to add custom validators
2020
- 💾 **Tiny footprint** - Lightweight with no dependencies
2121
- 🔍 **Detailed errors** - Comprehensive error reporting
22+
- 🛡️ **Robust validation** - Handles null, undefined, and edge cases properly
2223

2324
## Installation
2425

@@ -45,7 +46,7 @@ import { v } from '@stacksjs/ts-validation'
4546
const userValidator = v.object({
4647
name: v.string().min(2).max(50).required(),
4748
email: v.string().email().required(),
48-
age: v.number().min(18).integer().required(),
49+
age: v.integer().min(18).max(120).required(),
4950
website: v.string().url().optional(),
5051
tags: v.array().each(v.string()).optional(),
5152
})
@@ -69,6 +70,46 @@ else {
6970
}
7071
```
7172

73+
## Basic Usage
74+
75+
### Simple Validation
76+
77+
```typescript
78+
import { v } from '@stacksjs/ts-validation'
79+
80+
// Validate a single value
81+
const emailValidator = v.string().email().required()
82+
const result = emailValidator.validate('[email protected]')
83+
84+
if (result.valid) {
85+
console.log('Email is valid!')
86+
}
87+
else {
88+
console.log('Validation errors:', result.errors)
89+
}
90+
91+
// Quick test method
92+
const isValid = emailValidator.test('[email protected]') // returns boolean
93+
```
94+
95+
### Error Handling
96+
97+
```typescript
98+
const result = userValidator.validate(invalidUser)
99+
100+
if (!result.valid) {
101+
// For single field validation
102+
result.errors.forEach((error) => {
103+
console.log(error.message)
104+
})
105+
106+
// For object validation
107+
Object.entries(result.errors).forEach(([field, errors]) => {
108+
console.log(`${field}:`, errors.map(e => e.message))
109+
})
110+
}
111+
```
112+
72113
## Validation Types
73114

74115
### String Validation
@@ -88,6 +129,9 @@ const zipCodeValidator = v.string().matches(/^\d{5}$/).required()
88129

89130
// Alphanumeric, alpha, or numeric characters
90131
const usernameValidator = v.string().alphanumeric().required()
132+
133+
// Text validation (specialized for text content)
134+
const bioValidator = v.text().max(500).optional()
91135
```
92136

93137
### Number Validation
@@ -96,8 +140,17 @@ const usernameValidator = v.string().alphanumeric().required()
96140
// Basic number validation
97141
const ageValidator = v.number().min(18).max(120).required()
98142

99-
// Integer validation
100-
const quantityValidator = v.number().integer().positive().required()
143+
// Integer validation (whole numbers only)
144+
const quantityValidator = v.integer().positive().required()
145+
146+
// Float validation (decimal numbers)
147+
const priceValidator = v.float().min(0.01).required()
148+
149+
// Small integer validation (-32,768 to 32,767)
150+
const smallNumberValidator = v.smallint().required()
151+
152+
// Decimal validation (with precision control)
153+
const decimalValidator = v.decimal().min(0).max(999.99).required()
101154

102155
// Negative numbers
103156
const temperatureValidator = v.number().negative().required()
@@ -135,8 +188,7 @@ const addressValidator = v.object({
135188
})
136189

137190
// Nested object validation
138-
// .shape() is an alias for .object()
139-
const userValidator = v.object().shape({
191+
const userValidator = v.object({
140192
name: v.string().required(),
141193
address: addressValidator,
142194
})
@@ -148,6 +200,71 @@ const strictValidator = v.object().strict().shape({
148200
})
149201
```
150202

203+
### Date and Time Validation
204+
205+
```typescript
206+
// Basic date validation
207+
const dateValidator = v.date()
208+
expect(dateValidator.test(new Date())).toBe(true)
209+
expect(dateValidator.test(new Date('invalid'))).toBe(false)
210+
211+
// Datetime validation (MySQL DATETIME compatible)
212+
const datetimeValidator = v.datetime()
213+
expect(datetimeValidator.test(new Date('2023-01-01'))).toBe(true)
214+
215+
// Time validation (24-hour format)
216+
const timeValidator = v.time()
217+
expect(timeValidator.test('14:30')).toBe(true)
218+
expect(timeValidator.test('25:00')).toBe(false) // Invalid hour
219+
220+
// Unix timestamp validation
221+
const unixValidator = v.unix()
222+
expect(unixValidator.test(1683912345)).toBe(true) // Seconds
223+
expect(unixValidator.test(1683912345000)).toBe(true) // Milliseconds
224+
225+
// Regular timestamp validation (MySQL TIMESTAMP compatible)
226+
const timestampValidator = v.timestamp()
227+
expect(timestampValidator.test(0)).toBe(true) // 1970-01-01 00:00:00 UTC
228+
229+
// Timestamp with timezone
230+
const timestampTzValidator = v.timestampTz()
231+
```
232+
233+
### JSON Validation
234+
235+
```typescript
236+
// JSON string validation
237+
const jsonValidator = v.json()
238+
expect(jsonValidator.test('{"name": "John"}')).toBe(true)
239+
expect(jsonValidator.test('{"a": 1, "b": 2}')).toBe(true)
240+
expect(jsonValidator.test('123')).toBe(false) // Primitive values are invalid
241+
expect(jsonValidator.test('not json')).toBe(false)
242+
```
243+
244+
### Binary and Blob Validation
245+
246+
```typescript
247+
// Binary data validation
248+
const binaryValidator = v.binary()
249+
250+
// Blob validation
251+
const blobValidator = v.blob()
252+
```
253+
254+
### BigInt Validation
255+
256+
```typescript
257+
// BigInt validation
258+
const bigIntValidator = v.bigint().min(0n).max(1000000n).required()
259+
```
260+
261+
### Enum Validation
262+
263+
```typescript
264+
// Enum validation
265+
const statusValidator = v.enum(['active', 'inactive', 'pending']).required()
266+
```
267+
151268
### Custom Validation
152269

153270
```typescript
@@ -168,12 +285,6 @@ const passwordValidator = v.string()
168285

169286
The password validator provides comprehensive password validation with multiple security rules:
170287

171-
- Minimum and maximum length
172-
- Must contain both letters and numbers (alphanumeric)
173-
- Must have uppercase and lowercase letters
174-
- Must contain special characters
175-
- Can validate password matches (for confirmation)
176-
177288
```typescript
178289
// Basic password validation
179290
const passwordValidator = v.password()
@@ -199,38 +310,114 @@ else {
199310
const confirmPasswordValidator = v.password().matches('MySecureP@ss123')
200311
```
201312

202-
### Date and Time Validation
313+
## Advanced Usage
203314

204-
The library provides several date and time validators to handle different formats:
315+
### Conditional Validation
316+
317+
```typescript
318+
const userValidator = v.object({
319+
name: v.string().required(),
320+
email: v.string().email().required(),
321+
age: v.integer().min(18).required(),
322+
// Conditional validation based on age
323+
guardianInfo: v.object({
324+
name: v.string().required(),
325+
phone: v.string().required(),
326+
}).custom((value, data) => {
327+
return data.age < 18 ? value !== null : true
328+
}, 'Guardian information required for users under 18'),
329+
})
330+
```
205331

206-
- Basic JavaScript Date objects
207-
- MySQL DATETIME format (1000-01-01 to 9999-12-31)
208-
- Unix timestamps (both seconds and milliseconds)
209-
- MySQL TIMESTAMP format (1970-01-01 00:00:00 UTC to 2038-01-19 03:14:07 UTC)
332+
### Reusable Validators
210333

211334
```typescript
212-
// Basic date validation
213-
const dateValidator = v.date()
214-
expect(dateValidator.test(new Date())).toBe(true)
215-
expect(dateValidator.test(new Date('invalid'))).toBe(false)
335+
// Create reusable validators
336+
const emailValidator = v.string().email().required()
337+
const phoneValidator = v.string().matches(/^\+?[\d\s-()]+$/).required()
216338

217-
// Datetime validation (MySQL DATETIME compatible)
218-
const datetimeValidator = v.datetime()
219-
expect(datetimeValidator.test(new Date('2023-01-01'))).toBe(true)
220-
expect(datetimeValidator.test(new Date('0999-12-31'))).toBe(false) // Before 1000-01-01
221-
expect(datetimeValidator.test(new Date('10000-01-01'))).toBe(false) // After 9999-12-31
339+
// Use them in multiple places
340+
const contactFormValidator = v.object({
341+
email: emailValidator,
342+
phone: phoneValidator,
343+
})
222344

223-
// Unix timestamp validation
224-
const unixValidator = v.unix()
225-
expect(unixValidator.test(1683912345)).toBe(true) // Seconds
226-
expect(unixValidator.test(1683912345000)).toBe(true) // Milliseconds
227-
expect(unixValidator.test(-1)).toBe(false) // Invalid negative timestamp
345+
const userProfileValidator = v.object({
346+
primaryEmail: emailValidator,
347+
secondaryEmail: emailValidator.optional(),
348+
phone: phoneValidator.optional(),
349+
})
350+
```
228351

229-
// Regular timestamp validation (MySQL TIMESTAMP compatible)
230-
const timestampValidator = v.timestamp()
231-
expect(timestampValidator.test(0)).toBe(true) // 1970-01-01 00:00:00 UTC
232-
expect(timestampValidator.test(2147483647)).toBe(true) // 2038-01-19 03:14:07 UTC
233-
expect(timestampValidator.test(-1)).toBe(false) // Invalid negative timestamp
352+
### Validation with Custom Error Messages
353+
354+
```typescript
355+
const userValidator = v.object({
356+
name: v.string()
357+
.min(2, 'Name must be at least 2 characters')
358+
.max(50, 'Name cannot exceed 50 characters')
359+
.required('Name is required'),
360+
email: v.string()
361+
.email('Please provide a valid email address')
362+
.required('Email is required'),
363+
})
364+
```
365+
366+
## Error Handling Examples
367+
368+
```typescript
369+
// Single field validation
370+
const emailResult = emailValidator.validate('invalid-email')
371+
if (!emailResult.valid) {
372+
emailResult.errors.forEach((error) => {
373+
console.log(`Email error: ${error.message}`)
374+
})
375+
}
376+
377+
// Object validation
378+
const userResult = userValidator.validate(invalidUser)
379+
if (!userResult.valid) {
380+
// userResult.errors is an object with field names as keys
381+
Object.entries(userResult.errors).forEach(([field, errors]) => {
382+
console.log(`${field}:`)
383+
errors.forEach((error) => {
384+
console.log(` - ${error.message}`)
385+
})
386+
})
387+
}
388+
```
389+
390+
## Performance Tips
391+
392+
1. **Reuse validators**: Create validators once and reuse them instead of creating new ones for each validation
393+
2. **Use specific validators**: Use `v.integer()` instead of `v.number().integer()` for better performance
394+
3. **Chain efficiently**: Order validation rules from most likely to fail first
395+
4. **Avoid unnecessary validations**: Use `.optional()` for fields that can be undefined
396+
397+
## TypeScript Integration
398+
399+
```typescript
400+
import { v } from '@stacksjs/ts-validation'
401+
402+
// Type-safe validation
403+
interface User {
404+
name: string
405+
email: string
406+
age: number
407+
}
408+
409+
const userValidator = v.object({
410+
name: v.string().required(),
411+
email: v.string().email().required(),
412+
age: v.integer().min(18).required(),
413+
})
414+
415+
// The result is fully typed
416+
const result = userValidator.validate(userData)
417+
if (result.valid) {
418+
// TypeScript knows userData is valid here
419+
const validUser: User = userData
420+
}
234421
```
235422

236423
## Configuration
@@ -256,12 +443,6 @@ const config: ValidationOptions = {
256443
export default config
257444
```
258445

259-
## Performance Tips
260-
261-
1. **Use caching**: Enable `cacheResults` in the config for repeated validations
262-
2. **Early returns**: Set `strictMode: true` to stop on first error when validating complex objects
263-
3. **Reuse validators**: Create validators once and reuse them instead of creating new ones for each validation
264-
265446
## Testing
266447

267448
```bash

0 commit comments

Comments
 (0)