New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@alxandr/validated

Package Overview
Dependencies
Maintainers
1
Versions
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@alxandr/validated

JSON configuration utilities

2.0.0
latest
Source
npm
Version published
Weekly downloads
3
Maintainers
1
Weekly downloads
 
Created
Source

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, arrayOf, object, partialObject, oneOf, maybe, enumeration, recur,
  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 = arrayOf(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"
arrayOf

Validate arrays.

Untyped values (value validator defaults to any):

validateObject(arrayOf(any), [])
// => []

validateObject(arrayOf(any), [1, 2, 'ok'])
// => [ 1, 2, 'ok' ]

validateObject(arrayOf(any), 'oops')
// ValidationError: Expected an array but got string

Typed value:

validateObject(arrayOf(number), [1, 2])
// => [ 1, 2 ]

validateObject(arrayOf(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
//
recur

Allows to define recursive validators:

let tree = recur(tree =>
  object({
    value: any,
    children: maybe(arrayOf(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 = arrayOf(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 = arrayOf(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.

FAQs

Package last updated on 17 Jul 2018

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts