Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

mev

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mev - npm Package Compare versions

Comparing version 2.1.0 to 2.2.0

.travis.yml

2

dist/field/Field.d.ts

@@ -15,4 +15,4 @@ import { Rule } from '../rule/Rule';

addRule(fn: (r: R) => R): this;
validate(d: T): Validation;
test(d: T): Validation;
protected getNewRule(): R;
}

@@ -27,3 +27,3 @@ "use strict";

}
validate(d) {
test(d) {
const errors = this.rules

@@ -30,0 +30,0 @@ .map((r) => r.test(d))

@@ -23,3 +23,3 @@ "use strict";

});
describe('validate', () => {
describe('test', () => {
it('should return no errors when all rules pass', () => {

@@ -30,3 +30,3 @@ const field = new Field_1.Field()

.addRule((r) => r.addTestFunction(rule_1.truthyTest));
chai_1.expect(field.validate(rule_1.emptyData)).to.deep.equal(rule_1.success);
chai_1.expect(field.test(rule_1.emptyData)).to.deep.equal(rule_1.success);
});

@@ -41,6 +41,6 @@ it('should return errors for each failing test', () => {

};
chai_1.expect(field.validate(rule_1.emptyData)).to.deep.equal(expectedError);
chai_1.expect(field.test(rule_1.emptyData)).to.deep.equal(expectedError);
field.addRule((r) => r.addTestFunction(rule_1.falsyTest));
expectedError.errors.push(rule_1.emptyFail);
chai_1.expect(field.validate(rule_1.emptyData)).to.deep.equal(expectedError);
chai_1.expect(field.test(rule_1.emptyData)).to.deep.equal(expectedError);
});

@@ -47,0 +47,0 @@ });

@@ -21,3 +21,3 @@ "use strict";

.addRule(rule3);
const validation = field.validate(testString);
const validation = field.test(testString);
chai_1.expect(utils_1.isError(validation)).to.be;

@@ -24,0 +24,0 @@ // @ts-ignore

@@ -16,3 +16,3 @@ import { Field } from '../field/Field';

addSchemaField(fieldName: string, schema: (sf: Schema) => Schema): this;
run(obj: any): Validation;
test(obj: any): Validation;
private ensureFieldNameIsUnique;

@@ -19,0 +19,0 @@ }

@@ -31,12 +31,12 @@ "use strict";

}
run(obj) {
test(obj) {
function objHasResultPropAsFailure(o) {
return utils_1.isError(o.testResult);
}
function validateFieldOrSchema(field, data) {
function testFieldOrSchema(field, data) {
if (isSchema(field)) {
return field.run(data);
return field.test(data);
}
else {
return field.validate(data);
return field.test(data);
}

@@ -55,11 +55,5 @@ }

.from(this.fields)
.map(([fieldName, field]) => ({ fieldName, testResult: validateFieldOrSchema(field, obj[fieldName]) }))
.map(([fieldName, field]) => ({ fieldName, testResult: testFieldOrSchema(field, obj[fieldName]) }))
.filter(objHasResultPropAsFailure)
.map(fieldAndResultToIncludeFieldNameAndOptionallyParent)
/*({ fieldName, testResult }) =>
testResult.errors.map((error: ValidationRuleError) => ({
fieldName,
...error,
})),
)*/
.reduce((t, e) => t.concat(e), []);

@@ -66,0 +60,0 @@ return errors.length === 0 ? { success: true } : { errors };

@@ -32,3 +32,3 @@ "use strict";

};
const validation = parentSchema.run({ parent: { child: 'asdf' } });
const validation = parentSchema.test({ parent: { child: 'asdf' } });
chai_1.expect(validation).to.deep.equal(expectedError);

@@ -63,3 +63,3 @@ });

};
chai_1.expect(schema4.run(data)).to.deep.equal(expectedError);
chai_1.expect(schema4.test(data)).to.deep.equal(expectedError);
});

@@ -66,0 +66,0 @@ it('should accept a function which is passed a new schema', () => {

@@ -26,3 +26,3 @@ "use strict";

if (req.body && req.body && req.body.data === 'object') {
const validation = schema.run(req.body.data);
const validation = schema.test(req.body.data);
if (isSuccess(validation)) {

@@ -29,0 +29,0 @@ next();

@@ -33,3 +33,3 @@ import { expect } from 'chai';

describe('validate', () => {
describe('test', () => {
it('should return no errors when all rules pass', () => {

@@ -41,3 +41,3 @@ const field: Field<any, Rule<any>> = new Field()

expect(field.validate(emptyData)).to.deep.equal(success);
expect(field.test(emptyData)).to.deep.equal(success);
});

@@ -55,3 +55,3 @@

expect(field.validate(emptyData)).to.deep.equal(expectedError);
expect(field.test(emptyData)).to.deep.equal(expectedError);

@@ -61,5 +61,5 @@ field.addRule((r) => r.addTestFunction(falsyTest));

expect(field.validate(emptyData)).to.deep.equal(expectedError);
expect(field.test(emptyData)).to.deep.equal(expectedError);
});
});
});

@@ -43,3 +43,3 @@ import { Rule } from '../rule/Rule';

public validate(d: T): Validation {
public test(d: T): Validation {
const errors: ValidationRuleError[] = this.rules

@@ -46,0 +46,0 @@ .map((r) => r.test(d))

@@ -22,3 +22,3 @@ import { expect } from 'chai';

const validation: ValidationError = field.validate(testString) as ValidationError;
const validation: ValidationError = field.test(testString) as ValidationError;
expect(isError(validation)).to.be;

@@ -25,0 +25,0 @@ // @ts-ignore

@@ -39,3 +39,3 @@ import { expect } from 'chai';

const validation: Validation = parentSchema.run({ parent: { child: 'asdf' } });
const validation: Validation = parentSchema.test({ parent: { child: 'asdf' } });

@@ -76,3 +76,3 @@ expect(validation).to.deep.equal(expectedError);

expect(schema4.run(data)).to.deep.equal(expectedError);
expect(schema4.test(data)).to.deep.equal(expectedError);
});

@@ -79,0 +79,0 @@

@@ -48,3 +48,3 @@ import { Field } from '../field/Field';

public run(obj: any): Validation {
public test(obj: any): Validation {
function objHasResultPropAsFailure(o: { fieldName: string, testResult: Validation }):

@@ -55,7 +55,7 @@ o is { fieldName: string, testResult: ValidationError } {

function validateFieldOrSchema(field: Schema | Field<any, Rule<any>>, data: any): Validation {
function testFieldOrSchema(field: Schema | Field<any, Rule<any>>, data: any): Validation {
if (isSchema(field)) {
return field.run(data);
return field.test(data);
} else {
return field.validate(data);
return field.test(data);
}

@@ -83,11 +83,5 @@ }

.from(this.fields)
.map(([fieldName, field]) => ({ fieldName, testResult: validateFieldOrSchema(field, obj[fieldName]) }))
.map(([fieldName, field]) => ({ fieldName, testResult: testFieldOrSchema(field, obj[fieldName]) }))
.filter(objHasResultPropAsFailure)
.map(fieldAndResultToIncludeFieldNameAndOptionallyParent)
/*({ fieldName, testResult }) =>
testResult.errors.map((error: ValidationRuleError) => ({
fieldName,
...error,
})),
)*/
.reduce((t, e) => t.concat(e), []);

@@ -94,0 +88,0 @@

@@ -35,3 +35,3 @@ import { Schema } from '..';

if (req.body && req.body && req.body.data === 'object') {
const validation = schema.run(req.body.data);
const validation = schema.test(req.body.data);
if (isSuccess(validation)) {

@@ -38,0 +38,0 @@ next();

{
"name": "mev",
"version": "2.1.0",
"version": "2.2.0",
"description": "Another validator..",

@@ -5,0 +5,0 @@ "main": "dist/index.js",

@@ -1,24 +0,330 @@

# Unnamed Validator
If you are reading this, then I probably haven't put enough effort
into this module.
# mev
That being said, naming things isn't my strong point, so perhaps
it'll stick.
Meaningful Error Validation for everyone.
(Either that, or you are stalking my commit history. Please stop, you
likely won't find anything other than distressingly bad code.)
[![Build Status](https://travis-ci.com/beaumontjonathan/unnamed-validator.svg?branch=master)](https://travis-ci.com/beaumontjonathan/unnamed-validator)
## Motivation
I am _fed up_ of input validation. But even more, I am fed up of bad
input validation. The kind of module which kicks out such horrid
error messages that you need another module just to interpret them.
```js
import { createValidationSchema } from 'mev';
Too often a project motivation is killed while off attempting the
early steps of checking input and elegantly returning validation
errors. Frequently RESTful services do not provide meaningful errors
and this is not good enough. No more, I say.
const userSchema = createValidationSchema()
.addField('username', f => f
.string()
.addRule(r => r.minLength(5))
.addRule(r => r.maxLength(10))
.addRule(r => r.lowercase())
)
.addField('age', f => f
.number()
.addRule(r => r.min(0))
);
## Aim
The aim of this is to produce an input validator which provides
_meaningful_ error messages which can even be passed back up to the
user.
// { success: true }
userSchema.run({ username: 'myusername', age: 5 });
```
### Installation
Install using your favourite JavaScript package manager.
```sh
$ npm install mev
$ yarn add mev
```
## Features
- Object and primitive data validation
- Customisable, user friendly errors
- Chain based API
- Written in TypeScript
- Reusable by design
# Design
- Schemas are made up of fields
- Fields are made up of rules
- Rules are made up of tests and errors
## `Rule`
A rule is an atomic validation test which when tested either passes or provides a description of the failed test.
This description is the key to the purpose of this library. It is written by you, ready to be passed back up your stack and straight to the user. When unspecified, a test description and title may be generated.
###### Example
```js
import { createValidationRule } from 'mev';
const rule = createValidationRule()
.title('too long')
.description('must be no longer than 5')
.addTestFunction(e => e.length <= 5);
rule.test('short');
// { success: true }
rule.test('not short');
// { title: 'too long', description: 'must be no longer than 5' }
```
Here the `addTestFunction` method is being used to specify the validation test. Each rule may have as many tests as desired, however it is recommended to keep rules atomic for more specific error messages.
Mev has many build in methods for testing data. These are specific to the data type being tested, and as such there is an extension of `Rule` for each primitive data type `string`, `number` & `boolean`.
### `StringRule`
Calling the `string` method first in the chain will give the chain access to each of the test methods provided in `StringRule`. Here `maxLength` is being used to replace the test function written above.
###### Example
```js
import { createValidationRule } from 'mev';
const rule = createValidationRule()
.string()
.title('too long')
.description('must be no longer than 5')
.maxLength(5);
rule.test('short');
// { success: true }
rule.test('not short');
// { title: 'too long', description: 'must be no longer than 5' }
```
#### Methods
- `maxLength(n)` - fails when the test input has a length greater than `n`
- `minLength(n)` - fails when the test input has a length smaller than `n`
- `blacklist(list)` - fails when the test input contains one or more element in `list` as a substring
- `uppercase()` - fails when the test input contains any lowercase letters
- `lowercase()` - fails when the test input contains any uppercase letters
- `alphanumeric()` - fails when the test input contains any character other than a letter or number
- `regex(r)` - fails when the regular expression `r` fails on the test input
### `NumberRule`
Calling the `number` method first in the chain will give the chain access to each of the test methods provided in `NumerRule`.
###### Example
```js
import { createValidationRule } from 'mev';
const rule = createValidationRule()
.number()
.title('too big')
.description('must not be larger than 5')
.max(5);
rule.test(3);
// { success: true }
rule.test(6);
// { title: 'too big', description: 'must not be larger than 5' }
```
#### Methods
- `max(n)` - fails when the test input is greater than `n`
- `min(n)` - fails when the test input is less than `n`
- `closedMax(n)` - see `max(n)`
- `closedMin(n)` - see `max(n)`
- `openMax(n)` - fails when the test input is greater than or equal to `n`
- `openMin(n)` - fails when the test input is less than or equal to `n`
- `closedInterval(min, max)` - fails when the test input is outside of the interval [`min`, `max`]
- `openInterval(min, max)` - fails when the test input is outside of the interval (`min`, `max`)
### `BooleanRule`
Calling the `boolean` method first in the chain will give the chain access to each of the test methods provided in `BooleanRule`.
###### Example
```js
import { createValidationRule } from 'mev';
const rule = createValidationRule()
.boolean()
.title('truthy')
.description('must be truthy')
.true();
rule.test(true);
// { success: true }
rule.test(false);
// { title: 'truthy', description: 'must be truthy' }
```
#### Methods
- `true()` - fails when the test input is false
- `false()` - fails when the test input is true
## `Field`
A field is a collection of rules, typically pertaining to the same data type. Rules are either added as an object, or through a callback function.
When a field is tested, each of the rules are tested with the provided data and either a success flag is returned, or an array of errors from each failing test.
###### Example
```js
import { createValidationRule, createValidationField } from 'mev';
const rule = createValidationRule()
.title('too long')
.description('must be no longer than 5')
.addTestFunction(e => e.length <= 5);
const field = createValidationField()
.addRule(rule)
.addRule(r => r
.title('odd length')
.description('must have an even length')
.addTestFunction(e => e.length % 2 === 0)
);
field.test('pass');
// { success: true }
field.test('failure');
// { errors: [
// { title: 'too long', description: 'must be no longer than 5' },
// { title: 'odd length', description: 'must have an even length' }
// ] }
```
### Data types
As with `Rule`, fields may be associated with one of the primitive data types `string`, `number` or `boolean`. Once again this must be placed first in the chain, and once it has been used then all rules will have access to the test methods associated with that type.
###### Example
```js
import { createValidationField } from 'mev';
const field = createValidationField()
.string()
.addRule(r => r
.title('too long')
.description('must not be longer than 5')
.maxLength(5)
)
```
Here the value of `r` being passed into the callback of `addRule` will be an instance of `StringRule`, and therefore has access to the method `maxLength`.
It is important to note that if the value passed into `addRule` is a rule instead of a function, then it will not have access to the methods of field type and the type will have to be stated explicitly in the rule.
## `Schema`
A schema is a collection of fields and other schemas, similar to how a `Field` is a collection of `Rule`s. When a schema is tested against an input object, each field is tested, and the error from each failing test is reduced into a single array. Once again, if no rules have failed, then a success flag will be returned.
The `addField` method is used to add a new field to a schema. The first argument is the name of the field and the second argument takes either a field object or a callback function which is passed a new field object.
###### Example
```js
import { createValidationField, createValidationSchema } from 'mev';
const usernameField = createValidationField()
.string()
.addRule(r => r
.title('invalid character')
.description('usernames must only contain letters and numbers')
.alphanumeric()
)
.addRule(r => r
.title('invalid length')
.description('usernames must be between 2 and 15 characters long')
.minLength(2)
.maxLength(15)
);
const schema = createValidationSchema()
.addField('age', f => f
.number()
.addRule(r => r
.title('negative age')
.description('an age must be greater than 0')
.min(0)
)
)
.addField('username', usernameField);
schema.test({ age: 4, username: 'myusername' });
// { success: true }
schema.test({ age: -4, username: 'invalid username' })
// { errors: [
// { fieldName: 'age',
// title: 'negative age',
// description: 'an age must be greater than 0' },
// { fieldName: 'username',
// title: 'invalid character',
// description: 'usernames must only contain letters and numbers' },
// { fieldName: 'username',
// title: 'invalid length',
// description: 'usernames must be between 2 and 15 characters long' }
// ]}
```
When rules fail in a schema, the `fieldName` is also included in the error object.
### Nested Schemas
`Schema` has the method `addSchemaField` which is similar to `addField` except the second argument takes a schema object or callback passing a schema object. This allows nested schema validation.
###### Example
```js
import { createSchemaValidation } from 'mev';
import userSchema from './user';
const schema = createValidationSchema()
.addSchemaField('user', userSchema)
.addSchemaField('testInfo', s => s
.addField('score', f => f
.number()
.addRule(r => r
.title('out of range')
.description('out of test score range of 1-100')
.closedInterval(0, 100)
)
)
);
schema.test({
user: { username: 'myUsername', age: 32 },
testInfo: { score: 40 },
});
// { success: true }
schema.test({
user: { username: 'invalid username', age: 32 },
testInfo: { score: 1000 },
});
// { errors: [
// { parent: 'user',
// fieldName: 'username',
// title: 'invalid character',
// description: 'usernames must only contain letters and numbers' },
// { parent: 'user',
// fieldName: 'username',
// title: 'invalid length',
// description: 'usernames must be between 2 and 15 characters long' },
// { parent: 'testInfo',
// fieldName: 'score',
// title: 'out of range',
// description: 'out of test score range of 1-100' }
// ]}
```
When rules fail in a nested schema, the `fieldName` and `parent` schema are also included in the error object.

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc