Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Validate your configurations with precise error messages

Notifications You must be signed in to change notification settings

tomm1996/validated

Repository files navigation

validated

Join the chat at https://gitter.im/andreypopp/sitegen Travis build status Type System

Validate your configurations with precise error messages:

  • Define schema with validators which are agnostic to the actual representation of data, be it a JSON string, object in memory or any other format.

  • Use schema with runners specific for formats (object and JSON5 runners are included). Get error messages with precise info (line and column numbers for example).

  • Get the result of a validation as an object: either a plain JSON or some domain specific classes if schema is defined in that way.

Table of Contents

Installation

% npm install validated

Usage

Schema

Schema is defined with validators which are agnostic to the actual representation of data, be it a JSON string or an object in memory:

import {
 mapping, sequence, object, partialObject, oneOf, maybe, enumeration, ref,
 any, string, number, boolean
} from 'validated/schema'

There's schema validator for JSON objects in memory:

import {
 validate as validateObject
} from 'validated/object'

And schema validator for strings with JSON/JSON5 encoded data:

import {
 validate as validateJSON5
} from 'validated/json5'

Let's define some schema first:

let person = object({
 name: string,
 age: number,
})
let pet = object({
 nickName: string,
 age: number,
})
let collection = sequence(oneOf(person, pet))
validateJSON5(collection, '[{name: "John", age: 26}, {nickName: "Tima", age: 3}]')
// => [ { name: 'John', age: 26 }, { nickName: 'Tima', age: 3 } ]
validateObject(collection, [{name: "John", age: 26}, {nickName: "Tima", age: 3}])
// => [ { name: 'John', age: 26 }, { nickName: 'Tima', age: 3 } ]

List of schema primitives

any

Validates any value but not undefined or null:

validateObject(any, 'ok')
// => 'ok'
validateObject(any, 42)
// => 42
validateObject(any, null)
// ValidationError: Expected a value but got null
validateObject(any, undefined)
// ValidationError: Expected a value but got undefined

If you want to validated any value and even an absence of one then wrap it in maybe:

validateObject(maybe(any), null)
// => null
validateObject(maybe(any), undefined)
// => undefined
string, number, boolean

Validate strings, numbers and booleans correspondingly.

validateObject(string, 'ok')
// => 'ok'
validateObject(number, 42)
// => 42
validateObject(boolean, true)
// => true
enumeration

Validate enumerations:

validateObject(enumeration('yes', 'no'), 'yes')
// => 'yes'
validateObject(enumeration('yes', 'no'), 'no')
// => 'no'
validateObject(enumeration('yes', 'no'), 'oops')
// ValidationError: Expected value to be one of "yes", "no" but got "oops"
mapping

Validate mappings from string keys to values.

Untyped values (value validator defaults to any):

validateObject(mapping(), {})
// => {}
validateObject(mapping(), {a: 1, b: 'ok'})
// => { a: 1, b: 'ok' }
validateObject(mapping(), 'oops')
// ValidationError: Expected a mapping but got string

Typed value:

validateObject(mapping(number), {a: 1})
// => { a: 1 }
validateObject(mapping(number), {a: 1, b: 'ok'})
// ValidationError: Expected value of type number but got string
// While validating value at key "b"
sequence

Validate sequences.

Untyped values (value validator defaults to any):

validateObject(sequence(), [])
// => []
validateObject(sequence(), [1, 2, 'ok'])
// => [ 1, 2, 'ok' ]
validateObject(sequence(), 'oops')
// ValidationError: Expected an array but got string

Typed value:

validateObject(sequence(number), [1, 2])
// => [ 1, 2 ]
validateObject(sequence(number), [1, 2, 'ok'])
// ValidationError: Expected value of type number but got string
// While validating value at index 2
object

Validate objects, objects must specify validator for each of its keys:

let person = object({
 name: string,
 age: number,
})
validateObject(person, {name: 'john', age: 27})
// => { name: 'john', age: 27 }
validateObject(person, {name: 'john'})
// ValidationError: Expected value of type number but got undefined
// While validating missing value for key "age"
validateObject(person, {name: 'john', age: 'notok'})
// ValidationError: Expected value of type number but got string
// While validating value at key "age"
validateObject(person, {name: 'john', age: 42, extra: 'oops'})
// ValidationError: Unexpected key: "extra"
// While validating key "extra"
validateObject(person, {nam: 'john', age: 42})
// ValidationError: Unexpected key: "nam", did you mean "name"?
// While validating key "nam"

If some key is optional, wrap its validator in maybe:

let person = object({
 name: string,
 age: number,
 nickName: maybe(string),
})
validateObject(person, {name: 'john', age: 27})
// => { name: 'john', age: 27 }
validateObject(person, {name: 'john', age: 27, nickName: 'J'})
// => { name: 'john', age: 27, nickName: 'J' }

You can also specify default values for keys:

let person = object({
 name: string,
 age: number,
 nickName: string,
}, {
 nickName: 'John Doe'
})
validateObject(person, {name: 'john', age: 27})
// => { name: 'john', age: 27, nickName: 'John Doe' }
validateObject(person, {name: 'john', age: 27, nickName: 'J'})
// => { name: 'john', age: 27, nickName: 'J' }
partialObject

Validate a subset of the keys from the object, passing all extra keys through:

let person = partialObject({
 name: string,
 age: number,
})
validateObject(person, {name: 'john', age: 27})
// => { name: 'john', age: 27 }
validateObject(person, {name: 'john', age: 42, extra: 'ok'})
// => { name: 'john', age: 42, extra: 'ok' }
maybe

Validates null and undefined but passes through any other value to the underlying validator:

validateObject(maybe(string), null)
// => null
validateObject(maybe(string), undefined)
// => undefined
validateObject(maybe(string), 'ok')
// => 'ok'
validateObject(maybe(string), 42)
// ValidationError: Expected value of type string but got number
oneOf

Tries a multiple validators and choose the one which succeeds first:

validateObject(oneOf(string, number), 'ok')
// => 'ok'
validateObject(oneOf(string, number), 42)
// => 42
validateObject(oneOf(string, number), true)
// ValidationError: Either:
//
// Expected value of type string but got boolean
//
// Expected value of type number but got boolean
//
ref

Allows to define recursive validators:

let node = ref()
let tree = object({value: any, children: maybe(sequence(node))})
node.set(tree)
validateObject(tree, {value: 'ok'})
// => { value: 'ok' }
validateObject(tree, {value: 'ok', children: [{value: 'child'}]})
// => { value: 'ok', children: [ { value: 'child' } ] }

Refining validations

Example:

class Point {
 constructor(x, y) {
 this.x = x
 this.y = y
 }
}
let point = sequence(number).andThen((value, error) => {
 if (value.length !== 2) {
 throw error('Expected an array of length 2 but got: ' + value.length)
 }
 return new Point(value[0], value[1])
})
validateObject(point, [1, 2])
// => Point { x: 1, y: 2 }
validateJSON5(point, '[1, 2]')
// => Point { x: 1, y: 2 }
validateJSON5(point, '[1]')
// ValidationError: Expected an array of length 2 but got: 1 (line 1 column 1)

Defining new schema types

Example:

import {Node} from 'validated/schema'
class Point {
 constructor(x, y) {
 this.x = x
 this.y = y
 }
}
class PointNode extends Node {
 validate(context) {
 // prevalidate value with primitive validators
 let prevalidator = sequence(number)
 let {value, context: nextContext} = prevalidator.validate(context)
 // perform additional validations
 if (value.length !== 2) {
 // just report an error, context information such as line/column
 // numbers will be injected automatically
 throw context.error('Expected an array of length 2 but got: ' + value.length)
 }
 // construct a Point object, do whatever you want here
 let [x, y] = value
 let point = new Point(x, y)
 // return constructed value and the next context
 return {value: point, context: nextContext}
 }
}
validateObject(new PointNode(), [1, 2])
// => Point { x: 1, y: 2 }
validateJSON5(new PointNode(), '[1, 2]')
// => Point { x: 1, y: 2 }
validateJSON5(new PointNode(), '[1]')
// ValidationError: Expected an array of length 2 but got: 1 (line 1 column 1)

Integration with FlowType

Validated library uses FlowType extensively. Its API is defined in a way which automatically infers types for produced values:

import {object, string, number} from 'validated/schema'
import {validate} from 'validated/json5'
let personSchema = object({
 name: string,
 age: number,
})
let value: {name: string; age: number} = validate(
 personSchema,
 '{"name": "Andrey", age: 29}'
)

Note that the type annotation isn't needed — FlowType infers the type automatically based on a schema.

About

Validate your configurations with precise error messages

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 98.1%
  • Makefile 1.9%

AltStyle によって変換されたページ (->オリジナル) /