@stacksjs/ts-validation
Version:
A simple TypeScript starter kit using Bun.
319 lines (233 loc) • 9.3 kB
Markdown
<p align="center"><img src=".github/art/cover.jpg" alt="Social Card of this repo"></p>
[![npm version][npm-version-src]][npm-version-href]
[![GitHub Actions][github-actions-src]][github-actions-href]
[](http://commitizen.github.io/cz-cli/)
<!-- [![npm downloads][npm-downloads-src]][npm-downloads-href] -->
<!-- [![Codecov][codecov-src]][codecov-href] -->
# @stacksjs/ts-validation
A lightweight, type-safe validation library for TypeScript with blazing-fast performance, built for Bun.
## Features
- 🚀 **Blazing fast performance** - Optimized for speed
- 🔒 **Type-safe** - Full TypeScript support with strong typing
- 🔄 **Fluent API** - Chain validation rules for clean, readable code
- 🏗️ **Composable** - Create reusable validations and schemas
- 🧩 **Extendable** - Easy to add custom validators
- 💾 **Tiny footprint** - Lightweight with no dependencies
- 🔍 **Detailed errors** - Comprehensive error reporting
## Installation
```bash
# Using bun
bun add @stacksjs/ts-validation
# Using npm
npm install @stacksjs/ts-validation
# Using yarn
yarn add @stacksjs/ts-validation
# Using pnpm
pnpm add @stacksjs/ts-validation
```
## Quick Start
```typescript
import { v } from '@stacksjs/ts-validation'
// Create a validator for a user object
const userValidator = v.object().shape({
name: v.string().min(2).max(50).required(),
email: v.string().email().required(),
age: v.number().min(18).integer().required(),
website: v.string().url().optional(),
tags: v.array().each(v.string()).optional(),
})
// Validate a user object
const user = {
name: 'John Doe',
email: 'john@example.com',
age: 25,
website: 'https://example.com',
tags: ['developer', 'TypeScript'],
}
const result = userValidator.validate(user)
if (result.valid) {
console.log('User is valid!')
}
else {
console.error('Validation errors:', result.errors)
}
```
## Validation Types
### String Validation
```typescript
// Basic string validation
const nameValidator = v.string().min(2).max(50).required()
// Email validation
const emailValidator = v.string().email().required()
// URL validation
const websiteValidator = v.string().url().optional()
// Pattern matching
const zipCodeValidator = v.string().matches(/^\d{5}$/).required()
// Alphanumeric, alpha, or numeric characters
const usernameValidator = v.string().alphanumeric().required()
```
### Number Validation
```typescript
// Basic number validation
const ageValidator = v.number().min(18).max(120).required()
// Integer validation
const quantityValidator = v.number().integer().positive().required()
// Negative numbers
const temperatureValidator = v.number().negative().required()
```
### Boolean Validation
```typescript
// Boolean validation
const termsAcceptedValidator = v.boolean().required()
```
### Array Validation
```typescript
// Array validation
const tagsValidator = v.array().min(1).max(10).required()
// Validate each item in the array
const numbersValidator = v.array().each(v.number().positive()).required()
// Array with specific length
const coordinatesValidator = v.array().length(2).each(v.number()).required()
```
### Object Validation
```typescript
// Object validation
const addressValidator = v.object().shape({
street: v.string().required(),
city: v.string().required(),
state: v.string().length(2).required(),
zip: v.string().matches(/^\d{5}$/).required(),
})
// Nested object validation
const userValidator = v.object().shape({
name: v.string().required(),
address: addressValidator,
})
// Strict object validation (no extra fields allowed)
const strictValidator = v.object().strict().shape({
id: v.number().required(),
name: v.string().required(),
})
```
### Custom Validation
```typescript
// Custom validation
const isEven = (val: number) => val % 2 === 0
const evenNumberValidator = v.custom(isEven, 'Number must be even')
// Complex custom validation
const passwordValidator = v.string()
.min(8)
.matches(/[A-Z]/)
.matches(/[a-z]/)
.matches(/\d/)
.matches(/[^A-Z0-9]/i)
```
### Password Validation
The password validator provides comprehensive password validation with multiple security rules:
- Minimum and maximum length
- Must contain both letters and numbers (alphanumeric)
- Must have uppercase and lowercase letters
- Must contain special characters
- Can validate password matches (for confirmation)
```typescript
// Basic password validation
const passwordValidator = v.password()
.min(8)
.max(128)
.alphanumeric()
.hasUppercase()
.hasLowercase()
.hasNumbers()
.hasSpecialCharacters()
// Validate a password
const result = passwordValidator.validate('MySecureP@ss123')
if (result.valid) {
console.log('Password is valid!')
}
else {
console.error('Validation errors:', result.errors)
}
// Password matching validation
const confirmPasswordValidator = v.password().matches('MySecureP@ss123')
```
### Date and Time Validation
The library provides several date and time validators to handle different formats:
- Basic JavaScript Date objects
- MySQL DATETIME format (1000-01-01 to 9999-12-31)
- Unix timestamps (both seconds and milliseconds)
- MySQL TIMESTAMP format (1970-01-01 00:00:00 UTC to 2038-01-19 03:14:07 UTC)
```typescript
// Basic date validation
const dateValidator = v.date()
expect(dateValidator.test(new Date())).toBe(true)
expect(dateValidator.test(new Date('invalid'))).toBe(false)
// Datetime validation (MySQL DATETIME compatible)
const datetimeValidator = v.datetime()
expect(datetimeValidator.test(new Date('2023-01-01'))).toBe(true)
expect(datetimeValidator.test(new Date('0999-12-31'))).toBe(false) // Before 1000-01-01
expect(datetimeValidator.test(new Date('10000-01-01'))).toBe(false) // After 9999-12-31
// Unix timestamp validation
const unixValidator = v.unix()
expect(unixValidator.test(1683912345)).toBe(true) // Seconds
expect(unixValidator.test(1683912345000)).toBe(true) // Milliseconds
expect(unixValidator.test(-1)).toBe(false) // Invalid negative timestamp
// Regular timestamp validation (MySQL TIMESTAMP compatible)
const timestampValidator = v.timestamp()
expect(timestampValidator.test(0)).toBe(true) // 1970-01-01 00:00:00 UTC
expect(timestampValidator.test(2147483647)).toBe(true) // 2038-01-19 03:14:07 UTC
expect(timestampValidator.test(-1)).toBe(false) // Invalid negative timestamp
```
## Configuration
You can customize the validation behavior by modifying the `validation.config.ts` file:
```typescript
// validation.config.ts
import type { ValidationOptions } from '@stacksjs/ts-validation'
const config: ValidationOptions = {
verbose: true, // Enable detailed error messages
strictMode: false, // Stop on first error if true
cacheResults: true, // Cache validation results for better performance
errorMessages: {
// Customize error messages
required: '{field} is required',
email: '{field} must be a valid email address',
// ...more custom messages
},
}
export default config
```
## Performance Tips
1. **Use caching**: Enable `cacheResults` in the config for repeated validations
2. **Early returns**: Set `strictMode: true` to stop on first error when validating complex objects
3. **Reuse validators**: Create validators once and reuse them instead of creating new ones for each validation
## Testing
```bash
bun test
```
## Changelog
Please see our [releases](https://github.com/stackjs/ts-validation/releases) page for more information on what has changed recently.
## Contributing
Please see [CONTRIBUTING](.github/CONTRIBUTING.md) for details.
## Community
For help, discussion about best practices, or any other conversation that would benefit from being searchable:
[Discussions on GitHub](https://github.com/stacksjs/ts-validation/discussions)
For casual chit-chat with others using this package:
[Join the Stacks Discord Server](https://discord.gg/stacksjs)
## Credits
- [validator.js](https://github.com/validatorjs/validator.js) - for the original string validation functions
## Postcardware
"Software that is free, but hopes for a postcard." We love receiving postcards from around the world showing where Stacks is being used! We showcase them on our website too.
Our address: Stacks.js, 12665 Village Ln #2306, Playa Vista, CA 90094, United States 🌎
## Sponsors
We would like to extend our thanks to the following sponsors for funding Stacks development. If you are interested in becoming a sponsor, please reach out to us.
- [JetBrains](https://www.jetbrains.com/)
- [The Solana Foundation](https://solana.com/)
## License
The MIT License (MIT). Please see [LICENSE](LICENSE.md) for more information.
Made with 💙
<!-- Badges -->
[npm-version-src]: https://img.shields.io/npm/v/@stacksjs/ts-validation?style=flat-square
[npm-version-href]: https://npmjs.com/package/@stacksjs/ts-validation
[github-actions-src]: https://img.shields.io/github/actions/workflow/status/stacksjs/ts-validation/ci.yml?style=flat-square&branch=main
[github-actions-href]: https://github.com/stacksjs/ts-validation/actions?query=workflow%3Aci
<!-- [codecov-src]: https://img.shields.io/codecov/c/gh/stacksjs/ts-validation/main?style=flat-square
[codecov-href]: https://codecov.io/gh/stacksjs/ts-validation -->