confine v3.1.0
confine finely-tuned configuration
We live in a post-Sublime Text age. The cool way to store persistant state is in raw JSON. confine makes it easy to make some simple assertions about what is in that JSON before passing it to your application logic.
Clearly specifying configuration also gives us power when it comes to GUI auto-generation. For example, see react-confine.
confine works similarly to the Config system in the Atom editor, but with no type coercion. It is also modular and extendable, with support for custom types. confine also supports the null type.
Installation
npm install confineUsage
var Confine = require('confine')
var confine = new Confine()
var schema = {
type: 'object',
properties: {
name: {type: 'string'},
age: {type: 'integer', min: 0, max: 120},
income: {type: 'number', min: 0},
universe: {type: 'string', enum: ['Marvel', 'DC']},
living: {type: 'boolean', default: true},
alterEgos: {type: 'array', items: {type: 'string'}},
location: {
type: 'object',
properties: {
city: {type: 'string'},
state: {type: 'string', regex: /[A-Z]{2}/}
}
}
}
}
var object = {
name: 'Peter Parker',
age: 17,
income: 38123.52,
alterEgos: ['Spider-Man'],
universe: 'Marvel',
location: {city: 'New York', state: 'NY'},
girlfriend: 'Mary Jane'
}
console.log(confine.validateSchema(schema)) // true
console.log(confine.normalize(object, schema)) /* {
name: 'Peter Parker',
age: 17,
income: 38123.52,
living: true,
alterEgos: ['Spider-Man'],
universe: 'Marvel',
location: {city: 'New York', state: 'NY'}
} */Methods
confine.validateSchema(schema)
- Returns a
booleanindicating ifschemais valid. This should be checked for any untrusted schema before calling any other method - using an invalid schema with the otherconfinemethods results in undetermined behavior.
confine.normalize(obj, schema)
- Returns an adjusted representation of
obj, removing invalid or unnecessary fields and filling in defaults. - This method should be used to normalize data before it is passed to the logic that uses it. It ensures strictness about types.
- Please note that you do not need to check
validatebefore callingnormalize.normalizeexpects an invalidobj, and will adjust it appropriately. You still must callvalidateSchema, though.
confine.clean(obj, schema)
- Returns an adjusted representation of
objlikenormalize, but does not remove unnecessary fields or fill in defaults. - This method should be used to clean data before it is stored longterm or used by an automatic form generation tool (like react-confine). This allows for improved user experience, because the undefined/default distinction is made clear, and will not result in a loss of data as schemas change.
- You do not need to check
validatebefore callingclean. You still must callvalidateSchema, though. - Due to the fact that JSON does not allow for
undefined, cleaning sparse arrays could result in an object with integer keys and alengthproperty being generated. Such an object may look strange, but is handled in the same way bylodash, and prevents unnecessary overriding ofnull. For example:
var schema = {type: 'array', items: {type: 'string', default: 'x'}}
confine.clean(['a'], schema) // ['a']
confine.normalize(['a'], schema) // ['a']
confine.clean(['a', 42, 'c']) // {0: 'a', 2: 'c', length: 3}
confine.normalize(['a', 42, 'c']) // ['a', 'x', 'c']confine.validate(obj, schema)
- Returns a
booleanindicating ifobjis strictly valid according toschema. - A schema being valid means that
_.isEqual(confine.normalize(obj, schema), obj). That is,normalizeing the object will not change it. - This method should be used rarely. In most cases,
normalizeorcleanshould be preferred.
Confine Schemas
Confine uses a simplified version of JSON Schema to describe JSON objects. Each schema is a JSON object that contains a type property. 7 types are built-in, and custom types can also be added. Types may make use of additional properties, as defined below. Additionally, all types make use of 2 additional properties: default and enum.
defaultis an object that will be returned byconfine.normalizeorconfine.getDefaultif the provided input isundefined. It must be a valid object itself (that is to say,confine.validate(schema.default, schema)must returntrue).enumis an array that enumerates all possible options the value can take. Any input not listed in this array will be rejected. Every array emtry must be a valid object itself (that is to say,_.every(schema.enum, function (e) {return confine.validate(e, schema)})must returntrue.
Please see test/test.js for examples of all of these types in use.
object
Specifies a JSON object mapping string keys to any JSON entity. properties should be itself an object mapping string keys to sub-schemas.
{ type: 'object'
properties: {
myInt: { type: 'integer' }
myString: { type: 'string' } } }
// { myInt: 3, myString: 'something' }array
Specifies a JSON array - an ordered list of entities, all of the same type. items should be a single sub-schema that all array entries match.
{ type: 'array',
items: { type: 'integer' } }
// [ 1, 2, 3 ]number
Specifies a JSON number (integer or decimal). This is held to the same limitations of all numbers in Javascript. max and min can (inclusively) limit possible number ranges.
{ type: 'number',
min: 1.5,
max: 11 }
// 7.2integer
Specifies an integer. This is held to the same limitations of all integers in Javascript. max and min can (inclusively) limit possible number ranges.
{ type: 'integer',
min: 4,
max: 8 }
// 6string
Specifies a JSON string. regex can limit the possible input given a Javascript RegExp object, or a string that can be evaulated as a regular expression.
{ type: 'string',
regex: /.*/ }
// 'something'boolean
Specifies a JSON boolean.
{ type: 'boolean' }
/// falsenull
Specifies JSON null.
{ type: 'null' }
/// nullnullworks slightly differently than other types.confine.normalize(obj, {type: 'null'})will always returnnull, even if_.isUndefined(obj). Thus,confine.validate(undefined, {type: 'null'})returnsfalse.- This means that
confine.normalize(obj, {type: ['string', 'null']})will never returnundefined. Ifobjis not a validstring, it will returnnull. This is a good way of ensuring that there is something in thenormalizeoutput (even if it'snull).
Multiple types
type can be an array of type names. All type names must be valid. When normalizeing undefined, the returned value will be the first one that does not return undefined, or undefined if all types do.
Please note that because number includes integers, {type: ['number', 'integer]} is strictly equivalent to {type: 'number'} alone.
Custom Types
You can add custom types by setting properties on confine.types. By default, it understands integer, number, string, boolean, array, object, and null. A custom type is simply an object that contains the following functions.
confine.types['typeName'] = {
validateSchema: function (schema, confine) {...},
validate: function (obj, schema, confine) {...},
normalize: function (obj, schema, confine) {...} // optional
}validateSchema(schema, confine)
- Should return a boolean indicating if
schemais valid. confineis provided for subschema parsing (seelib/array).
validate(obj, schema, confine)
- should return a boolean indiciating if the
objfitsschema. confineis provided for subschema parsing (seelib/array).
normalize(obj, schema, confine) // optional
- should return a version of obj adjusted to fit the schema
- if not provided,
normalizewill returndefaultif it exists, orundefined - do not use this to coerce values - this should only be used for adjusting subschema parsing
- see
lib/objectfor an example