Giter VIP home page Giter VIP logo

v8n's Introduction

v8n

The ultimate JavaScript validation library you've ever needed.
Dead simple fluent API. Customizable. Reusable.

Build npm version npm bundle size (minified + gzip)

Installation - Documentation - API

Buy Me A Coffee

Introducing v8n

v8n is an acronym for validation. Notice that it has exactly eight letters between v and n in the "validation" word. This is the same pattern we are used to seeing with i18n, a11y, l10n ...

Chainable API

Create validations very easily with its chainable API:

v8n()
  .string()
  .minLength(5)
  .first("H")
  .last("o")
  .test("Hello"); // true

Incredibly fluent

Mix rules and modifiers together to create complex validations with great ease and fluency:

v8n()
  .array()
  .every.number()
  .not.some.negative()
  .test([1, 2, -3]); // false - no negative please!

So fluent that it looks like English:

v8n()
  .some.not.uppercase() // expects that some character is not uppercase
  .test("Hello"); // true

v8n()
  .not.some.uppercase() // expects that no character is uppercase
  .test("Hello"); // false

Notice how we made very different validation strategies just by changing the order of the modifiers. It's so intuitive that seems to be impossible, but this is v8n.

Customizable

Create your own custom validation rules in a very intuitive way:

function foo() {
  return value => value === "bar";
}

v8n.extend({ foo });

v8n will treat them like built-in ones:

v8n()
  .string()
  .foo()
  .test("bar"); // true

Reusable

Export validations just like you're used to do with your JavaScript modules:

specialNumber.js

import v8n from "v8n";

export default v8n()
  .number()
  .between(50, 100)
  .not.even();

and use them anywhere you want:

import specialNumber from "../specialNumber";

specialNumber.test(63); // true

For any kind of data

Use v8n to validate your data regardless of its type. You can validate primitives, arrays, objects and whatever you want! You can also use them together!

// numbers
v8n()
  .number()
  .between(5, 10)
  .test(7); //true

// strings
v8n()
  .string()
  .minLength(3)
  .test("foo"); // true

// arrays
v8n()
  .array()
  .every.even()
  .test([2, 4, 6]); // true

// objects
const myData = { id: "fe03" };

v8n()
  .schema({
    id: v8n().string()
  })
  .test(myData); // true

For any kind of validation

Do simple validations with boolean based tests. Get more information about your validation process with exception based tests. And of course, perform asynchronous tests as well. All in one library.

Boolean based validation:

v8n()
  .string()
  .first("H")
  .test("Hello"); // true

Exception based validation:

try {
  v8n()
    .string()
    .first("b")
    .check("foo");
} catch (ex) {
  console.log(ex.rule.name); // first
}

Getting all failures:

const failed = v8n()
  .string()
  .minLength(3)
  .testAll(10);

failed;
// [
//   ValidationError { rule: { name: "string", ... } },
//   ValidationError { rule: { name: "minLength", ... } }
// ]

Async validation:

If your validation strategy has some rule that performs time consuming validation, like a back-end check, you should use asynchronous validation:

v8n()
  .somAsyncRule()
  .testAsync("foo") // returns a Promise
  .then(result => {
    /* valid! */
  })
  .catch(ex => {
    /* invalid! */
  });

Shareable

Share your rules with the world, and use theirs as well.

Create useful validation rules and share them with the open source community, and let people around the world validate without reinventing the wheel.

Ready to use!

There are a lot of built-in rules and modifiers for you to use already implemented in v8n's core. Take a look at all of them in our API page. But if you can't find what you need, go ahead and make it.

Tiny!

All these incredible features for just a few bytes:

npm bundle size (minified + gzip)

Architecture

The v8n core is composed of rules and modifiers. They are used together to build complex validations in an easy way.

Rules

Rules are the heart of the v8n ecosystem. You use them to build your validation strategies:

v8n()
  .string()
  .minLength(3)
  .test("Hello"); // true

In this code snippet, we're using two rules (string and minLength) to build our validation strategy. So our validated value ("Hello") is valid because it's a string and it is at least 3 characters long.

Rules can be more powerful if used along with modifiers. Learn about them in the next section.

Modifiers

Modifiers can be used to change rules meaning. For example, you can use the not modifier to expect the reversed result from a rule:

v8n()
  .not.equal(5)
  .test(5); // false

You can check all available modifiers on our documentation page.

Modifiers are very powerful. They work as decorators for rules. When used together, they allow you to build very complex validations.

Contribute

Contributions of any kind are welcome! Read our CONTRIBUTING guide.

License

MIT License

v8n's People

Contributors

akarel avatar dependabot[bot] avatar evanwinter avatar havelaer avatar imbrn avatar jgpacheco avatar jonathanhawleypeters avatar panstav avatar seung-hwan285 avatar tomraithel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

v8n's Issues

.every and testAll shows a wrong cause of error

The Problem
When you testAll some data (array), it shows that it failed because TypeError: split(...).every is not a function
image

The expected behavior
The cause should be because that one of models was not good according to the schema.

Code:

var v8n = require('v8n');

const goodData = [{
    a: 'adasda'
}, {
    a: 'badassdd'
}];

const badData = [{
    a: 'adasda'
}, {
    a: 123
}];

const sampleSchema = {a: v8n().string()}

var badDataValidationError = v8n().every.schema(sampleSchema).testAll(badData);

console.log(badDataValidationError);

var goodDataValidationError = v8n().every.schema(sampleSchema).testAll(goodData);

console.log(goodDataValidationError);

Test for valid numbers

Unfortunately v8n().number().test(NaN) returns true, which while technically correct according to JavaScript is usually not what you want.

A few options:

  • Have number return false for NaN.
  • Have another not.nan() check.
  • Have a finite() check which returns false for NaN, Infinity, and -Infinity.

Add rule "optional"

This is a simple rule but that can add a lot of flexibility to the library.

It should be a composite rule. It must get a validation as input and should pass when this validation passes or when the validated value is not defined (null or undefined).

const validation = v8n()
  .optional(
    v8n().number().positive()
  );

validation.test(-1); // false
validation.test(1); // true
validation.test(null); // true

Note: its implementation should use check instead of test to provide better error handling.

ValidationException should be called ValidationError

This looks odd in the README:

failed;
// [
//   ValidationException { rule: { name: "string", ... } },
//   ValidationException { rule: { name: "minLength", ... } }
// ]

An array of exception doesn't make sense. These should be called ValidationError since that is what they are. This would also be in line with JavaScript's own naming, where Errors and not Exceptions are thrown. This is fairly unique in JS, but in this case it makes sense to use Error.

Simplify built in rule declarations

Right now the built in rule declarations are an absolute code mess. There are many complex helper function chains and some of them are done in line. I would argue the best approach is to define them all in line, since most of them can be simple one-liners. This would clean the code-base a lot.

The output size would need to be compared to the current, since there would be some duplicate code. But to be fair, some of the helper functions have very complex implementations and if checks that can be omitted when writing inline.

This would cause no change in any API and could be part of 1.2.0.

JSON Schema

Hi Sebastian.

I like v8n, simple and light. I'm trying to use v8n with Fastify framework upon request validation.

How to make v8n outputs a JSON Schema compatible object?

As explained here, but I'd like to use v8n instead of Joi.

Thanks a lot.

Reporting everything that's wrong with my value

Disclaimer: I haven't used the library but find it very interesting. I'd like to know everything that is wrong with my value instead of taking the fail-fast approach. I would expect to receive an array of Is there a way of doing that?

For example:

v8n()
  .number()
  .between(0, 100)
  .even()
  .test(133);

could result in something like

{
  errors: [ 'even', 'range' ]
}

In that case, I could tell my user that their number must be even and exceeds the predefined range.

Test to validate that two fields of a schema are equals

It would be nice if we could check that two fields are equals. Something like that :

v8n().schema({
  password: v8n().string().minLength(8).maxLength(40),
  confirmPassword: v8n().equalTo('password')
})

What do you think about ?

Include string holding a number in examples

Wonderful library, thank you.

I had a poke around but didn't find anything for this. A common use case for this library is probably validating user input that comes in the form of strings.

v8n().number().test('23')
v8n().integer().test('23')

are both rightly false. But what's the appropriate way to test if a string contains a number/integer? It feels wrong to add a pre-validation validation step where we attempt to convert to an int and handle as a validation failure if it doesn't. But perhaps that's the intended usage. Or maybe I just missed it.

Thanks!

Date validation

A very useful rule would be to provide date validation, where you could specify the pattern of a string to see if it's a valid date, for example v8n().date('YYYYMMDDHHMMSS').test('20180817111111)., and existing rules like lessThan, greaterThan, etc could work with it to verify whether it's older or newer than a specified date. Also isPast and isFuture to specify if a date is in the past or future.

Npm package doesn't include .schema

I was trying to use the .schema function described in the docs and ran into an error.
After digging around i found that it it hasn't been published on npm yet.
I realise that it was included very recently and so it's understandable.
Just wanted to give you guys a heads up!

My work around was simply to copy the implementation from the src and inject it as a custom rule.

Support branching

I want to be able to validate that something is either undefined or a number, for instance. Is there already a way to do that? If not, it might be worth adding.

Document various "aux" functions and additional helpers

The code is littered with helpers that some might not understand. To enable contributions these functions need to be described in a comment. It can be kept brief but should say what the function does and what it returns. Especially those functions returning functions need to receive this treatment. This is an important step in cleaning the code.

This is not another input field validation library

This is not another input field validation library.

What's the difference between joi and v8n?

Joi

  • Fluent and chainable API;
  • Useful standard validation rules;
  • Custom validations rules;
  • Reusability;

I'm really interested in how v8n differs from other libraries like joi. Does it focus on browser, server or both?

rule: integer

I'd like to have a rule which verifies if a value is an integer like so

function integer() {
    return value => typeof value === "number" &&
        isFinite(value) &&
        Math.floor(value) === value;
}

v8n.extend({integer});

Bug with `integer` rule

The integer rule has a bug when it needs to use its polyfilled version. Look:

v8n/src/v8n.js

Line 150 in 10216d2

integer: () => value => Number.isInteger(value) || testIntegerPolyfill(value),

This code is going to throw an exception when Number.isInteger is not present, instead of fallback to the polyfill test.

It should first detect for the Number.isInteger presence and fallback to the polyfill before calling it, like this:

(Number.isInteger || testIntegerPolyfill)(value)

NOTE: This is a bug fix that has to be solved as soon as possible. And it must go in a patch version. It needs to be fixed upon the stable branch instead of master.

How to validate items of an array of arrays ?

Hello !

I want to validate values of an array of arrays, something like this :

const value = [
  [0,1,2,3],
  [0,2],
  [0,3,4]
]

I tried this ...

{
                value: v8n()
                    .array()
                    .maxLength(8)
                    .every.array()
                    .every.number()
                    .positive(),
}

... but it didn't work.

Is it possible to validate this kind of array or sould I create my own custom rule ?

Improve the look and feel of docs

The README is very long and daunting. I would consider using either something like GitBook or VuePress for external docs or at least moving the entire API to a separate API.md file. The docs could generally be a bit nicer to look at, so I would also possibly consider switching documentation.js for manual creation which would also make the code nicer, since JSDoc is extremely space-consuming.

Add support for truthy / falsey / empty. And about the `.equal` & `.exact`

Heya! 🎉 Great work and code!

Would mind adding support for this rules? Where the .empty should work for any passed value - empty array, empty string, empty object (Object.keys(val).length?) and etc.

edit: oh there's .empty already.

As about the .equal and .exact. What about renaming them? There are few scenarions.

1/ Since even Nodejs is moving to "strict by default" for the assert core module, why not make .equal strict by default and add looseEqual rule?

2/ Or adding one more alias for the .exact - .strictEqual?

Support for Async Validations

This looks like a really nice tool, however I don't see any support or documentation on async/promise-based validation.

Is this something that this project plans on supporting or is this outside of the plan? Classic use-case being username validation, for example!

Pass "optional" rule with 0 length strings

Would be great if the optional rule would also pass on an empty trimmed string. Guessing there might be a more technical reason as to why you chose not add in, but figured I'd bring it up just in case.

Version 1.3.0 - v8n().optional() and v8n().string() bug

Hey, when I updated to version 1.3.0

One of my function stopped working, I managed to see that the v8n.optional() with v8n.string() is causing the bug,

Reproducing

var a = v8n().schema({name: v8n().optional(v8n().string())}).testAll({name: ""})

In version 1.2.3 there is no error:
image

But in version 1.3.0

 var a = v8n().schema({name: v8n().optional(v8n().string())}).testAll({name: ""})
undefined
> a
[ { Error
      at /Users/shaharshalev/Documents/repos/webapp-backend/node_modules/v8n/dist/v8n.cjs.js:224:20
      at Array.forEach (<anonymous>)
      at Proxy.testAll (/Users/shaharshalev/Documents/repos/webapp-backend/node_modules/v8n/dist/v8n.cjs.js:220:18)
      at repl:1:62
      at Script.runInThisContext (vm.js:119:20)
      at REPLServer.defaultEval (repl.js:332:29)
      at bound (domain.js:395:14)
      at REPLServer.runBound [as eval] (domain.js:408:12)
      at REPLServer.onLine (repl.js:639:10)
      at REPLServer.emit (events.js:194:15)
    rule:
     Rule { name: 'schema', fn: [Function], args: [Array], modifiers: [] },
    value: { name: '' },
    cause: [ [Error] ],
    target: undefined } ]

Add 'some' and 'every' as additional modifiers

Proposing to add some and every as new modifiers for testing array elements.

v8n()
  .some.number()
  .even()
  .test([1, 2, 3]); // true

v8n()
  .some.number()
  .even()
  .test([1, 3]); // false

v8n()
  .every.number()
  .even()
  .test([1, 2, 3]); // false

v8n()
  .every.number()
  .even()
  .test([2, 4]); // true

An argument can be made for the following instead:

[1, 2, 3].some(i => v8n().number().even(i));

But personally, I find the former more elegant.

p.s. I can work on this feature request.

error TypeError: v8n(...).schema is not a function

Hi !

I try to use the schema rule to validate objects. Here is my code :

const v8n = require('v8n')

const validate = (obj, specs) => {
    try {
        const validation = v8n().schema(specs)

        validation.check(obj)

        return obj
    } catch (error) {
        console.log('error', error)
    }
}

const { accessId, password } = validate(myObject, {
  accessId: v8n().string(),
  password: v8n().string().minLength(8).maxLength(40)
})

When I execute this code I got this error :

error TypeError: v8n(...).schema is not a function

I don't understand what's wrong ?

v8n: 1.0.2
node: 9.10.0

Possibility to include extra information along with validations

What is this proposal about?

An issue was filled asking some kind of i18n support from v8n. Take a look at #107

Actually, this kind of feature is more related to the presentational layer of an application. And it's not a v8n's role to provide a messaging system, but to provide a validation solution for as many use cases as possible.

But in fact, we need to provide some kind of "help" to developers for mapping validations into messages. But we should keep things simple, fluent and in accordance with all of the main goals of this library.

I was thinking about that, and I ended up with the fact that we should provide a way to identify validations better, like with an ID or something like that. But I realized that we shouldn't keep things strictly tied to ID's or any other kind of data, but instead, we could provide an abstract mechanism for the developer to define what he/she wants to tie with his/her validation.

So my proposal is to provide a feature where the developer can provide more information to attach with the validation process.


The following solutions have crossed my mind:

  • Passing extra data along with the v8n function:
v8n({ id: "name" }).string().not.empty().check("");
// ValidationError{ id: "name", ... }

At a first glance, this solution looks nice. But there are situations where it makes no sense, as when we branch a validation from another validation. Look:

const numbers = v8n({ id: "numbers" }).number();
const positive = numbers.positive();
const negative = numbers.negative();
  • Passing extra data with the validation functions:
const name = v8n().string().not.empty();
name.check("", { id: "firstName" });
name.check("", { id: "lastName" });

This syntax looks a little weird to me, and it also requires some more work to be done to make it work with all the validation methods.

  • Higher-order validation

This is my favorite solution, as it is very functional, and it does not conflict with any of the current API. But indeed it's more difficult to implement and maybe should not look very familiar for everyone.

const name = v8n().string().not.empty();

withExtra({ id: "firstName" })(name).check("");
// ValidationError{ extras: { id: "firstName" }, ... }

All these solutions have advantages and disadvantages, but we need to discuss more them so that we can understand them better to avoid future problems. We can also end up with other better solutions after all.

ValidationException should extend Error

Since ValidationException is a custom Error, it should extend JavaScripts base Error. This is for consistency and handling purposes and will make the exception more rich.

There is a description on how to extend the base Error on the MDN info page for it. This won't cause any API changes and no code changes outside the ValidationException function.

Most notably this would give the stack trace on most platforms: Medium.com article

Bug: nested async rules

Async rules are not tested async when placed within a schema.

  test("nested async rule", async () => {
    v8n.extend({ asyncRule });

    const validation = v8n().schema({
      item: v8n().number().asyncRule([10, 17, 20]),
    });

    await expect(validation.testAsync({ item: "10" })).rejects.toBeDefined();
    await expect(validation.testAsync({ item: 11 })).rejects.toBeDefined(); // -> expect failes, because asyncRule is not validated async.
    await expect(validation.testAsync({ item: 17 })).resolves.toBe({ item: 17 });
  });

Introduce pulling to a development branch instead of master

For proper versioning pull requests should not be toward master. I believe master should represent the latest released version whereas all changes for the next version should be on another branch called dev, develop or something like that. That branch could of course be default on GitHub to keep current code visible.

number check not working against NaN

When testing if something is a number with a string using either the Number constructor, the parseInt/parseFloat methods, or the '+' unary operator it returns true.

Ex:

v8n()
.number()
.test(Number('foobar'));

changing the number function to use a regexp pattern seems to solve this issue.
number: makeTestPattern(/^((?![a-z]).)*$/),

This is my first time opening an issue in open source for a bit (at least with a suggestion) so I don't know what all guidelines are in place, if anyone would like for me to open a pull request I would be more than happy to.

Add `instanceOf` rule

This rule should reflect the usage of the instanceof operator:

const date = new Date();

v8n().instanceOf(Date).test(date); // true

Create a process for pull requests

There should be a defined process for new features. I believe a good starting point would be a pull request template containing a checklist for all important tasks when changing something.

The main points should be:

- [ ] Tests are passing
- [ ] The code is properly formatted with Prettier
- [ ] The code is commented or easily understandable
- [ ] Changes are documented
- [ ] Changes are added to the `Unreleased` section within the changelog

Can you think of additional points or change any? What else should be in the template?

Add a CONTRIBUTING file

This file should communicate how people can contribute. Things like how to clone the repo, install and get the project running. And other useful information.

It can be put inside a .github folder.

Better sharable extending

Currently you can use v8n.extend but it does not return anything, i think a lot more better would be to return and then pass it where it is needed.

For example

customRules.js

const v8n = require('v8n')

module.exports = v8n.extend({
  one: (expected) => (actual) => actual === 1
})

so later we can pass it for example to the v8n() or to new v8n().use()?

const v8n = require('v8n')
const customRules = require('./customRules')

v8n(customRules)
  .one()
  .test(123) // => false

Possibility to validate in relation to other rules

Thank you very much for this incredible validation library. It's so lightweight and flexible, I use it everywhere and even created a Node.js API validation module on top of it.

I know v8n doesn't aim to mimic Joi, but it also has the ability to validate schemas. Would it be possible to have conditional validation at some point, like XOR, NAND etc?

Let me illustrate this:

const validation = v8n().schema({
  id: v8n()
    .number()
    .positive(),
  name: v8n()
    .string()
    .minLength(4),
  isMarried: v8n()
    .boolean(),
  birthname: v8n() // this one would be required only if isMarried is true
    .string()
    .minLength(4)
});

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.