A small, simple and fast JS validator. Like, wow thats fast. π
Nope is heavily inspired stolen from Yup but Nope attempts to be much smaller and much faster. To achieve this Nope only allows for synchronous data validation which should cover most of the use cases.
Note that instead of throwing errors Nope simply returns the error object and if there are no errors it returns undefined.
Typescript definitions included. π
To start using Nope simply do
yarn add nope-validator
or
npm install -S nope-validator
// const Nope = require('nope-validator'); // or
// const { Nope } = require('nope-validator'); // or
import Nope from 'nope-validator';
// create a schema
const UserSchema = Nope.object().shape({
name: Nope.string()
.min(5, 'Please provide a longer name')
.max(255, 'Name is too long!'),
email: Nope.string()
.email()
.required(),
confirmEmail: Nope.string()
.oneOf([Nope.ref('email')])
.requried(),
});
UserSchema.validate({
name: 'John',
email: '[email protected]',
confirmEmail: '[email protected]',
}); // returns an error object { name: 'Please provide a longer name '};
UserSchema.validate({
name: 'Jonathan Livingston',
email: '[email protected]',
confirmEmail: '[email protected]',
}); // returns undefined since there are no errors
-
Primitives
(String, Number, Date, Boolean)-
when(key: string | string[], conditionObject: { is: boolean | ((...args: any) => boolean), then: NopeSchema, othervise: NopeSchema })
- Conditional validation of a key. -
The first param is the set of keys (or a single key) that the
is
predicate should run on. -
The
is
param can be set to simply true or false (which will run the .every method on the values and assert the against the passedis
) or a predicate that will decide what schema will be active in that moment. -
const schema = Nope.object().shape({ check: Nope.boolean().required(), test: Nope.string().when('check', { is: true, then: Nope.string() .min(5, 'minError') .required(), otherwise: Nope.string() .max(5) .required(), }), }); schema.validate({ check: true, test: 'test', }); // { test: 'minError' } // or as a predicate const schema2 = Nope.object().shape({ check: Nope.boolean(), check2: Nope.boolean(), test: Nope.string().when(['check', 'check2'], { is: (check, check2) => check && check2, then: Nope.string() .min(5, 'minError') .required(), otherwise: Nope.string() .max(5) .required(), }), }); schema.validate({ check: true, check2: false, test: 'testing', }); // { test: 'maxError' }
-
oneOf(options: string | ref[], message: string)
- Asserts if the entry is one of the defined options -
Nope.string() .oneOf(['a', 'b', 'c']) .validate('b'); // returns undefined Nope.string() .oneOf(['a', 'b', 'c']) .validate('d'); // returns the error message
-
required(message: string)
- Asserts if the entry is not nil -
Nope.string() .required() .validate('b'); // returns undefined Nope.string() .required() .validate(); // returns the error message
-
test(rule: (entry: string) => string | undefined)
- Add a custom rule -
Nope.string() .test(a => (a === '42' ? undefined : 'Must be 42')) .validate('42'); // returns undefined Nope.string() .test(a => (a === '42' ? undefined : 'Must be 42')) .validate('41'); // returns the error message
-
validate(entry: string | undefined | null)
- Runs the rule chain against an entry
-
-
String
-
regex(regex: RegExp, message: string)
- Asserts if the entry matches the pattern -
Nope.string() .regex(/abc/i) .validate('abc'); // returns undefined Nope.string() .regex(/abc/i) .validate('123'); // returns the error message
-
url(message: string)
- Asserts if the entry is a valid URL -
Nope.string() .url() .validate('http://google.com'); // returns undefined Nope.string() .url() .validate('http:google.com'); // returns the error message
-
email(message: string)
- Asserts if the entry is a valid email -
Nope.string() .email() .validate('[email protected]'); // returns undefined Nope.string() .email() .validate('testgmail.com'); // returns the error message
-
min(length: number, message: string)
- Asserts if the entry is smaller than a threshold -
Nope.string() .min(4) .validate('https'); // returns undefined Nope.string() .min(4) .validate('http'); // returns the error message
-
max(length: number, message: string)
- Asserts if the entry is greater than a threshold -
Nope.string() .max(4) .validate('url'); // returns undefined Nope.string() .max(4) .validate('http'); // returns the error message
-
-
Number
-
min(size: number, message: string)
- Asserts if the entry is smaller than a threshold -
Nope.number() .min(1, 'error message') .validate(2); // returns undefined Nope.number() .min(1, 'error message') .validate(1); // returns the error message
-
max(size: number, message: string)
- Asserts if the entry is greater than a threshold -
Nope.number() .max(1, 'error message') .validate(-1); // returns undefined Nope.number() .max(1, 'error message') .validate(2); // returns the error message
-
positive(message: string)
- Asserts if the entry is positive -
Nope.number() .positive('error message') .validate(42); // returns undefined Nope.number() .positive('error message') .validate(-42); // returns the error message
-
negative(message: string)
- Asserts if the entry is negative -
Nope.number() .negative('error message') .validate(-42); // returns undefined Nope.number() .negative('error message') .validate(42); // returns the error message
-
-
Date
-
before(date: string | number | Date, message: string)
- Asserts if the entry is before a certain date -
Nope.date() .before('2019-01-01') .validate('2018-31-12'); // returns undefined Nope.date() .before('2019-01-01') .validate('2019-01-02'); // returns the error message
-
after(date: string | number | Date, message: string)
- Asserts if the entry is after a certain date -
Nope.date() .after('2019-01-01') .validate('2018-02-01'); // returns undefined Nope.date() .after('2019-01-01') .validate('2018-31-12'); // returns the error message
-
-
Boolean
-
true(message: string)
- Asserts if the entry is true -
Nope.boolean() .true() .validate(true); // returns undefined Nope.boolean() .true() .validate(false); // returns the error message
-
false(message: string)
- Asserts if the entry is false -
Nope.boolean() .false() .validate(false); // returns undefined Nope.boolean() .false() .validate(true); // returns the error message
-
-
Object
-
shape(shape: object)
- Sets the shape which of the object. Use name as keys and Nope validators as values -
const schema = Nope.object().shape({ name: Nope.string() .max(15) .required(), email: Nope.string() .email('Please provide a valid email') .required(), }); const errors = schema.validate({ name: 'Test', email: 'invalidemail', }); console.log(errors); // { email: 'Please provide a valid email', }
-
extend(Base: NopeObject)
- Extends the schema of an already defined NopeObject -
const baseSchema = Nope.object().shape({ password: Nope.string().min(5), confirmPassword: Nope.string() .oneOf([Nope.ref('password')], "Passwords don't match") .required(), }); const userSchema = Nope.object() .extend(baseSchema) .shape({ name: Nope.string() .min(4) .required(), }); userSchema.validate({ name: 'Jonathan', password: 'birdybird', confirmPassworod: 'burdyburd', }); // returns { confirmPassword: 'Passwords don\'t match' }
-
validate(entry: object)
- Runs the rule chain against an entry
-
-
Reference
- allows the schema to reference other values in the provided entry-
const schema = Nope.object().shape({ email: Nope.string() .email() .max(255) .required(), confirmEmail: Nope.string().oneOf([Nope.ref('email')], 'Must match the first email'), }); const errors = schema.validate({ email: '[email protected]', confirmEmail: '[email protected]', }); console.log(errors); // { confirmEmail: 'Must match the first email' } const noerrors = schema.validate({ email: '[email protected]', confirmEmail: '[email protected]', }); console.log(noerrors); // undefined
-
Usage with Formik
Instead of passing it through the validationSchema
prop, you should call Nope's validate on the validate
prop as shown in the example below.
const schema = Nope.object().shape({
email: Nope.string()
.email()
.max(255)
.required(),
password: Nope.string()
.min(8)
.max(64)
.required(),
});
<Formik
initialValues={{ email: '', password: '' }}
validate={values => schema.validate(values)}
onSubmit={values => console.log('Submitted', values)}
>
{() => (
<Form>
<Field type="email" name="email" />
<ErrorMessage name="email" component="div" />
<Field type="password" name="password" />
<ErrorMessage name="password" component="div" />
<button type="submit">Submit</button>
</Form>
)}
</Formik>;
nope x 941,878 ops/sec Β±0.37% (94 runs sampled)
yup x 6,566 ops/sec Β±3.24% (90 runs sampled)
I'll add tests against other validation libraries as well.
The benchmark results can be found in the benchmark/
folder along with the specs and the code that was used for the benchmark.