@teonord/validator
v0.2.0
Published
Advanced validation library with multiple API styles including JSON templates, inline rules, builder pattern, and functional composition. Features 50+ built-in validators, dot notation for nested objects, field reference resolution, and internationalizati
Maintainers
Readme
@teonord/validator
Advanced validation library with multiple API styles including JSON templates, inline rules, builder pattern, and functional composition. Features 50+ built-in validators, dot notation for nested objects, field reference resolution, and internationalization support. Zero dependencies, fully synchronous, and designed for maximum developer experience with extensible custom rule system.
Features
- 🎯 Multiple Validation APIs: JSON templates, inline rules, builder pattern, functional composition
- 🏷️ TypeScript First: Full type safety and intelligent autocomplete
- 🌍 Internationalization: Multi-language error messages
- 🔧 Extensible: Custom rules and validators
- 🧪 Comprehensive Rule Set: 50+ built-in validation rules
- 🚀 Lightweight: Zero dependencies, tree-shakable
📚 Table of Contents
- Installation
- Quick Start
- JSON Template Validation
- Validation APIs
- Rule Reference
- Error Handling
- Internationalization
- Custom Rules
- API Reference
Installation
npm install @teonord/validatorExamples
Quick Start
import { Validator, parseInlineRules } from '@teonord/validator';
const data = {
name: 'John Doe',
email: '[email protected]',
age: 25
};
const validator = new Validator(data);
const result = validator.validateRules({
name: parseInlineRules('required|minLength:2'),
email: parseInlineRules('required|email'),
age: [{ rule: 'numeric' }, { rule: 'min', value: 18 }]
});
console.log(result.isValid); // true
console.log(result.errors); // []JSON Template Validation
import { Validator } from '@teonord/validator';
const data = {
username: 'john_doe',
};
const validator = new Validator(data);
const template = [
{
name: 'username',
validation: [
{
rule: 'required',
message: {
en: 'Username is required',
fr: 'Nom d\'utilisateur est requis'
}
},
{
rule: 'minLength',
value: 3,
message: {
en: 'Username must be at least 3 characters',
fr: 'Le nom d\'utilisateur doit contenir au moins 3 caractères'
}
}
]
}
];
const result = validator.validateTemplate(template);Validation APIs
JSON Template API
Structured validation with field definitions and custom messages:
import { Validator } from '@teonord/validator';
const data = {
email: '[email protected]',
password: 'pass123',
};
const validator = new Validator(data);
const template = [
{
name: 'email',
validation: [
{
rule: 'required',
message: { en: 'Email is required', es: 'El email es requerido' }
},
{
rule: 'email',
message: { en: 'Invalid email format', es: 'Formato de email inválido' }
}
]
},
{
name: 'password',
validation: [
{
rule: 'required',
message: { en: 'Password is required', es: 'La contraseña es requerida' }
},
{
rule: 'minLength',
value: 8,
message: { en: 'Password must be 8+ characters', es: 'La contraseña debe tener 8+ caracteres' }
}
]
}
];
const result = validator.validateTemplate(template);Inline Rules API
import { Validator, parseInlineRules } from '@teonord/validator';
const data = {
username: 'john',
email: '[email protected]',
age: 25,
tags: ['js', 'ts'],
website: 'https://example.com'
};
const validator = new Validator(data);
const result = validator.validateRules({
username: parseInlineRules('required|minLength:3|maxLength:20|alphaDash'),
email: parseInlineRules('required|email'),
age: parseInlineRules('required|numeric|min:18|max:100'),
tags: parseInlineRules('array|minItems:1|maxItems:5'),
website: parseInlineRules('url')
});Builder Pattern API
Fluent interface for building validation rules:
import { ValidatorBuilder } from '@teonord/validator';
const result = new ValidatorBuilder()
.setData({ username: 'john_doe', email: '[email protected]' })
.addField('username', [
{ rule: 'required' },
{ rule: 'minLength', value: 3 },
{ rule: 'alphaDash' }
])
.addField('email', [
{ rule: 'required' },
{ rule: 'email' }
])
.setLanguage('en')
.validate();Functional Composition API
Composable validation pipelines:
import { createPipe, pipe, transformData, mapErrors, conditional, validateField, parseInlineRules } from '@teonord/validator';
// Individual validation pipes
const userValidation = createPipe({
name: [{ rule: 'required' }, { rule: 'minLength', value: 2 }],
email: [{ rule: 'required' }, { rule: 'email' }]
});
const addressValidation = createPipe({
street: [{ rule: 'required' }],
city: [{ rule: 'required' }],
country: [{ rule: 'required' }, { rule: 'in', value: ['US', 'CA', 'UK'] }]
});
const paymentValidation = createPipe({
payment_method: [{ rule: 'required' }],
amount: [{ rule: 'required' }, { rule: 'numeric' }, { rule: 'min', value: 1 }]
});
// Data transformation
const sanitizeData = (data) => ({
...data,
name: data.name?.trim().toLowerCase(),
email: data.email?.trim().toLowerCase(),
street: data.street?.trim()
});
// Error formatting
const formatErrors = (errors) =>
errors.map(error => ({
...error,
message: `${error.field}: ${error.message}`,
code: `VALIDATION_${error.rule.toUpperCase()}`
}));
// Complete validation pipeline
const completeValidation = pipe(
transformData(userValidation, sanitizeData),
addressValidation,
conditional(
(data) => data.requires_payment,
paymentValidation
)
);
const validationPipe = mapErrors(completeValidation, formatErrors);
// Usage
const userData = {
name: ' JOHN DOE ',
email: '[email protected]',
street: '123 Main St',
city: 'New York',
country: 'US',
requires_payment: true,
payment_method: 'credit_card',
amount: 50
};
const result = validationPipe(userData);Rule Reference
String Rules
required- Field is requiredminLength:value- Minimum string lengthmaxLength:value- Maximum string lengthlength:value- Exact string lengthemail- Valid email formaturl- Valid URL formatip- Valid IP address (IPv4, IPv6 compressed/uncompressed, IPv4-mapped)uuid- Valid UUID formatalpha- Only lettersalphaNumeric- Letters and numbers onlyalphaDash- Letters, numbers, dashes and underscoresregex:pattern- Matches regex patternstartsWith:value- Starts with valueendsWith:value- Ends with valuecontains:value- Contains valuenotContains:value- Does not contain valuein:value1,value2,...- Value is in listnotIn:value1,value2,...- Value is not in list
Number Rules
numeric- Is a numberinteger- Is an integerfloat- Is a floatmin:value- Minimum valuemax:value- Maximum valuebetween:min,max- Between min and maxpositive- Positive numbernegative- Negative numbermultipleOf:value- Multiple of value
Array Rules
array- Is an arrayminItems:value- Minimum array lengthmaxItems:value- Maximum array lengthlengthItems:value- Exact array lengthincludes:value- Array includes valueexcludes:value- Array excludes valueunique- Array has unique values
Date Rules
date- Valid datebefore:date- Date is beforeafter:date- Date is afterbetweenDates:start,end- Date is between
File Rules
file- Is a file objectmime:type1,type2,...- File MIME typemaxSize:bytes- Maximum file sizeminSize:bytes- Minimum file size
Boolean Rules
boolean- Is booleanaccepted- Is accepted (true, 'true', 1, '1', 'yes', 'on')
Conditional Rules
requiredIf:field,value- Required if field equals valuerequiredUnless:field,value- Required unless field equals valuerequiredWith:field- Required when field is presentrequiredWithAll:field1,field2,...- Required when all fields presentrequiredWithout:field- Required when field is not presentrequiredWithoutAll:field1,field2,...- Required when none of fields presentsame:field- Same as another fielddifferent:field- Different from another fieldgt:field- Greater than another fieldgte:field- Greater than or equal to another fieldlt:field- Less than another fieldlte:field- Less than or equal to another fieldwhen:condition- Apply rules when condition is truerequiredIfAny:conditions- Required if any condition is metrequiredIfAll:conditions- Required if all conditions are met
Error Handling
import { Validator } from '@teonord/validator';
const validator = new Validator(data);
const result = validator.validateRules({
email: [{ rule: 'required' }, { rule: 'email' }]
});
if (!result.isValid) {
result.errors.forEach(error => {
console.log(`Field: ${error.field}`);
console.log(`Rule: ${error.rule}`);
console.log(`Message: ${error.message}`);
console.log(`Value: ${error.value}`);
});
const apiErrors = result.errors.map(error => ({
field: error.field,
message: error.message,
code: error.rule
}));
}Internationalization
import { Validator } from '@teonord/validator';
const validator = new Validator(data, {
language: 'fr',
customMessages: {
'email.required': {
en: 'Email address is required',
fr: 'L\'adresse email est requise',
es: 'La dirección de correo electrónico es obligatoria'
},
'email.email': {
en: 'Must be a valid email address',
fr: 'Doit être une adresse email valide',
es: 'Debe ser una dirección de correo electrónico válida'
}
}
});Custom Rules
import { Validator } from '@teonord/validator';
const validator = new Validator(data, {
customRules: {
customRule: (value, params, data) => {
if (value === 'custom') {
return true;
}
return false; // or return error message string
}
}
});
validator.addCustomRule('even', (value) => typeof value === 'number' && value % 2 === 0);
const result = validator.validateRules({
field: [{ rule: 'customRule' }],
number: [{ rule: 'even' }]
});API Reference
Main Classes and Functions
Validator- Main validation classValidatorBuilder- Fluent builder for validation rulesparseInlineRules(rulesString)- Parse inline rule string
Convenience Functions
validateRules(data, rules, options?)- Validate with rules map (convenience function)validateTemplate(data, template, options?)- Validate with template (convenience function)createValidator(data, options?)- Create Validator instance (convenience function)createValidatorBuilder()- Create ValidatorBuilder instance (convenience function)
Validator Class
Constructor
new Validator(data: Record<string, any>, options?: ValidatorOptions)Methods
validateTemplate(template: any[]): ValidationResultvalidateRules(rules: Record<string, ValidationRuleConfig[]>): ValidationResultaddCustomRule(name: string, rule: CustomRule): void
ValidatorBuilder Class
Methods
setData(data: Record<string, any>): thisaddField(field: string, rules: ValidationRuleConfig[]): thissetOptions(options: ValidatorOptions): thissetLanguage(language: string): thisbuild(): Validatorvalidate(): ValidationResult
Functional API
createPipe(rules, options): ValidationPipecreateTemplatePipe(template, options): ValidationPipepipe(...pipes): ValidationPipemapErrors(pipe, mapper): ValidationPipetransformData(pipe, transformer): ValidationPipeconditional(condition, truePipe, falsePipe?): ValidationPipemergePipes(...pipes): ValidationPipevalidateField(field, rules, options?): ValidationPipetap(pipe, callback): ValidationPipecatchError(pipe, handler): ValidationPipewithDefault(pipe, defaultData): ValidationPipe
Types
interface ValidationResult {
isValid: boolean;
errors: ValidationError[];
data: Record<string, any>;
}
interface ValidationError {
field: string;
rule: string;
message: string;
value?: any;
params?: Record<string, any>;
}
interface ValidatorOptions {
language?: string;
customMessages?: Record<string, LocalizedMessage>;
customRules?: Record<string, CustomRule>;
}
interface LocalizedMessage {
[language: string]: string;
}
interface ValidationRuleConfig {
rule: string;
value?: any;
message?: LocalizedMessage;
field?: string;
fields?: string[];
condition?: (data: any) => boolean;
rules?: ValidationRuleConfig[];
}
type CustomRule = (value: any, params: any[], data: Record<string, any>) => boolean | string;