JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 9
  • Score
    100M100P100Q49423F
  • License MIT

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.

Package Exports

  • @teonord/validator

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.

See examples

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

npm install @teonord/validator

Examples

Quick Start

import { Validator, parseInlineRules } from '@teonord/validator';

const data = {
  name: 'John Doe',
  email: 'john@example.com',
  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: 'john@example.com',
  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: 'john@example.com',
  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: 'john@example.com' })
  .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: 'JOHN@EXAMPLE.COM',
  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 required
  • minLength:value - Minimum string length
  • maxLength:value - Maximum string length
  • length:value - Exact string length
  • email - Valid email format
  • url - Valid URL format
  • ip - Valid IP address (IPv4, IPv6 compressed/uncompressed, IPv4-mapped)
  • uuid - Valid UUID format
  • alpha - Only letters
  • alphaNumeric - Letters and numbers only
  • alphaDash - Letters, numbers, dashes and underscores
  • regex:pattern - Matches regex pattern
  • startsWith:value - Starts with value
  • endsWith:value - Ends with value
  • contains:value - Contains value
  • notContains:value - Does not contain value
  • in:value1,value2,... - Value is in list
  • notIn:value1,value2,... - Value is not in list

Number Rules

  • numeric - Is a number
  • integer - Is an integer
  • float - Is a float
  • min:value - Minimum value
  • max:value - Maximum value
  • between:min,max - Between min and max
  • positive - Positive number
  • negative - Negative number
  • multipleOf:value - Multiple of value

Array Rules

  • array - Is an array
  • minItems:value - Minimum array length
  • maxItems:value - Maximum array length
  • lengthItems:value - Exact array length
  • includes:value - Array includes value
  • excludes:value - Array excludes value
  • unique - Array has unique values

Date Rules

  • date - Valid date
  • before:date - Date is before
  • after:date - Date is after
  • betweenDates:start,end - Date is between

File Rules

  • file - Is a file object
  • mime:type1,type2,... - File MIME type
  • maxSize:bytes - Maximum file size
  • minSize:bytes - Minimum file size

Boolean Rules

  • boolean - Is boolean
  • accepted - Is accepted (true, 'true', 1, '1', 'yes', 'on')

Conditional Rules

  • requiredIf:field,value - Required if field equals value
  • requiredUnless:field,value - Required unless field equals value
  • requiredWith:field - Required when field is present
  • requiredWithAll:field1,field2,... - Required when all fields present
  • requiredWithout:field - Required when field is not present
  • requiredWithoutAll:field1,field2,... - Required when none of fields present
  • same:field - Same as another field
  • different:field - Different from another field
  • gt:field - Greater than another field
  • gte:field - Greater than or equal to another field
  • lt:field - Less than another field
  • lte:field - Less than or equal to another field
  • when:condition - Apply rules when condition is true
  • requiredIfAny:conditions - Required if any condition is met
  • requiredIfAll: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 class
  • ValidatorBuilder - Fluent builder for validation rules
  • parseInlineRules(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[]): ValidationResult
  • validateRules(rules: Record<string, ValidationRuleConfig[]>): ValidationResult
  • addCustomRule(name: string, rule: CustomRule): void

ValidatorBuilder Class

Methods

  • setData(data: Record<string, any>): this
  • addField(field: string, rules: ValidationRuleConfig[]): this
  • setOptions(options: ValidatorOptions): this
  • setLanguage(language: string): this
  • build(): Validator
  • validate(): ValidationResult

Functional API

  • createPipe(rules, options): ValidationPipe
  • createTemplatePipe(template, options): ValidationPipe
  • pipe(...pipes): ValidationPipe
  • mapErrors(pipe, mapper): ValidationPipe
  • transformData(pipe, transformer): ValidationPipe
  • conditional(condition, truePipe, falsePipe?): ValidationPipe
  • mergePipes(...pipes): ValidationPipe
  • validateField(field, rules, options?): ValidationPipe
  • tap(pipe, callback): ValidationPipe
  • catchError(pipe, handler): ValidationPipe
  • withDefault(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;