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

s-validator

v0.0.9

Published

[![NPM Version](https://img.shields.io/npm/v/s-validator)](https://www.npmjs.com/package/s-validator) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![TypeScript](https://img.shields.io/badge

Readme

NPM Version License: MIT TypeScript Zero Dependencies

s-validator

A simple, lightweight, and type-safe validation library for TypeScript and JavaScript.

s-validator provides a straightforward and declarative API for building validation schemas, ensuring your data conforms to the required structure and types without any external dependencies.

cover image

Table of Contents

Why s-validator?

In a sea of validation libraries, s-validator stands out by focusing on a few key principles:

  • Declarative, Configuration-Object API: Schemas are just plain JavaScript objects. This makes them easy to define, read, compose, and even serialize. No complex method chaining or builder patterns are needed.
  • Powerful Three-Phase Pipeline: The unique prepare -> validate -> transform pipeline provides a clear and robust mental model for handling data. It cleanly separates type coercion, validation, and output formatting, preventing cluttered and hard-to-maintain validation logic.
  • Async-First by Design: All validation is asynchronous from the ground up. This means you can easily add async validation rules (like checking a database for a unique username) without any special workarounds.
  • Zero Dependencies & Lightweight: s-validator is built to be lean and easy to integrate into any project without bringing in a large dependency tree.
  • Fully Type-Safe: Leverage the full power of TypeScript for excellent autocompletion, type inference, and compile-time error checking.

Core Concepts

s-validator operates on a unique three-phase validation pipeline for every schema. When you call parse() or safeParse(), your data flows through these steps in order, giving you granular control over the entire process.

graph TD
    A[Input Data] --> P["<b>1. Preparation</b><br>Coerce types<br>Trim strings<br>Apply defaults"];
    P --> V["<b>2. Validation</b><br>Check lengths/ranges<br>Validate formats (email, URL)<br>Run custom rules"];
    V --> T["<b>3. Transformation</b><br>Change data shape<br>Format values<br>Add or remove fields"];
    T --> O[Output Data];

    style P fill:#f9f9f9,stroke:#333,stroke-width:2px,color:#333
    style V fill:#f9f9f9,stroke:#333,stroke-width:2px,color:#333
    style T fill:#f9f9f9,stroke:#333,stroke-width:2px,color:#333
  1. Preparation: The raw input is recursively traversed, and preparation functions are run. This is ideal for coercing data into the correct type before validation, such as converting a Date string to a Date object or trimming a string.

  2. Validation: The prepared data is recursively validated against the rules defined in your schema (e.g., minLength, min, email). If any validation fails, the process stops and returns an error.

  3. Transformation: After the data has been successfully validated, it is recursively transformed into its final output shape. This is useful for formatting data, such as converting a Date object back to a formatted string or adding a computed property.

Getting Started

First, install s-validator in your project:

pnpm add s-validator
# or
npm install s-validator
# or
yarn add s-validator

Next, define a schema. Let's create one for a User that has a contact field, which can be either an email or a phone number.

import { s } from "s-validator";

// Define a schema with the new configuration-object syntax
const userSchema = s.object({
  // Top-level configurations
  transform: {
    custom: [(user) => ({ ...user, name: user.name.toLowerCase() })],
  },

  // Validation logic is nested under the 'validate' key
  validate: {
    properties: {
      name: s.string({
        validate: { minLength: 2 },
      }),
      contact: s.union({
        // The union validator can also have top-level configs
        // for preparations, transformations, or custom error messages.
        validate: {
          of: [
            s.string({ validate: { email: true } }),
            s.string({ validate: { pattern: /^\d{10}$/ } }),
          ],
        },
      }),
      createdAt: s.date({
        prepare: { coerce: true }, // Coerce string/number to Date
        optional: true, // This field can be omitted
      }),
    },
  },
});

// Use `s.infer` to extract the TypeScript type
type User = s.infer<typeof userSchema>;
// type User = {
//   name: string;
//   contact: string;
//   createdAt?: Date | undefined
// }

async function safeValidateUser(data: unknown) {
  const result = await userSchema.safeParse(data);

  if (result.status === "success") {
    console.log("User is valid:", result.data);
    return result.data;
  }

  // The error object contains detailed information about what went wrong
  console.error("Validation failed:", result.error.issues);
  // Example error:
  // [
  //   {
  //     "path": [ "name" ],
  //     "message": "minLength must be greater than or equal to 2, but received 1"
  //   }
  // ]
}

// Example Usages
safeValidateUser({
  name: "John Doe",
  contact: "[email protected]",
});

safeValidateUser({
  name: "J", // Too short
  contact: "not-a-valid-contact",
});

Advanced Example: Recursive Schemas

s-validator supports recursive schemas out of the box using getters. This is useful for validating nested data structures like file system trees or comments with replies.

Here's how you can define a schema for a file system entry, where a directory can contain more entries:

import { s } from "s-validator";

interface File {
  type: "file";
  name: string;
  size: number;
}

interface Directory {
  type: "directory";
  name: string;
  children: (File | Directory)[];
}

type FileSystemEntry = File | Directory;

const fileSchema = s.object({
  validate: {
    properties: {
      type: s.literal("file"),
      name: s.string(),
      size: s.number(),
    },
  },
});

const directorySchema: s.ObjectSchema<any, Directory> = s.object({
  validate: {
    properties: {
      type: s.literal("directory"),
      name: s.string(),
      // Use a getter to reference the 'entrySchema' which is defined later
      get children() {
        return s.array({ validate: { of: entrySchema } });
      },
    },
  },
});

const entrySchema = s.switch<FileSystemEntry>({
  validate: {
    on: "type",
    of: {
      file: fileSchema,
      directory: directorySchema,
    },
  },
});

// Example of a valid tree
const fileSystemTree = {
  type: "directory",
  name: "root",
  children: [
    { type: "file", name: "file1.txt", size: 100 },
    {
      type: "directory",
      name: "subdir",
      children: [{ type: "file", name: "file2.txt", size: 200 }],
    },
  ],
};

async function validateTree() {
  const result = await entrySchema.safeParse(fileSystemTree);
  console.log(result.status); // 'success'
}

validateTree();

Documentation

For a complete guide to all features and validators, check out the full documentation.

Contributing

Contributions are welcome! Please feel free to submit a pull request or open an issue.

License

This project is licensed under the MIT License.