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 🙏

© 2024 – Pkg Stats / Ryan Hefner

moat-maker

v2.2.0

Published

Validate your runtime data with easy to pick up, TypeScript-inspired syntax.

Downloads

26

Readme

Moat Maker

Complete Documentation

Validate your runtime JavaScript data with easy to pick up, TypeScript-inspired syntax. It's as easy as:

npm i moat-maker
import { validator } from 'moat-maker';

// (This is just a small taste of the kind
// of expressive power this tool can provide)
const userValidator = validator`{
  username: string // required string property
  age?: number // optional number property
  dateOfBirth: string | ${Date} // must be a string or Date object
}`;

// ✓ - This is valid.
userValidator.assertMatches({
  username: 'cookieMonster42',
  dateOfBirth: new Date(1969),
});

// ✕ - Expected <receivedValue>.age to be of type "number"
//     but got type "string".
userValidator.assertMatches({
  username: 'elmo77',
  age: "it's a secret",
  dateOfBirth: new Date(1984),
});

If you use CommonJS instead of ES Modules (i.e. you use require(), or your TS compiled output uses require()), you'll need to instead install moat-maker-commonjs.

Moat Maker can be used anywhere where you might want to validate the correctness of your data, including:

  • User-input validation. Build a solid validation wall around your business logic to ensure your API users don't try and provide any bad inputs. Helpful auto-generated error messages will be provided to your API users so they can know what needs to be fixed. (If you find any particular error message isn't as helpful as you would like, please open an issue).
  • Validate HTTP responses, configuration, outputs from third-party libraries, etc, to make sure they all fit your expectations.
  • Write expressive assertions in your automated tests.

This project strives to follow a number of code-quality standards to keep the tool flexible and useful for anyone who needs it. For you, this means you can expect this project to be:

  • Lightweight: To keep out the bloat this project will be careful about what dependencies it chooses to drag in. Currently, this means it has zero dependencies. In the future, if there's demand for it, this project may be split up into smaller components that can be plugged together, allowing you to leave out the code from features you don't use.
  • Stable: Breaking changes are taken seriously. If, for whatever reason your codebase breaks after an update, please submit an issue so it can be addressed.
  • Fast: The results of parsing a template string will be cached, so you don't have to worry about the the performance penalty of defining your validators inside of functions vs outside. Attention has also been given to many other aspects of the validation process to try and keep it running smoothly. If you find validation to ever be the cause of significant performance issues in your application, please file an issue so it can be addressed.
  • Supported: Bugs, feature suggestions, or questions? Go ahead and start a discussion.
  • Open Source: This project is licensed under the MIT license. Feel free to do with it as you wish.

Why Moat Maker?

A number of existing runtime type-validation tools already exists in the JavaScript ecosystem, including:

  • Zod - build your schemas via function calls to produce both runtime validation and auto-built TypeScript types.
  • Ajv - validates the shape of your JSON data, using a schema defined in JSON. (similar to how XSD validates XML).
  • validator.js - Build your schema as a nested object, then validate your runtime data against that.
  • And many, many more. Google around and you'll find them.

So why make another?

Many of the existing type-validation tools tend to exhibit similar issues:

  • They can be cumbersome to use, due to the fact that they rely on function calls or nested object structures to define their schemas.
  • There's a higher learning curve associated with these tools because they have a fairly large and unfamiliar API surface area.

Moat Maker set out to solve both of these problems by requiring schemas to be defined, not by nested objects or function calls, but with TypeScript syntax - a syntax that many JavaScript developers are already familiar with. This greatly reduced the learning curve for this project (in fact, all you really need to know to get started can be found in the "Quick Start" section below). Due to the concise nature of TypeScript's syntax, your schemas will feel much more light-weight and simple to understand.

If Moat Maker's goals don't align with yours, feel free to take a look at the great work these other projects have done to see if they offer what you need. You may also be interested in ArkType, which has similar goals to Moat-Maker - it doesn't support quite as much TypeScript syntax, but it is capable of auto-generating TypeScript types from your schemas.

Quick Start

Moat Maker supports all of the major syntactic features from TypeScript's type syntax, including syntax support for arrays, tuples, objects, unions, intersections, and more. If you want to know which TypeScript features are supported, take a look at the overly detailed syntax reference, or just try it out and see what happens. Here's a quick taste of what is possible:

validator`{
  arrayOfStringsOrNumbers: (string | number)[]
  canBeMissingOrBoolean?: boolean | undefined
  mustBe42: 42
  aOneOrTwoLengthedTupleOfBooleans: [boolean, boolean?]
  stringToNumberMapping: { [index: string]: number }

  // Generic matching, like Set<string>, can't be supported the same way
  // it exists in TypeScript. Instead, iterable-matching syntax is
  // provided among other tools to fill this gap.
  // This is the only piece of syntax you'll find that isn't also
  // provided by TypeScript.
  mustBeASetThatYieldsStringsWhenIterated: ${Set}@<string>
}`

Additionally, because Moat Maker is built on template literals, you're allowed to interpolate runtime values you wish to match against. Interpolating different types of values will cause different matching behaviors to happen, for example:

// This can only be matched with the number `42`.
validator`${42}`.assertMatches(42);

// This will only accept an array of `true`s.
validator`${true}[]`.assertMatches([true, true, true]);

class Shape {}
// Passing in a class will require the user
// to provide an instance of the class.
validator`${Shape}`.assertMatches(new Shape());

// You can create more complicated validator
// instances by composing smaller ones.
const pointValidator = validator`{ x: number, y: number }`;
const lineValidator = validator`{
  start: ${pointValidator}
  end: ${pointValidator}
}`;

Finally, if you need a custom validation behavior that isn't supported by this library, the escape hatch is to create your own "expectations" using validator.expectTo(), then interpolating the resulting expectation instance wherever it is needed.

// If a string is returned, it'll be used as part of the error message.
// The strings should complete the sentence: "Expect the value to ..."
const expectGreaterThanZero = validator.expectTo(value => {
  if (typeof value !== 'number' || value <= 0) {
    return 'be a number greater than zero.';
  }
});

const validatePositivePoint = validator`{
  x: ${expectGreaterThanZero}
  y: ${expectGreaterThanZero}
}`;

// ✕ - Expected <receivedValue>.y, which was -2,
//     to be a number greater than zero.
validatePositivePoint.assertMatches({
  x: 2,
  y: -2,
});

Please refer to the docs for a more complete reference of what's possible. In the complete docs, you'll find information about what syntax is supported, what utility functions are provided, how you can customize parts of the error message if needed, and other, more-advance techniques this tool supports.