funval
Version:
A minimalist library for data validation using functions interfaces.
584 lines (378 loc) • 12.1 kB
Markdown
<h1 align="center" style="text-align:center">🦩 Funval</h1>
<h4 align="center">A minimalist library for data validation using functions interfaces.</h4>
<p align="center">
<a href="https://www.npmjs.org/package/funval">
<img src="http://img.shields.io/npm/v/funval.svg" alt="View On NPM">
</a>
<a href="https://travis-ci.org/neuledge/computed-types">
<img src="https://travis-ci.org/neuledge/computed-types.svg?branch=funval" alt="Build Status">
</a>
<a href="https://libraries.io/npm/funval/">
<img src="https://img.shields.io/librariesio/release/npm/funval" alt="Dependency Status">
</a>
<a href="https://coveralls.io/github/neuledge/computed-types?branch=funval">
<img src="https://coveralls.io/repos/github/neuledge/computed-types/badge.svg?branch=funval"
alt="Coverage Status" />
</a>
<a href="LICENSE">
<img src="https://img.shields.io/npm/l/funval.svg" alt="License">
</a>
</p>
<br>
<hr />
**WARNING**: This package is deprecated and no longer maintain. Please switch to it's successor:
[Computed-Types](https://github.com/neuledge/computed-types).
<hr />
**Funval** is a minimalist validation library that seamlessly integrates with your business logic.
Using only plain functions, *Funval* knows how to validate your data and automatically generates
TypeScript interfaces to reduce code duplications and complexity.
```ts
function ValidNumber(input: unknown): number {
const value = Number(input);
if (isNaN(value)) {
throw new TypeError('Invalid number');
}
return value;
}
```
### Main Features
- **Easy to Read** - Uses functions as types (including `String`, `Number`, `Boolean`, etc...)
- **Reusable Interfaces** - Create new validator using plain functions in seconds.
- **TypeScript Validation** - Detect errors during compile time.
- **Function Composition** - Pipe multiple validators to generate new ones.
- **Asynchronous & Synchronous Support** - Automatically detected promises.
- **Pure Javascript** - Also works without TypeScript.
<br>
## Install
```bash
npm i funval
```
<br>
## Usage
```ts
import { Schema, Optional, Or, Type, Integer, Between } from 'funval';
const UserSchema = {
name: Optional(String),
username: /^[a-z0-9]{3,10}$/,
status: Or('active' as 'active', 'suspended' as 'suspended'),
amount: input => Between(1, 50)(Integer(input)),
};
const validator = Schema(UserSchema);
let user: Type<typeof UserSchema>;
try {
user = validator({
username: 'john1',
// @ts-ignore Type '"unregistered"' is not assignable to type '"active" | "suspended"'.
status: 'unregistered',
amount: 20,
});
} catch (err) {
console.error(err.message, err.paths);
}
```
<br>
## Creating Validators
A validator is any function that can return a value without throwing any exceptions:
```ts
import * as EmailValidator from 'email-validator';
function Email(input: string): string {
if (!EmailValidator.validate(input)) {
throw new TypeError(`Invalid email address: "${input}"`);
}
return input;
}
```
You can use the above validator on schemas as an `Email` type:
```ts
const UserSchema = {
email: Email,
};
const validator = Schema(UserSchema);
```
<br>
### Asynchronous Validators
Asynchronous validators are supported by returning a `Promise` (or `PromiseLike`) values:
```ts
import fetch from 'node-fetch';
async function AvailableUsername(input: string): Promise<string> {
const res = await fetch(`/check-username?username=${encodeURIComponent(input)}`);
if (!res.ok) {
throw new TypeError(`Username "${input}" is already taken`);
}
return input;
}
```
*Funval* automatically detects promise and convert the return type of the `Validator` to promise as well:
```ts
const UserSchema = {
username: AvailableUsername,
};
const validator = Schema(UserSchema);
const user = await validator({ username: 'test' });
```
If you prefer, you can safely convert any validator to an asynchronous validator using the `Async`
helper:
```ts
import { Async, Schema } from 'funval';
const UserSchema = {
email: Email,
};
const validator = Async(Schema(UserSchema));
// will catch instead of throwing
validator({ email: 'invalid-email' }).catch(err => console.err(err));
```
<br>
## Available Validators
All the available validators ordered by type:
* **Schema** -
[`Schema`](#schema),
[`Maybe`](#maybe),
[`Optional`](#optional),
[`Default`](#default),
[`Required`](#required),
[`Truthy`](#truthy),
[`Or`](#or),
[`ArrayOf`](#arrayof),
[`TypeOf`](#typeof),
[`Any`](#any),
[`Override`](#override)
[`Test`](#test)
* **Comparison** -
[`Equals`](#equals),
[`GreaterThan`](#greaterthan),
[`GreaterThanEqual`](#greaterthanequal),
[`LessThan`](#lessthan),
[`LessThanEqual`](#lessthanequal),
[`Between`](#between)
* **Strings** -
[`ContentString`](#contentstring),
[`TrimString`](#trimstring)
[`StringRange`](#stringrange)
[`StringMatch`](#stringmatch)
* **Numbers** -
[`Float`](#float),
[`Integer`](#integer)
* **Booleans** -
[`Bool`](#bool)
<br>
### `Schema`
```ts
import { Schema } from 'funval';
declare function Schema(schema: any, error?: string | Error): Validator;
```
Validate inputs using the given schema.
**Throws:** If the input does not match the given schema.
<br>
### `Maybe`
```ts
import { Maybe } from 'funval';
declare function Maybe(schema: any, error?: string | Error): Validator;
```
Same as [`Schema`](#schema) but ignores `undefined` or omitted inputs.
**Throws:** If the input tested and does not match the given schema.
<br>
### `Optional`
```ts
import { Optional } from 'funval';
declare function Optional(schema: any, error?: string | Error): Validator;
```
Same as [`Schema`](#schema) but ignores `undefined`, `null` or omitted inputs.
**Throws:** If the input tested and does not match the given schema.
<br>
### `Default`
```ts
import { Default } from 'funval';
declare function Default(schema: any, value: any): Validator;
```
Validate inputs using the given schema or use the given value if input equals to `undefined` or
omitted.
**Throws:** If the input tested and does not match the given schema.
<br>
### `Required`
```ts
import { Required } from 'funval';
declare function Required(schema: any, error?: string | Error): Validator;
```
Validate inputs using the given schema.
**Throws:** If input is `undefined` or does not match the given schema.
<br>
### `Truthy`
```ts
import { Truthy } from 'funval';
declare function Truthy<T>(input: T): T;
```
Validate input is truthy.
**Throws:** If input is not truthy.
<br>
### `Or`
```ts
import { Or } from 'funval';
declare function Or(...candidates: any[]): Validator;
```
Validate inputs using any of the given candidates.
**Throws:** If the input does not match to any of the given schemas.
<br>
### `ArrayOf`
```ts
import { ArrayOf } from 'funval';
declare function ArrayOf(itemSchema: any, error?: string | Error): Validator;
```
Validate the input is an array and that each item matches the given schema.
**Throws:** If the given input is not an array or one of the items not matches the item schema.
<br>
### `TypeOf`
```ts
import { TypeOf } from 'funval';
declare function TypeOf(
typeOf:
| 'string'
| 'number'
| 'object'
| 'boolean'
| 'undefined'
| 'symbol'
| 'bigint',
error?: string | Error,
): Validator;
```
Check the input type is equals to the given type.
**Throws:** If the input type is different from the given type.
<br>
### `Any`
```ts
import { Any } from 'funval';
declare function Any(input: any): any;
```
Allow any type of input.
**Throws:** Never.
<br>
### `Override`
```ts
import { Override } from 'funval';
declare function Override(value: any): Validator;
```
Override any input and returns the given value.
**Throws:** Never.
<br>
### `Test`
```ts
import { Test } from 'funval';
declare function Test<T>(test: (input: T) => unknown, error?: string | Error): Validator;
```
Return the input value as is, only if the test function returns a truthy value.
**Throws:** If the test function throws or the test function return a non-truthy value.
<br>
### `Equals`
```ts
import { Equals } from 'funval';
declare function Equals(value: any, error?: string | Error): Validator;
```
Check the input is strictly equals to the given value.
**Throws:** If the input does not equal to the given value.
<br>
### `GreaterThan`
```ts
import { GreaterThan } from 'funval';
declare function GreaterThan(value: any, error?: string | Error): Validator;
```
Check the input is greater than the given value.
**Throws:** If the input does not greater than the given value.
<br>
### `GreaterThanEqual`
```ts
import { GreaterThanEqual } from 'funval';
declare function GreaterThanEqual(value: any, error?: string | Error): Validator;
```
Check the input is greater than or equals the given value.
**Throws:** If the input does not greater than or equals the given value.
<br>
### `LessThan`
```ts
import { LessThan } from 'funval';
declare function LessThan(value: any, error?: string | Error): Validator;
```
Check the input is less than the given value.
**Throws:** If the input does not less than the given value.
<br>
### `LessThanEqual`
```ts
import { LessThanEqual } from 'funval';
declare function LessThanEqual(value: any, error?: string | Error): Validator;
```
Check the input is less than or equals the given value.
**Throws:** If the input does not less than or equals the given value.
<br>
### `Between`
```ts
import { Between } from 'funval';
declare function Between(minValue: any | null, maxValue: any | null, error?: string | Error):
Validator;
```
Check the input is between the given boundaries.
**Throws:** If the input is not between the given boundaries.
<br>
### `ContentString`
```ts
import { ContentString } from 'funval';
declare function ContentString(input: unknown): string;
```
Converts any input to a valid string.
**Throws:** If input is either `null`, `undefined`, an object without proper `toString`
implementation, empty or a whitespace string.
<br>
### `TrimString`
```ts
import { TrimString } from 'funval';
declare function TrimString(input: unknown): string;
```
Same as [`ContentString`](#contentstring), but `trim` the output as well.
**Throws:** If input is either `null`, `undefined`, an object without proper `toString`
implementation, empty or a whitespace string.
<br>
### `StringRange`
```ts
import { StringRange } from 'funval';
declare function StringRange(
minLength: number | null,
maxLength: number | null,
error?: string | Error,
): Validator;
```
Converts any input to a valid string and make sure the string is in the given boundaries.
**Throws:** If input is either `null`, `undefined`, an object without proper `toString`
implementation, empty string, whitespace string, or string outside of the given boundaries.
<br>
### `StringMatch`
```ts
import { StringMatch } from 'funval';
declare function StringMatch(regex: RegEx, error?: string | Error): Validator;
```
Validate the input is matches the given regular expression.
**Throws:** If input does not match the given regular expression.
<br>
### `Float`
```ts
import { Float } from 'funval';
declare function Float(input: unknown): number;
```
Converts any input to a valid float number.
**Throws:** If the input can not convert to a valid number.
<br>
### `Integer`
```ts
import { Integer } from 'funval';
declare function Integer(input: unknown): number;
```
Converts any input to a valid integer number.
**Throws:** If the input can not convert to a valid number or the number is not an integer.
<br>
### `Bool`
```ts
import { Bool } from 'funval';
declare function Bool(input: unknown): boolean;
```
Converts any input to a valid boolean.
**Throws:** If the input can not convert unambiguously to a boolean.
<br>
## License
[MIT](LICENSE) license © 2020 [Neuledge](https://neuledge.com)