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

yeval

v0.3.0

Published

Dead simple javascript validation

Downloads

28

Readme

yeval

<yktv4>

Dead simple JavaScript schema validation.

Example

// Require the main `validate` function and the rules you'll need
const {
  validate,
  rules: {
    isString,
    minLength,
    sameAs,
  },
} = require('yeval');

// Run the `validate` function with the rules against the target object to get the errors object
const errors = await validate(
  {
    userName: [isString, minLength(1)],
    password: [isString, minLength(6)],
    repeatPassword: [isString, minLength(6), sameAs('password')],
  },
  {
    userName: 'Mark',
    password: 'somePassword',
    repeatPassword: 'someOtherPassword',
  }
);

console.log(errors); // { repeatPassword: 'Must match password' }

Concept

Any validation rule is a function that returns an error string in case validation fails. Any validation function is provided with three arguments:

  • value -- value of an attribute this rule is declared for
  • data -- the whole object that is being validated
  • path -- path in data to currently validated value

Here's the simplest validation rule possible:

const required = value => {
  if (!value) {
    return 'Required';
  }
};

// Let's apply our rule against a null value:
const error = required(null);
console.log(error); // we get a string 'Required' as a result

Yeval is just a tool that runs such validation functions for you and allows to combine them in an eloquent fashion!

Some aspects

  • yeval is Promise-based meaning validate function always returns a Promise. Even for synchronous rules.
  • Successful validation resolves with undefined.
  • Failed validation resolves with a plain object that contains error string for every attribute that failed a validation.
  • Rejection of promise occurs only on runtime errors.
  • yeval returns only the first error for each object's attribute.
  • Validation of the next object's attribute will start only after the previous attribute was validated.
  • Rules for each attribute are executed from left to right. Each next rule waits until the previous one finishes. Even if rule is asynchronous.
  • All built-in rules assume value is of proper type for that rule. Build your validation rules list in order of increasing strictness. i.e. validating null against isEmail would result in runtime error since isEmail assumes value is a string. Proper validation for this case is [isString, isEmail].

More examples

  • Conditional validation

Use when to build conditions whether to apply any validation rules.

const {
  validate,
  util: {
    when,
  },
  rules: {
    isBoolean,
    isEmail,
  },
} = require('yeval');

const optedInForNewsletter = (value, data) => data.optedInForNewsletter === true;

const errors = await validate(
  {
    optedInForNewsletter: isBoolean,
    email: when(optedInForNewsletter, isEmail),
  },
  {
    optedInForNewsletter: true,
  }
);

console.log(errors);  // { email: 'Must be a valid email address' }
  • Custom validation rules

Writing your own validation rules in the simplest way possible. Just define a function.

const {
  validate,
  rules: {
    isEmail,
  },
} = require('yeval');

const isGmailAccount = (value) => {
  if (value.slice(-9) !== 'gmail.com') {
    return 'Sorry, we only accept gmail accounts';
  }
};

const errors = await validate(
  {
    email: [isEmail, isGmailAccount],
  },
  {
    email: '[email protected]',
  }
);

console.log(errors); // { email: 'Sorry, we only accept gmail accounts' }
  • Custom error messages

Use msgFor for custom error messages if rule fails.

const {
  validate,
  util: {
    msgFor,
  },
  rules: {
    isEmail,
  },
} = require('yeval');

const errors = await validate(
  {
    email: msgFor(isEmail, 'We need your email address. We really do.'),
  },
  {
  email: 'notAnEmail',
  }
);

console.log(errors); // { email: 'We need your email address. We really do.' }
  • Validation of nested objects

Supply an object as a rule for an attribute if you want to validate nested object

const {
  validate,
  rules: {
    isString,
    oneOfArray,
  },
} = require('yeval');

const errors = await validate(
  {
    car: {
      make: [isString, oneOfArray(['BMW', 'Mercedes', 'Audi'])],
    },
  },
  {
    car: {
      make: 'Boeing',
    },
  }
);

console.log(errors); // { car: { make: 'Must be one of: BMW, Mercedes, Audi' } }
  • Async validation

Any validation rule can be a promise that resolves with an error string in case of failure.

const {
  validate,
  rules: {
    isEmail,
  },
} = require('yeval');

const isUniqueEmail = (value) => {
  return User.where({ email: value }).exists().then(exists => {
    if (exists) {
      return 'Email you supplied is already registered';
    }
  });
};

const errors = await validate(
  {
    email: [isEmail, isUniqueEmail],
  },
  {
    email: '[email protected]',
  }
);

console.log(errors); // { email: 'Email you supplied is already registered' }
  • Optional validation

All built-in rules assume the value is defined by default. So to optionally apply any rule you can use when(isDefined, rule) construction.

const {
  validate,
  util: {
    when,
    isDefined,
  },
  rules: {
    isString,
    isEmail,
  },
} = require('yeval');

const errors = await validate(
  {
    email: when(isDefined, [isString, isEmail]),
  },
  {}
);

console.log(errors); // undefined
  • Compose rules in any way you need.

Since rule is just a function you can easily compose them in no particular order.

const {
  validate,
  util: {
    when,
    isDefined,
    msgFor,
  },
  rules: {
    isString,
    isEmail,
    oneOfArray,
  }
} = require('yeval');

const validAudiModels = ['A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8'];
const isAudi = (value, data) => data.car.make === 'Audi';

const errors = await validate(
  {
    email: when(isDefined, [msgFor(isString, 'Hey, we need a string!'), isEmail]),
    car: when(isDefined, {
      make: isString,
      model: when(isAudi, msgFor(oneOfArray(validAudiModels), 'This is not a valid audi model!')),
    }),
  },
  {
    email: '[email protected]',
    car: {
      make: 'Audi',
      model: 'A3',
    },
  }
);

console.log(errors); // undefined

Docs

Docs are available here.

License (MIT)