nana
v2.0.0
Published
A minimal validator for any JavaScript environment.
Downloads
106
Maintainers
Readme
Nana
A minimal validator for any JavaScript environment.
- ~360 lines of code, 0 dependencies
- Only 3 concepts:
pipe,transform,check - Rich error context:
expected/actual/path/key/parent/root
Install
$ npm install nanaBasic usage
import { string, object, pipe, check, validate } from 'nana'
const userSchema = object({
name: string('Name must be a string'),
job: object({
title: pipe(
string('Job title must be a string'),
check(v => v !== 'God', 'You cannot be God')
)
})
})
console.log(
validate(userSchema, {
name: 'nana',
job: {
title: 'God'
}
})
)
/*
{
valid: false,
error: Error: You cannot be God
at ...
expected: 'check',
actual: 'God',
path: '$.job.title',
key: 'title',
message: 'You cannot be God',
parent: { title: 'God' },
root: { name: 'nana', job: [Object] }
},
result: { name: 'nana', job: { title: 'God' } }
}
*/Core concepts
pipe(...validators)Compose multiple validators/transformers in order. The output of the previous step becomes the input of the next.transform(fn)Only transforms the value, without validating. For example, convert anumbertostring, or change letter case.check(fn, msg?)Custom validation logic:fn(value, ctx)must returntrueto pass. Any other result throws an error.
For example:
// Combine multiple validations and transformations
pipe(
string('Name must be a string'),
transform(v => v.trim()),
transform(v => v.toUpperCase()),
check(v => v.length >= 3, 'Name length must be >= 3')
)transform
import { string, number, object, pipe, transform, validate } from 'nana'
const userSchema = object({
name: pipe(
string('Name must be a string'),
transform(v => v.toUpperCase())
),
age: pipe(
number('Age must be a number'),
transform(v => v + 1)
)
})
console.log(
validate(userSchema, {
name: 'nana',
age: 18
})
)
/*
{
valid: true,
result: {
name: 'NANA',
age: 19
}
}
*/Create custom validator with createValidator
import { string, number, object, pipe, transform, check, validate, createValidator, formatValue } from 'nana'
const minLength = createValidator('minLength', (value, ctx, args) => {
const [expected, msg] = args
if (value.length < expected) {
throw new Error(
msg || `(${ctx.path}: ${formatValue(value)}) ✖ (minLength: ${formatValue(expected)})`
)
}
return value
})
const userSchema = object({
profile: object({
name: pipe(
string('Name must be a string'),
// check(v => v.length >= 6, 'Name too short')
minLength(6)
),
age: pipe(
number('Age must be a number'),
check(v => v >= 18, 'Age must be >= 18')
),
gender: pipe(
string('Gender must be a string'),
check(v => ['male', 'female'].includes(v), 'Gender must be male or female')
)
})
})
console.log(
validate(userSchema, {
profile: {
name: 'nana',
age: 16,
gender: 'lalala',
}
})
)
/*
{
valid: false,
error: Error: ($.profile.name: nana) ✖ (minLength: 6)
at ...
expected: 'minLength',
actual: 'nana',
path: '$.profile.name',
key: 'name',
parent: { name: 'nana', age: 16, gender: 'lalala' },
root: { profile: [Object] }
},
result: { profile: { name: 'nana', age: 16, gender: 'lalala' } }
}
*/validateAll (collect all errors)
Unlike validate which stops at the first error, validateAll collects all validation errors:
import { string, number, object, validateAll } from 'nana'
const userSchema = object({
name: string(),
age: number()
})
const result = validateAll(userSchema, { name: 2, age: 'nana' })
/*
{
valid: false,
errors: [
Error: ($.name: 2) ✖ string,
Error: ($.age: nana) ✖ number
],
result: { name: 2, age: 'nana' }
}
*/
## TypeScript
Use `InferOutput` to extract the output type from a schema:
```ts
import { string, number, object, InferOutput } from 'nana'
const userSchema = object({
name: string(),
age: number()
})
type User = InferOutput<typeof userSchema>
// type User = { name: string; age: number }With third party validator
import { string, object, pipe, check, validate } from 'nana'
import isEmail from 'validator/lib/isEmail.js'
const userSchema = object({
name: string('Name must be a string'),
emails: array(pipe(string(), check(isEmail)))
})
console.log(
validate(userSchema, {
name: 'nana',
emails: ['[email protected]', 'email']
})
)
/*
{
valid: false,
error: Error: ($.emails[1]: email) ✖ isEmail
at ...
expected: 'isEmail',
actual: 'email',
path: '$.emails[1]',
key: 1,
parent: [ '[email protected]', 'email' ],
root: { name: 'nana', emails: [Array] }
},
result: { name: 'nana', emails: [ '[email protected]', 'email' ] }
}
*/Built-in validators
required(msg?)optional()string(msg?)number(msg?)bigint(msg?)boolean(msg?)symbol(msg?)object(obj, msg?)array(validator, msg?)
Test (100% coverage)
$ npm testLicense
MIT
