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

@knno/valid

v1.4.0

Published

A simple data validation toolkit.

Readme

@knno/valid

Description

A TypeScript/JavaScript validation toolkit.

Installation

npm i @knno/valid

What this validation tool can do?

  • Validate user-provided data early without putting validation logic in business code
  • Structured validation rules enable automatic API documentation generation
  • TypeScript support with type inference
  • Customizable error messages
  • Composable and reusable validation rules

Getting Started

import {Schema, string} from '@knno/valid';

// 1. Define validation rule
const rule = string(min(10), max(100));

// 2. Create validator
const schema = new Schema(rule);

// 3. Validate data
try {
  schema.validate('Hello World!'); 
} catch (e) {
  console.log(e.message); // Handle validation error
}

Major Rule Definitions

  1. need()
// input can not be undefined or null
let rule = need();
// input can not be undefined or null and it must be a string 
let rule = need(string());
// must be a number
let rule = need(number())
// must be a string or a number
let rule = need(union(string(), number()));
...

need rule can only have primitive rule as it's sub rule, all supported sub rules are:

object, string, number, array, boolean, date, union
  1. string()
// input should be a string, but if input not provide or it is null, it won't be regarded as error.
let rule = string();
// must be a string and cannot be null or undefined
let rule = need(string());
// string length must at least have 10 characters
let rule = string(min(10));
// string length must at most have 100 characters
let rule = string(max(100));
// string must match the regular expression
let rule = string(match(/^\d+$/));
// string must be a particular value
let rule = string(equal('abc'));
// verfication successful if all of the following conditions are met
let rule = string(min(10), max(100));
// verfication successful if any of the following conditions are met
let rule = string(any(equal('abc'), equal('def'), min(10), pattern(/^\d+$/)));
...
  1. number()
let rule = number();
// value should great or equal to 10
let rule = number(min(10));
// value should great to 10
let rule = number(more(10));
// value should less or equal to 100
let rule = number(max(100));
// value should less 100
let rule = number(less(100));
let rule = number(range(10, 100));
let rule = number(equal(33));
let rule = number(any(equal(33), equal(44), equal(55)));
  1. boolean()
let rule = boolean();
let rule = boolean(equal(true));
  1. date()
let rule = date();
let rule = date(equal('2019-1-1'));
let rule = date(begin('2019-1-1'));
let rule = date(end('2020-1-1'));
let rule = date(before('2020-1-1'));
let rule = date(after('2019-1-1'));
let rule = date(between('2019-1-1', '2020-1-1'));
let rule = date(any(before('2019-1-1', between('2020-3-1', '2020-5-1'))));
  1. object()
let rule = object();
let rule = object(
  prop('name', string()),
  prop('age', number()),
  prop('extra', need()),
  prop('detail', need(
    object(
      prop('id', need(number())),
      prop('account', need(string()))
    )
  ))
);
  1. array()
let rule = array();
let rule = array(
  item(need(
    union(
      object(
        prop('id', need(number())),
        prop('account', need(string()))
      ),
      string()
    )
  )),
  min(10), max(20)
);
  1. union()

That's means value can be multiple types.

let rule = union(string(), number());
...
  1. any() and all()

This two rules can combine a group of sub rules to reach more complex condition check.

let rule = string(any(min(10), all(pattern(/^A/), min(5))));
  1. not()

Makes the match condition negated! (can only have one sub rule)

let rule = string(any(min(10), not(match(/^A/))));
let rule = string(not(any(min(10), match(/^A/))));
let rule = string(not(all(min(10), match(/^A/))));

Above expression means either the string greater or equals to 10 character length or greater or equal to 5 character length and starts with character 'A'.

Rename Rule Name

You can rename any rule name as what your like, this usually can shorten your code:

import {Schema, string as s, number as n, need as r, object as o, prop as p} from '@knno/valid';

let rule = r(o(
  p('name', r(s(min(1), max(30)))),
  p('age', r(n(min(18))))
));

Split Definition

To make the code clearly, usually you can split a complex definition to several parts:

let detail = need(object(
  prop('name', need(string())),
  prop('account', need(string())),
));
let users = need(array(
  item(detail),
  min(1), max(1000)
));
let rule = need(object(
  prop('action', need(string())),
  prop('users', users)
));
try {
  let schema = new Schema(rule);
  schema.validate({
    action: 'show',
    users: [{
      name: 'user 1',
      account: 'account1'
    },{
      name: 'user 2',
      account: 'account2'
    }]
  });
} catch (e) {
  console.log(e.message);
}

Specify Custom Message

  1. mismatch()

There have a particular rule mismatch(), it can under the primitive type rule used to specify error message when input type doesn't match the expected type.

let rule = string(mismatch('There need a string'));
  1. need()
let rule = need(object(), 'use custom message');
  1. Other check rules

Any check rules can accept a string as last parameter as custom message.

let rule = string(max(20, 'String length cannot be more than 20 characters'));

Simplified type definition syntax

The define() function allows creating validation rules with type inference:

import { define, req, obj, str, num } from '@knno/valid';

// Define both type and validation rules
const userType = define(() =>
  req(obj({
    name: req(str(min(3))),
    age: req(num())
  }))
);

// Use inferred type
const user: typeof userType.type = {
  name: "John",
  age: 30
};

// Create validator
const validator = new Schema(userType.rule);

Integration with @knno/web

Seamless integration with @knno/web framework for API parameter validation:

import { define, num, obj, str, req } from '@knno/valid';
import { DefaultContext, query, title, result, desc } from '@knno/web';

// Parameter definition
const paramsDef = define(() =>
  req(obj({
    id: req(num())
  }))
);

// Request body definition
const bodyDef = define(() =>
  req(obj({
    field1: req(str(min(3))),
    field2: req(num())
  }))
);

@title('Sample API')
export default class SampleController {
  @desc('API description...')
  @query(paramsDef)
  @result('None')
  async post(ctx: DefaultContext): Promise<void> {
    const params = ctx.getParams(paramsDef);
    const payload = ctx.body.json(bodyDef);
    // Use validated parameters...
  }
}

See @knno/web

NOTE:

Usually we don't need to specify any custom message, because the builtin error message will provide more detailed info.


That's all

If you find any problem please feel free to report to issues, I would appreciate your contribution.