JSPM

  • Created
  • Published
  • Downloads 32759
  • Score
    100M100P100Q141225F
  • License MIT

Type driven schema validator

Package Exports

    This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (schemastery) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

    Readme

    Schemastery

    Codecov downloads npm GitHub

    Type Driven Schema Validator.

    Features

    • Lightweight. Much smaller than other validation libraries.
    • Easy to use. You can use any schema as a function or constructor directly.
    • Powerful. Schemastery supports some advanced types such as union, intersect and transform.
    • Extensible. You can create your own schema types via Schema.extend().
    • Serializable. Schema objects can be serialized into JSON and then be hydrated in another environment.

    Basic Examples

    use as validator (JavaScript)

    const Schema = require('schemastery')
    
    const validate = Schema.number().default(10)
    
    validate(0)     // 0
    validate(null)  // 10
    validate('')    // TypeError

    use as constructor (TypeScript)

    import Schema from 'schemastery'
    
    interface Config {
      foo: Record<string, string>
      bar: string[]
    }
    
    const Config = Schema.object({
      foo: Schema.dict(Schema.string()).default({}),
      bar: Schema.array(Schema.string()).default([]),
    })
    
    // config is an instance of Config
    // in this case, that is { foo: {}, bar: [] }
    const config = new Config()

    General Types

    Schema.any()

    Assert that the value is of any type.

    const validate = Schema.any()
    
    validate()            // undefined
    validate(0)           // 0
    validate({})          // {}

    Schema.never()

    Assert that the value is nullable.

    const validate = Schema.never()
    
    validate()            // undefined
    validate(0)           // TypeError
    validate({})          // TypeError

    Schema.const(value)

    Assert that the value is equal to the given constant.

    const validate = Schema.const(10)
    
    validate(10)          // 10
    validate(0)           // TypeError

    Schema.number()

    Assert that the value is a number.

    const validate = Schema.number()
    
    validate()            // undefined
    validate(1)           // 1
    validate('')          // TypeError

    Schema.string()

    Assert that the value is a string.

    const validate = Schema.string()
    
    validate()            // undefined
    validate(0)           // TypeError
    validate('foo')       // 'foo'

    Schema.boolean()

    Assert that the value is a boolean.

    const validate = Schema.boolean()
    
    validate()            // undefined
    validate(0)           // TypeError
    validate(true)        // true

    Schema.is(constructor)

    Assert that the value is an instance of the given constructor.

    const validate = Schema.is(RegExp)
    
    validate()            // undefined
    validate(/foo/)       // /foo/
    validate('foo')       // TypeError

    Schema.array(inner)

    Assert that the value is an array of inner. The default value will be [] if not specified.

    const validate = Schema.array(Schema.number())
    
    validate()                  // []
    validate(0)                 // TypeError
    validate([0, 1])            // [0, 1]
    validate([0, '1'])          // TypeError

    Schema.dict(inner)

    Assert that the value is a dictionary of inner. The default value will be {} if not specified.

    const validate = Schema.dict(Schema.number())
    
    validate()                  // {}
    validate(0)                 // TypeError
    validate({ a: 0, b: 1 })    // { a: 0, b: 1 }
    validate({ a: 0, b: '1' })  // TypeError

    Schema.tuple(list)

    Assert that the value is a tuple whose each element is of corresponding subtype. The default value will be [] if not specified.

    const validate = Schema.tuple([
      Schema.number(),
      Schema.string(),
    ])
    
    validate()                  // []
    validate([0])               // { a: 0 }
    validate([0, 1])            // TypeError
    validate([0, '1'])          // [0, '1']

    Schema.object(dict)

    Assert that the value is an object whose each property is of corresponding subtype. The default value will be {} if not specified.

    const validate = Schema.object({
      a: Schema.number(),
      b: Schema.string(),
    })
    
    validate()                  // {}
    validate({ a: 0 })          // { a: 0 }
    validate({ a: 0, b: 1 })    // TypeError
    validate({ a: 0, b: '1' })  // { a: 0, b: '1' }

    Schema.union(list)

    Assert that the value is one of the specified types.

    const validate = Schema.union([
      Schema.number(),
      Schema.string(),
    ])
    
    validate()                  // undefined
    validate(0)                 // 0
    validate('1')               // '1'
    validate(true)              // TypeError

    Schema.intersect(list)

    Assert that the value should match each specified type.

    const validate = Schema.intersect([
      Schema.object({ a: Schema.string().required() }),
      Schema.object({ b: Schema.number().default(0) }),
    ])
    
    validate()                  // TypeError
    validate({ a: '' })         // { a: '', b: 0 }
    validate({ a: '', b: 1 })   // { a: '', b: 1 }
    validate({ a: '', b: '2' }) // TypeError

    Schema.transform(inner, callback)

    Assert that the value is of the specified subtype and then transformed by callback.

    const validate = Schema.transform(Schema.number().default(0), n => n + 1)
    
    validate()                  // 1
    validate('0')               // TypeError
    validate(10)                // 11

    Instance Methods

    Note: default and required are mutually exclusive.

    schema.required()

    Assert that the value is not nullable.

    schema.default(value)

    Set the fallback value when nullable.

    schema.description(text)

    Set the description of the schema.

    Shorthand Syntax

    Some shorthand syntax is available for inner types.

    • undefined -> Schema.any()
    • String -> Schema.string()
    • Number -> Schema.number()
    • Boolean -> Schema.boolean()
    • 1 -> Schema.const(1) (only for primitive types)
    • Date -> Schema.is(Date)
    Schema.array(String)        // Schema.array(Schema.string())
    Schema.dict(RegExp)         // Schema.dict(Schema.is(RegExp))
    Schema.union([1, 2])        // Schema.union([Schema.const(1), Schema.const(2)])

    You can also use Schema.from() to get the inferred schema from a shorthand value.

    Schema.from()               // Schema.any()
    Schema.from(Date)           // Schema.is(Date)
    Schema.from('foo')          // Schema.const('foo')

    Advanced Examples

    Here are some examples which demonstrate how to define advanced types.

    Enumeration

    const Enum = Schema.union(['red', 'blue'])
    
    Enum('red')                 // 'red'
    Enum('blue')                // 'blue'
    Enum('green')               // TypeError

    ToString

    const ToString = Schema.transform(Schema.any(), v => String(v))
    
    ToString('')                // ''
    ToString(0)                 // '0'
    ToString({})                // '{}'

    Listable

    const Listable = Schema.union([
      Schema.array(Number),
      Schema.transform(Number, n => [n]),
    ]).default([])
    
    Listable()                  // []
    Listable(0)                 // [0]
    Listable([1, 2])            // [1, 2]

    Alias

    const Config = Schema.dict(Number, Schema.union([
      'foo',
      Schema.transform('bar', () => 'foo'),
    ]))
    
    Config({ foo: 1 })          // { foo: 1 }
    Config({ bar: 2 })          // { foo: 2 }
    Config({ bar: '3' })        // TypeError

    Extensibility

    Serializability

    const schema1 = Schema.object({
      foo: Schema.string(),
      bar: Schema.number(),
    })
    
    // should have the same effect as schema1
    const schema2 = new Schema(JSON.parse(JSON.stringify(schema1)))