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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@awish10122004/validator

v1.0.1

Published

A validation library inspired by yup with support for string, number, boolean, bigint, date, null, and undefined types

Readme

My Validator

TypeScript validation library inspired by Yup, with a clear API, type coercion, and strong error handling. This README consolidates all docs and explains the concrete implementations across schema/, factories/, error/, and types/, plus the GoF patterns in use (Abstract Factory, Builder [fluent immutable], Composite, Template Method, Prototype).

Features

  • Type Schemas: string(), number(), boolean(), bigint(), date(), nullType(), undefinedType()
  • 🔄 Nullable & Optional: .nullable(), .optional(), .required(), .notRequired()
  • 🎯 Type Coercion: Built-in transforms, .strict() to disable coercion
  • Fluent API: Chain methods; immutable cloning under the hood
  • 🛡️ Type Safe: Strong TypeScript generics and narrowing
  • 🧩 Composite: ObjectSchema, ArraySchema validate nested structures
  • 🏭 Abstract Factory: Preconfigured factories for contexts (strict/lenient/db/prod)
  • 🧪 Custom Tests: Add rules with test(); custom transforms with transform()
  • 🚨 Robust Errors: ErrorHandler with aggregated field errors

Installation

npm install
npm run build

Quick Start

import { string, number, boolean, bigint, date } from "my-validator";

// String validation
const emailSchema = string().required().email();

await emailSchema.validate("[email protected]"); // ✅ Passes

// Number validation
const ageSchema = number().required().min(0).max(120).integer();

await ageSchema.validate(25); // ✅ Passes

// Boolean validation
const acceptedSchema = boolean().required().isTrue();

await acceptedSchema.validate(true); // ✅ Passes

API Reference

String Schema

string()
  .min(length: number)           // Minimum length
  .max(length: number)           // Maximum length
  .length(length: number)        // Exact length
  .matches(regex: RegExp)        // Pattern matching
  .email()                       // Email validation
  .url()                         // URL validation
  .trim()                        // Trim whitespace
  .lowercase()                   // Convert to lowercase
  .uppercase()                   // Convert to uppercase
  .required(message?: string)    // Non-null, non-undefined
  .nullable(message?: string)    // Allow null
  .optional(message?: string)    // Allow undefined
  .nonNullable(message?: string) // Disallow null
  .defined(message?: string)     // Disallow undefined

Number Schema

number()
  .min(value: number)           // Minimum value
  .max(value: number)           // Maximum value
  .lessThan(value: number)      // Strictly less than
  .moreThan(value: number)      // Strictly greater than
  .positive()                   // Must be positive
  .negative()                   // Must be negative
  .integer()                    // Must be integer
  .round()                      // Round to nearest integer
  .truncate()                   // Truncate to integer
  .required/.nullable/.optional/.nonNullable/.defined

Boolean Schema

boolean()
  .isTrue() // Must be true
  .isFalse(); // Must be false
// plus required/nullable/optional/nonNullable/defined

BigInt Schema

bigint()
  .min(value: bigint)           // Minimum value
  .max(value: bigint)           // Maximum value
  .lessThan(value: bigint)      // Strictly less than
  .moreThan(value: bigint)      // Strictly greater than
  .positive()                   // Must be positive
  .negative()                   // Must be negative
  // plus required/nullable/optional/nonNullable/defined

Date Schema

date()
  .min(date: Date)              // Minimum date
  .max(date: Date)              // Maximum date
  // plus required/nullable/optional/nonNullable/defined

Null and Undefined Types

import { nullType, undefinedType } from "my-validator";

nullType(); // Only accepts null
undefinedType(); // Only accepts undefined

Nullable and Optional

All schemas support nullable and optional modifiers:

// Nullable - accepts null
const schema1 = string().nullable();
schema1.validate(null); // ✅ Passes

// Optional - accepts undefined
const schema2 = number().optional();
schema2.validate(undefined); // ✅ Passes

// Required - rejects both null and undefined
const schema3 = string().required();
schema3.validate(null); // ❌ Fails
schema3.validate(undefined); // ❌ Fails

// Not Required - accepts both null and undefined
const schema4 = string().notRequired();
schema4.validate(null); // ✅ Passes
schema4.validate(undefined); // ✅ Passes

Type Coercion

By default, schemas attempt to coerce values to the correct type:

// Coercion enabled (default)
number().validate("42"); // ✅ Returns 42
boolean().validate("true"); // ✅ Returns true
date().validate("2023-12-13"); // ✅ Returns Date object

// Strict mode - no coercion
number().strict().validate("42"); // ❌ Fails - must be a number

Default Values

Set default values for undefined inputs:

const schema = string().default("default value");
schema.cast(undefined); // Returns 'default value'

// Function defaults
const schema2 = date().default(() => new Date());
schema2.cast(undefined); // Returns current date

Validation Methods

// Synchronous validation
schema.validateSync(value);

// Asynchronous validation
await schema.validate(value);

// Check validity without throwing
schema.isValidSync(value); // Returns boolean
await schema.isValid(value); // Returns Promise<boolean>

// Cast without validation
schema.cast(value);

// Add custom transform (runs during cast unless strict)
schema.transform((value) => /* transform */ value);

// Add custom test (runs during validate)
schema.test({
  name: "myRule",
  message: "Custom validation failed",
  test: (value) => /* boolean check */ true,
  skipAbsent: true, // optional; skip when value is null/undefined
});

Custom Tests

Add custom validation logic:

const schema = string().test({
  name: "customTest",
  message: "Custom validation failed",
  test: (value) => value !== "forbidden",
});

// Or shorthand
const schema2 = string().test(
  "customTest",
  "Custom error",
  (value) => value !== "forbidden"
);

Error Handling

import { ErrorHandler } from "my-validator";

try {
  await schema.validate(invalidValue);
} catch (error) {
  if (error instanceof ErrorHandler) {
    console.log(error.message); // summarised message or count
    console.log(error.value); // offending value
    console.log(error.type); // schema type name
    console.log(error.getFieldErrors()); // flat Record<path, message>
    console.log(error.getAllMessages()); // string[] of messages
  }
}

Implementation Details

Architecture & Internals

Conforms to a clean base-class design:

  1. Base Class Schema<TValue>: Core logic in [schema/Schema.ts]; subclasses implement type-specific checks and rules.
  2. Immutability via clone(): Each mutator returns a new instance; inMutationMode() enables batch mutable updates internally.
  3. Transform Pipeline: Coercion runs in cast() unless .strict(true).
  4. Validation Queue: Rules added via test() run after casting; skipAbsent helps optional/nullable flows.
  5. Spec Object: Flags like coerce, strict, nullable, optional, default, label drive behavior.

Key Methods

  • matchesType(v) — Type check honoring .nullable() / .optional()
  • clone(spec?) — Prototype-style cloning with spec override
  • label(label) — Attach a human-readable label for messages
  • inMutationMode(fn) — Temporarily allow internal mutation for setup
  • transform(fn) — Add a ValueTransformer
  • test(config) — Add a ValidationRule
  • cast(value) — Run transforms and apply defaults
  • validate(value) / validateSync(value) — Cast then test; throw ErrorHandler on failure
  • isValid(value) / isValidSync(value) — Return boolean; catch ErrorHandler
  • default(def) — Value or thunk used when input is undefined
  • strict(isStrict) — Disable transforms/coercion when true

Examples

Complex Validation

const userSchema = object({
  name: string().required().min(2),
  email: string().required().email(),
  age: number().required().positive().integer().max(120),
  website: string().url().nullable(),
  acceptTerms: boolean().required().isTrue(),
  accountValue: bigint().optional().positive(),
  createdAt: date().default(() => new Date()),
});

Dynamic Validation

const createSchema = (minAge: number) => {
  return number().required().min(minAge).integer();
};

const adultSchema = createSchema(18);
const seniorSchema = createSchema(65);

🏗️ Design Patterns (GoF)

The implementation uses the following core patterns, backed by the code in this repository:

1) Abstract Factory

Centralized creation of preconfigured schemas for different contexts (strict/lenient/db/prod) via factories/SchemaFactory.ts.

import {
  strictFactory,
  lenientFactory,
  databaseFactory,
  productionFactory,
} from "my-validator";

const strict = strictFactory();
const email = strict.createString().email().label("Email");
const id = strict
  .createString()
  .matches(/^[a-zA-Z0-9_-]+$/)
  .label("ID");

const form = lenientFactory();
const price = form.createNumber().positive().round().label("Price");

Internals: SchemaFactoryProvider (Singleton) caches StrictSchemaFactory, LenientSchemaFactory, DatabaseSchemaFactory, ProductionSchemaFactory.

2) Builder (Fluent Immutable)

Each method on Schema returns a new schema configured with the requested rule — an immutable builder style:

const passwordSchema = string()
  .min(8)
  .matches(/[A-Z]/)
  .matches(/[a-z]/)
  .matches(/[0-9]/)
  .required();

This provides step-by-step construction (builder) with fluent chaining while keeping instances immutable.

3) Composite

ObjectSchema (composite of field schemas) and ArraySchema (composite of item schema) validate nested structures by delegating to child schemas.

const userSchema = object({
  name: string().min(2).required(),
  tags: array(string()).min(1),
});

4) Template Method

Schema.validateSync() defines the validation algorithm (cast → type check → run tests). Subclasses like StringSchema, NumberSchema, etc. customize parts via type check and specific rule methods, but the overall control flow remains in the base class.

5) Prototype

Schema.clone() creates new instances copying configuration (spec, transforms, tests). Composite schemas also clone their inner members (ArraySchema.innerType, ObjectSchema.shape) when overriding clone().

Types & Internals

Located in types/common.ts:

  • ValueTransformer<T>(value: any) => any used by .transform()
  • ValidationRule<T>{ name?: string; message: string; test: (value: T | null | undefined) => boolean; skipAbsent?: boolean }
  • ValidationTest — runtime form of a rule

Error class in error/ErrorHandler.ts (bilingual comments):

  • Aggregates errors (errors: string[], inner: ErrorHandler[])
  • Static isError(err) type guard
  • Helpers: getFieldErrors() returning Record<string,string>, getAllMessages() returning string[]

Factories in factories/SchemaFactory.ts:

  • StrictSchemaFactory, LenientSchemaFactory, DatabaseSchemaFactory, ProductionSchemaFactory
  • SchemaFactoryProvider with helpers: strictFactory(), lenientFactory(), databaseFactory(), productionFactory()

Schemas in schema/:

  • StringSchema, NumberSchema, BooleanSchema, BigIntSchema, DateSchema, NullSchema, UndefinedSchema, ArraySchema, ObjectSchema
  • Common modifiers: .required(), .nullable(), .optional(), .nonNullable(), .defined(), .notRequired()
  • Selected rules per type (e.g., matches(), email(), url() on strings; numeric bounds on numbers; date bounds on dates; boolean truthiness; bigint bounds)

Index exports in src/index.ts:

  • Re-exports ErrorHandler
  • Types: ValidationRule, ValueTransformer, Optional
  • Helper types: InferTypeSchema
  • All schemas and creators from schema/index (string, number, boolean, bigint, date, nullType, undefinedType, array, object)

Helper types in types/object.helper.ts:

  • ObjectShape — map of field name → Schema
  • InferShape<TShape> — derive object output type from a shape
  • InferType<T> — derive type from a single Schema
  • InferTypeSchema<TSchema> — derive a fully prettified type including nested arrays/objects

Example:

import { object, string, number } from "my-validator";
import type { InferTypeSchema } from "my-validator";

const userSchema = object({
  name: string().required().min(2),
  age: number().required().min(0).integer(),
});

type User = InferTypeSchema<typeof userSchema>;
// User => { name: string; age: number }

Requirements Coverage

Mapped to REQUIREMENTS.md statements:

  • Notifications when data is invalid: ErrorHandler with aggregated messages and paths.
  • Combine validations: fluent chaining of multiple .test() and built-in rules.
  • Regular expressions: StringSchema.matches(regex).
  • Custom validation: Schema.test() accepts custom predicates.
  • Base classes for basic data types: concrete schemas in schema/.
  • Processing layer: validateSync() and validate() execute transforms and rules.
  • Declarative-style support: Abstract Factory presets and labels provide consistent configurations (TypeScript lacks runtime reflection; decorators not used here).

If you need attribute-based declarations (like .NET/Java), consider adding TypeScript decorators that translate metadata into schema construction — kept out-of-scope for this core library.

Try It

Build and run quick checks:

npm install
npm run build

Minimal usage in a Node REPL or script:

import { string, number, object, array, strictFactory } from "my-validator";

const schema = object({
  name: string().required().min(2),
  age: number().required().min(0).integer(),
  tags: array(string()).min(1),
});

schema.validateSync({ name: "An", age: 20, tags: ["dev"] });

// Use factories
const strict = strictFactory();
strict.createEmail().validateSync("[email protected]");