npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@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

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: '[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 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;