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

shape-validate

v0.0.8

Published

A library to validate data, based on ajv, inspired by joi and superstruct.

Readme

Shape Validate

A library to validate data, based on ajv, inspired by joi and superstruct.

Features

  • Use ajv to compile validate function, so it's fast
  • Provides joi-like api, easy to use
  • Provides TypeScript types, useful for inferring type of validated data.
  • Deep clone data before validation, which can be turned off.
  • Use user-defined functions to customize validation
  • Use before/after methods to control validation order
  • Define new shape directly from JSON Schema

Quick Start

import { object, string, number } from "@xuanxiaodi/shape";

const shape = object({
  name: string(),
  age: number(),
});

shape.validateSync({ name: "Tom", age: "18" });
// { name: 'Tom', age: 18 }

await shape.validateAsync({ name: "Tom", age: "18" });
// { name: 'Tom', age: 18 }

Introduction

"Shape"

"Shape" is a wrapper for JSON Schema, with some options for combining into other shapes.

Usage

Validation

import { validateSync, validateAsync } from "shape-validate";

// use validate functions in this package
const validatedValue = validateSync(shape, inputValue);
const validatedValue = validateSync(shape, inputValue, false); // turn off deep clone
const validatedValue = await validateAsync(shape, inputValue);
const validatedValue = await validateAsync(shape, inputValue, false); // turn off deep clone

// use validate methods of shapes
const validatedValue = shape.validateSync(inputValue);
const validatedValue = shape.validateSync(inputValue, false); // turn off deep clone
const validatedValue = await shape.validateAsync(inputValue);
const validatedValue = await shape.validateAsync(inputValue, false); // turn off deep clone

Validate functions/methods will return the value after validate (value could be modified), or throw a validation error.

Basically, you can use validation functions if shape is an input value, use methods if shape is surely an instance of shape class.

Basic Shapes

import { any, boolean, date } from "shape-validate";

any(); // A shape with no limit
any().optional(); // Indicate value can be omitted in object
any().nullable(); // Indicate value can be null (if limited by type)
any().default("a"); // Set value to default value if it was undefined or null or empty string

String Shape

import { string } from "shape-validate";

string(); // A shape indicating value should be string
string().minLength(5); // Indicate string length limit
string().maxLength(20); // Indicate string length limit
string().pattern(/^\p{sc=Han}$/u); // Indicate string should match an regex.
string().format("email"); // Indicate string should in specific format.
string().trim().lowercase(); // Transform string before other validation

Number Shapes

import { number, integer } from "shape-validate";

number(); // A shape indicating value should be number
integer(); // A shape indicating value should be integer

number().range(5, 20); // Indicate value should between two values (inclusive)
number().min(5).max(20); // Equivalent
number().range(5, 20, true); // Indicate value should between two values (exclusive)
number().min(5, true).max(20, true); // Equivalent

Other Basic Shapes

import { boolean, date, enumerate, constant } from "shape-validate";

boolean();
date(); // A shape indicating value should be number or string for valid date
enumerate([1, 2, 3]);
constant(1);

Object Shape

import { object, number, string } from "shape-validate";

// Each property is required by default
object({ name: string(), age: number().optional() });

// Unknown properties will be striped, use keepUnknown() to keep them
object({ name: string() }).keepUnknown();

Array Shape

import { array, integer, string } from "shape-validate";

array(integer());
array(integer()).minSize(10);
array(integer()).maxSize(10);
array(integer()).unique();

Tuple Shape

import { tuple, integer } from "shape-validate";

const point2d = tuple(integer(), integer()); // (x, y)
const point3d = tuple(integer(), integer(), integer()); // (x, y, z)

const latlng = tuple(number().range(-90, 90), number().range(0, 360));

Custom Shape and Logic

import { custom } from "shape-validate";

const shape = custom<string>({ type: "string", minLength: 1 });

// these before/after methods is for any shape.
shape.beforeSync((value) => value + 1);
shape.afterSync((value) => value + 1);
shape.beforeAsync(async (value) => await findReference(value));
shape.afterAsync(async (value) => await findResult(value));

custom() return a shape object instead of shape instance, means you cannot use shape.validateSync(value) (but you can use this in validateSync(shape, value)).

Customize Error Messages

import { number, setKeywordMessage, setStaticMessage } from "shape-validate";

// Override error message for current field and any sub fields
number().message("验证失败");

// Override keyword error messages for current field only
number().range(1, 10).message({
  minimum: "必须大于等于1",
  maximum: "必须小于等于10",
  // "_" is for any other keywords, this will override sub field default error messages
  _: "验证失败",
});

// Override global default error messages
setStaticMessage("fallback", "验证失败");
setStaticMessage("rootRequired", "数据不能为空");

// Override global keyword error messages
setKeywordMessage("minimum", (path, params, schema) => {
  const name = schema.title || path || "值";
  return `${name}必须${params.exclusive ? "大于" : "大于等于"} ${params.limit}`;
});

i18n

import { setLocale } from "shape-validate";

// Set global error messages for Simplified Chinese
setLocale("zh-CN");

Built-in configurations:

  • en(English, the default one)
  • zh-CN(Simplified Chinese)

Type Coercing

These shape can be coerced from other values:

| shape | from | | --------- | --------------------------------- | | boolean() | 'true', 'false', 1, 0, '1', '0' | | number() | 12.34, 1234, 12.3e4 | | integer() | 1234 | | date() | ISO8601 Date-Time String |

Other conversion can be defined by beforeSync() or beforeAsync()