Socket
Socket
Sign inDemoInstall

js-schema

Package Overview
Dependencies
Maintainers
1
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

js-schema - npm Package Compare versions

Comparing version 0.5.0 to 0.6.1

build.sh

12

HISTORY.md
Version history
===============
### 0.6.1 (2012-08-19) ###
* Minor bugfixes
### 0.6.0 (2012-08-18) ###
* Support for general purpose referencing (with JSON Schema serialization/deserialization)
* Property description support
* Splitting out random generation into a separate library (molnarg/random.js)
* Removal of the premature compilation system (optimizations will reappear in a future release)
* Cleaner codebase
* Js-schema is now self-contained: it has no dependencies
* Reduced size: 15kb -> 5kb (minified and gzipped)
### 0.5.0 (2012-06-27) ###

@@ -5,0 +17,0 @@ * Support for self-referencing

4

index.js
module.exports = require('./lib/schema')
// Core schemas
// Patterns
require('./lib/patterns/reference')

@@ -12,2 +12,3 @@ require('./lib/patterns/nothing')

require('./lib/patterns/class')
require('./lib/patterns/schema')

@@ -21,1 +22,2 @@ // Extensions

require('./lib/extensions/Function')
require('./lib/extensions/Schema')

@@ -1,95 +0,55 @@

var schema = require('../schema')
var Schema = require('../Schema')
, EqualitySchema = require('../patterns/equality')
, anything = require('../patterns/anything')
, _ = require('underscore')
, RandExp = require('randexp')
, anything = require('../patterns/anything').instance
var ArraySchema = module.exports = function(itemSchema, max, min) {
this.itemSchema = itemSchema || anything
this.min = min || 0
this.max = max || Infinity
return new schema(this)
}
var ArraySchema = module.exports = Schema.extensions.ArraySchema = Schema.extend({
initialize : function(itemSchema, max, min) {
this.itemSchema = itemSchema || anything
this.min = min || 0
this.max = max || Infinity
},
ArraySchema.prototype = {
compile : function() {
var compiled = { }
validate : function(instance) {
// Instance must be an instance of Array
compiled.fn = 'if (!(instance instanceof Array)) return false;'
if (!(instance instanceof Array)) return false
// Checking length
if (this.min > 0 || this.max < Infinity) {
var checks = []
if (this.min === this.max) {
checks.push('instance.length !== ' + this.min)
} else {
if (this.min > 0 ) checks.push('instance.length < ' + this.min)
if (this.max < Infinity) checks.push('instance.length > ' + this.max)
}
compiled.fn += 'if (' + checks.join(' || ') + ') return false;'
if (this.min === this.max) {
if (instance.length !== this.min) return false
} else {
if (this.min > 0 && instance.length < this.min) return false
if (this.max < Infinity && instance.length > this.max) return false
}
// Checking conformance to the given item schema
if (this.itemSchema !== anything) {
compiled.references = [this.itemSchema]
compiled.fn += 'for (var i = 0; i < instance.length; i++) {'
+ ' if (!{0}(instance[i])) return false;'
+ '}'
for (var i = 0; i < instance.length; i++) {
if (!this.itemSchema.validate(instance[i])) return false;
}
// If every check passes, return true
compiled.fn += 'return true;'
return compiled
return true
},
generate : function() {
var array = []
while (array.length < this.min || (array.length < this.max && Math.random() < 0.666)) {
array.push(this.itemSchema.generate())
}
return array
},
leafs : function() {
var item_leafs = this.itemSchema.leafs ? this.itemSchema.leafs()
: { certain : [ this.itemSchema ], uncertain : [] }
if (this.min > 0) return item_leafs
return { certain : []
, uncertain : _.union(item_leafs.certain, item_leafs.uncertain)
}
},
getId : function() {
if (!this.id) this.id = new RandExp(/^[a-zA-Z]{4,6}$/).gen()
return this.id
},
toJSON : function() {
var schema = { type : 'array' }
if (this.min > 0 ) schema.minItems = this.min
if (this.max < Infinity) schema.maxItems = this.max
if (this.itemSchema !== anything) schema.items = this.itemSchema.toJSON()
if (this.id) schema.id = this.id
return schema
}
}
schema.fromJSON.def(function(sch) {
toJSON : Schema.session(function() {
var json = Schema.prototype.toJSON.call(this, true)
if (json['$ref'] != null) return json
json.tpye = 'array'
if (this.min > 0) json.minItems = this.min
if (this.max < Infinity) json.maxItems = this.max
if (this.itemSchema !== anything) json.items = this.itemSchema.toJSON()
return json
})
})
Schema.fromJSON.def(function(sch) {
if (!sch || sch.type !== 'array') return
// Tuple typing is not yet supported
if (sch.items instanceof Array) return
return new ArraySchema(schema.fromJSON(sch.items), sch.maxItems, sch.minItems)
return new ArraySchema(Schema.fromJSON(sch.items), sch.maxItems, sch.minItems)
})

@@ -101,12 +61,11 @@

// (minLength, maxLength, schema)
var args = Array.prototype.reverse.call(arguments)
var args = Array.prototype.slice.call(arguments).reverse()
if (args.length === 2) args[2] = args[1]
return new ArraySchema(schema.fromJS(args[0]), args[1], args[2])
return new ArraySchema(Schema.fromJS(args[0]), args[1], args[2]).wrap()
}
Array.like = function(other) {
return new EqualitySchema(other)
return new EqualitySchema(other).wrap()
}
Array.schema = new ArraySchema()
Array.schema = new ArraySchema().wrap()

@@ -1,11 +0,7 @@

var schema = require('../schema')
var Schema = require('../Schema')
var booleanSchema = module.exports = new schema({
compile : function() {
return { expression : 'Object(instance) instanceof Boolean' }
var BooleanSchema = module.exports = Schema.extensions.BooleanSchema = new Schema.extend({
validate : function(instance) {
return Object(instance) instanceof Boolean
},
generate : function() {
return Math.random() < 0.5
},

@@ -17,5 +13,7 @@ toJSON : function() {

schema.fromJSON.def(function(sch) {
var booleanSchema = module.exports = new BooleanSchema().wrap()
Schema.fromJSON.def(function(sch) {
if (!sch || sch.type !== 'boolean') return
return booleanSchema

@@ -22,0 +20,0 @@ })

var ReferenceSchema = require('../patterns/reference')
, ClassSchema = require('../patterns/class')
// Function creation is not possible the way patterns/class.js does,
// so overriding it here
Function.schema = new ClassSchema(Function)
Function.schema.generate = function() {
return function() {}
}
Function.reference = function(f) {
return new ReferenceSchema(f)
return new ReferenceSchema(f).wrap()
}

@@ -1,122 +0,82 @@

var schema = require('../schema')
var Schema = require('../Schema')
var NumberSchema = module.exports = function(minimum, exclusiveMinimum, maximum, exclusiveMaximum, divisibleBy) {
this.minimum = minimum != null ? minimum : -Infinity
this.exclusiveMinimum = exclusiveMinimum
this.maximum = minimum != null ? maximum : Infinity
this.exclusiveMaximum = exclusiveMaximum
this.divisibleBy = divisibleBy || 0
return new schema(this)
}
var NumberSchema = module.exports = Schema.extensions.NumberSchema = Schema.extend({
initialize : function(minimum, exclusiveMinimum, maximum, exclusiveMaximum, divisibleBy) {
this.minimum = minimum != null ? minimum : -Infinity
this.exclusiveMinimum = exclusiveMinimum
this.maximum = minimum != null ? maximum : Infinity
this.exclusiveMaximum = exclusiveMaximum
this.divisibleBy = divisibleBy || 0
},
NumberSchema.prototype = {
min : function(minimum) {
return new NumberSchema(minimum, false, this.maximum, this.exclusiveMaximum, this.divisibleBy)
return new NumberSchema( minimum, false
, this.maximum, this.exclusiveMaximum
, this.divisibleBy
).wrap()
},
above : function(minimum) {
return new NumberSchema(minimum, true, this.maximum, this.exclusiveMaximum, this.divisibleBy)
return new NumberSchema( minimum, true
, this.maximum, this.exclusiveMaximum
, this.divisibleBy
).wrap()
},
max : function(maximum) {
return new NumberSchema(this.minimum, this.exclusiveMinimum, maximum, false, this.divisibleBy)
return new NumberSchema( this.minimum, this.exclusiveMinimum
, maximum, false
, this.divisibleBy
).wrap()
},
below : function(maximum) {
return new NumberSchema(this.minimum, this.exclusiveMinimum, maximum, true, this.divisibleBy)
return new NumberSchema( this.minimum, this.exclusiveMinimum
, maximum, true
, this.divisibleBy
).wrap()
},
step : function(divisibleBy) {
return new NumberSchema(this.minimum, this.exclusiveMinimum, this.maximum, this.exclusiveMaximum, divisibleBy)
return new NumberSchema( this.minimum, this.exclusiveMinimum
, this.maximum, this.exclusiveMaximum
, divisibleBy
).wrap()
},
compile : function() {
var references = [this.minimum, this.maximum, this.divisibleBy]
, checks = ['Object(instance) instanceof Number']
if (this.minimum !== -Infinity) {
checks.push('instance ' + (this.exclusiveMinimum ? '>' : '>=') + ' {0}')
}
if (this.maximum !== Infinity) {
checks.push('instance ' + (this.exclusiveMaximum ? '<' : '<=') + ' {1}')
}
if (this.divisibleBy !== 0) {
checks.push('instance % {2} === 0')
}
return { references : references, expression : checks.join(' && ') }
publicFunctions : [ 'min', 'above', 'max', 'below', 'step' ],
validate : function(instance) {
return (Object(instance) instanceof Number) &&
(this.exclusiveMinimum ? instance > this.minimum
: instance >= this.minimum) &&
(this.exclusiveMaximum ? instance < this.maximum
: instance <= this.maximum) &&
(this.divisibleBy === 0 || instance % this.divisibleBy === 0)
},
generate : function() {
var length, random
, min = this.minimum
, max = this.maximum
, step = this.divisibleBy
// If there's no declared maximum or minimum then assigning a reasonable value
if (min === -Infinity || max === Infinity) {
length = 10
while (Math.random() < 0.5) length = length * 10
toJSON : function() {
var json = Schema.prototype.toJSON.call(this)
if (min === -Infinity && max === Infinity) {
min = length / -2
max = length / +2
} else if (min === -Infinity) {
min = max - length
} else if (max === Infinity) {
max = min + length
}
}
// Choosing random number from a continuous set
if (step === 0) {
length = max - min
do {
random = min + Math.random()*length
} while ((this.exclusiveMinimum && random === min) || (this.exclusiveMaximum && random === max))
// Choosing random number from a discrete set
} else {
min = Math.ceil(min / step) * step
max = Math.floor(max / step) * step
if (this.exclusiveMinimum && min === this.minimum) min += step
if (this.exclusiveMaximum && max === this.maximum) max -= step
if (min > max) return undefined
length = Math.round((max - min) / step) + 1
random = min + step * Math.floor(Math.random()*length)
}
return random
},
json.type = ( this.divisibleBy !== 0 && this.divisibleBy % 1 === 0 ) ? 'integer' : 'number'
toJSON : function() {
var step = this.divisibleBy
, integer = ( step !== 0 && step === Math.floor(step) )
, schema = { type : integer ? 'integer' : 'number' }
if (step !== 0 && step !== 1) schema.divisibleBy = step
if (this.divisibleBy !== 0 && this.divisibleBy !== 1) json.divisibleBy = this.divisibleBy
if (this.minimum !== -Infinity) {
schema.minimum = this.minimum
if (this.exclusiveMinimum === true) schema.exclusiveMinimum = true
json.minimum = this.minimum
if (this.exclusiveMinimum === true) json.exclusiveMinimum = true
}
if (this.maximum !== Infinity) {
schema.maximum = this.maximum
if (this.exclusiveMaximum === true) schema.exclusiveMaximum = true
json.maximum = this.maximum
if (this.exclusiveMaximum === true) json.exclusiveMaximum = true
}
return schema
return json
}
}
})
schema.fromJSON.def(function(sch) {
Schema.fromJSON.def(function(sch) {
if (!sch || (sch.type !== 'number' && sch.type !== 'integer')) return
return new NumberSchema( sch.minimum, sch.exclusiveMinimum

@@ -128,3 +88,3 @@ , sch.maximum, sch.exclusiveMaximum

Number.schema = new NumberSchema()
Number.schema = new NumberSchema().wrap()
Number.min = Number.schema.min

@@ -131,0 +91,0 @@ Number.above = Number.schema.above

@@ -6,9 +6,9 @@ var ReferenceSchema = require('../patterns/reference')

Object.like = function(other) {
return new EqualitySchema(other)
return new EqualitySchema(other).wrap()
}
Object.reference = function(o) {
return new ReferenceSchema(o)
return new ReferenceSchema(o).wrap()
}
Object.schema = new ObjectSchema()
Object.schema = new ObjectSchema().wrap()

@@ -7,3 +7,3 @@ var RegexpSchema = require('../patterns/regexp')

// (minLength, maxLength, charset)
var args = Array.prototype.reverse.call(arguments)
var args = Array.prototype.slice.call(arguments).reverse()
, charset = args[0] ? ('[' + args[0] + ']') : '[a-zA-Z0-9]'

@@ -13,6 +13,6 @@ , max = args[1]

, regexp = '^' + charset + '{' + (min || 0) + ',' + (max || '') + '}$'
return new RegexpSchema(RegExp(regexp))
return new RegexpSchema(RegExp(regexp)).wrap()
}
String.schema = new RegexpSchema()
String.schema = new RegexpSchema().wrap()

@@ -1,13 +0,7 @@

var schema = require('../schema')
, nothing = require('./nothing')
var Schema = require('../Schema')
var anything = module.exports = new schema({
compile : function() {
return { expression : 'instance != null' }
var AnythingSchema = module.exports = Schema.patterns.AnythingSchema = Schema.extend({
validate : function(instance) {
return instance != null
},
generate : function() {
var type = [nothing, Boolean, Number, String, Array, Object][Math.floor(Math.random()*6)]
return type.schema.generate()
},

@@ -19,8 +13,10 @@ toJSON : function() {

schema.fromJS.def(function(sch) {
var anything = AnythingSchema.instance = new AnythingSchema()
Schema.fromJS.def(function(sch) {
if (sch === undefined) return anything
})
schema.fromJSON.def(function(sch) {
Schema.fromJSON.def(function(sch) {
if (sch.type === 'any') return anything
})

@@ -1,28 +0,19 @@

var schema = require('../schema')
var Schema = require('../Schema')
var ClassSchema = module.exports = function(constructor) {
this.constructor = constructor
return new schema(this)
}
var ClassSchema = module.exports = Schema.patterns.ClassSchema = Schema.extend({
initialize : function(constructor) {
this.constructor = constructor
},
ClassSchema.prototype = {
compile : function() {
return { references : [this.constructor], expression : 'instance instanceof {0}' }
},
generate : function() {
var Constructor = function() {}
Constructor.prototype = this.constructor.prototype
return new Constructor()
validate : function(instance) {
return instance instanceof this.constructor
}
}
})
schema.fromJS.def(function(constructor) {
Schema.fromJS.def(function(constructor) {
if (!(constructor instanceof Function)) return
if (constructor.schema instanceof Function) {
return constructor.schema
return constructor.schema.unwrap()
} else {

@@ -29,0 +20,0 @@ return new ClassSchema(constructor)

@@ -1,2 +0,2 @@

var schema = require('../schema')
var Schema = require('../Schema')

@@ -7,11 +7,9 @@ // Object deep equality

if (Object(a) !== a || Object(b) !== b) return a === b
// both a and b must be Array, or none of them
if ((a instanceof Array && !(b instanceof Array)) || (!(a instanceof Array) && b instanceof Array)) {
return false
}
if ((a instanceof Array) !== (b instanceof Array)) return false
// they must have the same number of properties
if (Object.keys(a).length !== Object.keys(b).length) return false
// and every property should be equal

@@ -21,3 +19,3 @@ for (var key in a) {

}
// if every check succeeded, they are deep equal

@@ -27,21 +25,23 @@ return true

var EqualitySchema = module.exports = function(object) {
this.object = object
return new schema(this)
}
var EqualitySchema = module.exports = Schema.patterns.EqualitySchema = Schema.extend({
initialize : function(object) {
this.object = object
},
EqualitySchema.prototype = {
validate : function(instance) {
return equal(instance, this.object)
},
toJSON : function() {
return { 'enum' : [this.object] }
var json = Schema.prototype.toJSON.call(this)
json['enum'] = [this.object]
return json
}
}
})
schema.fromJS.def(function(sch) {
Schema.fromJS.def(function(sch) {
if (sch instanceof Array && sch.length === 1) return new EqualitySchema(sch[0])
})

@@ -1,12 +0,8 @@

var schema = require('../schema')
var Schema = require('../Schema')
var nothing = module.exports = new schema({
compile : function() {
return { expression : 'instance == null' }
var NothingSchema = module.exports = Schema.patterns.NothingSchema = Schema.extend({
validate : function(instance) {
return instance == null
},
generate : function() {
return Math.random() < 0.5 ? null : undefined
},
toJSON : function() {

@@ -17,8 +13,10 @@ return { type : 'null' }

schema.fromJS.def(function(sch) {
var nothing = NothingSchema.instance = new NothingSchema()
Schema.fromJS.def(function(sch) {
if (sch === null) return nothing
})
schema.fromJSON.def(function(sch) {
Schema.fromJSON.def(function(sch) {
if (sch.type === 'null') return nothing
})

@@ -1,152 +0,68 @@

var schema = require('../schema')
, RandExp = require('randexp')
, utils = require('../utils')
, anything = require('./anything')
, nothing = require('./nothing')
, _ = require('underscore')
var Schema = require('../Schema')
, anything = require('./anything').instance
, nothing = require('./nothing').instance
var ObjectSchema = module.exports = function(properties, other) {
var self = this
this.other = other || anything
this.properties = properties || []
// Sorting properties into two groups
this.stringProps = {}, this.regexpProps = []
this.properties.forEach(function(property) {
if (typeof property.key === 'string') {
self.stringProps[property.key] = property
} else {
self.regexpProps.push(property)
}
})
return new schema(this)
}
var ObjectSchema = module.exports = Schema.patterns.ObjectSchema = Schema.extend({
initialize : function(properties, other) {
var self = this
ObjectSchema.prototype = {
compile : function() {
var checks = ['instance != null']
, references = []
, ref = utils.referenceHandler(references)
this.other = other || anything
this.properties = properties || []
// Sorting properties into two groups
this.stringProps = {}, this.regexpProps = []
this.properties.forEach(function(property) {
if (typeof property.key === 'string') {
self.stringProps[property.key] = property
} else {
self.regexpProps.push(property)
}
})
},
validate : function(instance) {
var self = this
if (instance == null) return false
// Simple string properties
var check
for (var key in this.stringProps) {
check = '{schema}(instance[{key}])'.replace('{schema}', ref(this.stringProps[key].value))
.replace('{key}', ref(key))
if (this.stringProps[key].min === 0) {
check = '(instance[{key}] === undefined || {check})'.replace('{key}', ref(key))
.replace('{check}', check)
}
checks.push(check)
}
if (!this.regexpProps.length && this.other === anything) {
return { references : references, expression : checks.join(' && ') }
}
var stringPropsValid = Object.keys(this.stringProps).every(function(key) {
return (self.stringProps[key].min === 0 && !(key in instance)) ||
(self.stringProps[key].value.validate(instance[key]))
})
if (!stringPropsValid) return false
// If there are no RegExp and other validator, that's all
if (!this.regexpProps.length && this.other === anything) return true
// Regexp and other properties
var stringPropNames = Object.keys(this.stringProps)
var fn = 'if (!( {checks} )) return false;'.replace('{checks}', checks.join(' && '))
if (this.other !== anything) fn += 'var checked;'
// Iterating over the keys in the instance
fn += 'for (var key in instance) {'
var checked
for (var key in instance) {
// Checking the key against every key regexps
if (this.other !== anything) fn += 'checked = false;'
for (var i = 0; i < this.regexpProps.length; i++) {
if (this.other !== anything) {
check = 'if (({regexp}.test(key) && (checked = true)) && !{schema}(instance[key])) return false;'
} else {
check = 'if ({regexp}.test(key) && !{schema}(instance[key])) return false;'
}
fn += check.replace('{regexp}', ref(this.regexpProps[i].key))
.replace('{schema}', ref(this.regexpProps[i].value))
}
// If the key is not matched by regexps and by simple string checks, check it against this.other
if (this.other !== anything) {
check = 'if (!checked && {stringProps}.indexOf(key) === -1 && !{other}(instance[key])) return false;'
fn += check.replace('{stringProps}', ref(stringPropNames))
.replace('{other}', ref(this.other))
}
fn += '}'
// Iteration ends
checked = false
var regexpPropsValid = Object.keys(this.regexpProps).every(function(key) {
return (!self.regexpProps[key].key.test(key) ||
((checked = true) && self.regexpProps[key].value.validate(instance[key]))
)
})
if (!regexpPropsValid) return false
// If the key is not matched by regexps and by simple string checks
// then check it against this.other
if (!checked && !(key in this.stringProps) && !this.other.validate(instance[key])) return false
}
// If all checks passed, the instance conforms to the schema
fn += 'return true;'
return { references : references, fn : fn }
return true
},
generate : function() {
var object = {}
for (var key in this.stringProps) {
if (this.stringProps[key].min === 1 || Math.random() < 0.5) {
object[key] = this.stringProps[key].value.generate()
}
}
var n, property, randexp
for (var i = 0; i < this.regexpProps.length; i++) {
property = this.regexpProps[i]
n = Object.keys(object).filter(function(ikey){ return property.key.test(ikey) }).length
randexp = new RandExp(property.key)
while (n < property.min || (n < property.max && Math.random() < 0.5)) {
key = randexp.gen()
if (key in object) continue
object[key] = property.value.generate()
n += 1
}
}
toJSON : Schema.session(function() {
var i, property, regexp, json = Schema.prototype.toJSON.call(this, true)
if (this.other !== nothing) {
while (Math.random() < 0.5) {
key = String.schema.generate()
if (!(key in object)) object[key] = this.other.generate()
}
}
if (json['$ref'] != null) return json
return object
},
leafs : function() {
var certain = [], uncertain = []
this.properties.forEach(function(property) {
var property_leafs = property.value.leafs ? property.value.leafs()
: { certain : [ property.value ], uncertain : [] }
if (property.min > 0) {
certain.push(property_leafs.certain)
uncertain.push(property_leafs.uncertain)
} else {
uncertain.push(property_leafs.uncertain)
uncertain.push(property_leafs.certain)
}
})
return { certain : _.union.apply(null, certain)
, uncertain : _.union.apply(null, uncertain.concat([this.other]))
}
},
getId : function() {
if (!this.id) this.id = new RandExp(/^[a-zA-Z]{4,6}$/).gen()
return this.id
},
toJSON : function() {
var i, property, regexp, json = { type : 'object' }
json.type = 'object'
for (i in this.stringProps) {

@@ -157,4 +73,5 @@ property = this.stringProps[i]

if (property.min === 1) json.properties[property.key].required = true
if (property.title) json.properties[property.key].title = property.title
}
for (i = 0; i < this.regexpProps.length; i++) {

@@ -166,13 +83,12 @@ property = this.regexpProps[i]

json.patternProperties[regexp] = property.value.toJSON()
if (property.title) json.patternProperties[regexp].title = property.title
}
if (this.other !== anything) {
json.additionalProperties = (this.other === nothing) ? false : this.other.toJSON()
}
if (this.id) json.id = this.id
return json
}
}
})
})

@@ -190,6 +106,6 @@ // Testing if a given string is a real regexp or just a single string escaped

})
return function(string) {
var i, j, match
for (i = 0; i < shouldBeEscaped.length; i++) {

@@ -211,3 +127,3 @@ match = string.match(shouldBeEscaped[i])

}
// It is not a real regexp. Removing the escaping.

@@ -219,3 +135,3 @@ for (i = 0; i < shouldBeEscaped.length; i++) {

}
return string

@@ -225,52 +141,62 @@ }

schema.fromJS.def(function(object) {
Schema.fromJS.def(function(object) {
if (!(object instanceof Object)) return
var first, min, max, value, properties = [], other
var other, property, properties = []
for (var key in object) {
value = schema.fromJS(object[key])
property = { value : Schema.fromJS(object[key]) }
// '*' as property name means 'every other property should match this schema'
if (key === '*') {
other = value
other = property.value
continue
}
first = key[0]
min = (first === '*' || first === '?') ? 0 : 1
max = (first === '*' || first === '+') ? Infinity : 1
if (first === '*' || first === '?' || first === '+') key = key.substr(1)
key = regexpString(key)
properties.push({ min : min, max : max, key : key, value : value })
// Handling special chars at the beginning of the property name
property.min = (key[0] === '*' || key[0] === '?') ? 0 : 1
property.max = (key[0] === '*' || key[0] === '+') ? Infinity : 1
key = key.replace(/^[*?+]/, '')
// Handling property title that looks like: { 'a : an important property' : Number }
key = key.replace(/\s*:[^:]+$/, function(match) {
property.title = match.replace(/^\s*:\s*/, '')
return ''
})
// Testing if it is regexp-like or not. If it is, then converting to a regexp object
property.key = regexpString(key)
properties.push(property)
}
return new ObjectSchema(properties, other)
})
schema.fromJSON.def(function(sch) {
if (!sch || sch.type !== 'object') return
Schema.fromJSON.def(function(json) {
if (!json || json.type !== 'object') return
var key, properties = []
for (key in sch.properties) {
properties.push({ min : sch.properties[key].required ? 1 : 0
for (key in json.properties) {
properties.push({ min : json.properties[key].required ? 1 : 0
, max : 1
, key : key
, value : schema.fromJSON(sch.properties[key])
, value : Schema.fromJSON(json.properties[key])
, title : json.properties[key].title
})
}
for (key in sch.patternProperties) {
for (key in json.patternProperties) {
properties.push({ min : 0
, max : Infinity
, key : RegExp('^' + key + '$')
, value : schema.fromJSON(sch.properties[key])
, value : Schema.fromJSON(json.patternProperties[key])
, title : json.patternProperties[key].title
})
}
var other
if (sch.additionalProperties !== undefined) {
other = sch.additionalProperties === false ? nothing : schema.fromJSON(sch.additionalProperties)
if (json.additionalProperties !== undefined) {
other = json.additionalProperties === false ? nothing : Schema.fromJSON(json.additionalProperties)
}
return new ObjectSchema(properties, other)
})

@@ -1,82 +0,50 @@

var schema = require('../schema')
var Schema = require('../Schema')
, EqualitySchema = require('../patterns/equality')
, _ = require('underscore')
, RandExp = require('randexp')
var OrSchema = module.exports = function(schemas) {
this.schemas = schemas
return new schema(this)
}
var OrSchema = module.exports = Schema.patterns.OrSchema = Schema.extend({
initialize : function(schemas) {
this.schemas = schemas
},
OrSchema.prototype = {
compile : function() {
var compiled = { references : this.schemas.slice() }
var checks = this.schemas.map(function(sch, i) { return '{' + i + '}(instance)' })
compiled.expression = checks.join(' || ')
return compiled
validate : function(instance) {
return this.schemas.some(function(sch) {
return sch.validate(instance)
})
},
generate : function() {
return this.schemas[Math.floor(Math.random()*this.schemas.length)].generate()
},
leafs : function() {
// Certain and uncertain leafs of subschemas
var subschema_leafs = this.schemas.map(function(sub) {
return sub.leafs ? sub.leafs()
: { certain : [ sub ], uncertain : [] }
})
subschema_leafs.certain = subschema_leafs.map(function(leafs){ return leafs.certain })
subschema_leafs.uncertain = subschema_leafs.map(function(leafs){ return leafs.uncertain })
// If some leaf appears in all subschemas as certain then it is certain. Otherwise uncertain.
var all = _.union.apply(null, subschema_leafs.certain.concat(subschema_leafs.uncertain))
var certain = _.intersection.apply(null, subschema_leafs.certain)
var uncertain = _.difference(all, certain)
return { certain : certain, uncertain : uncertain }
},
getId : function() {
if (!this.id) this.id = new RandExp(/^[a-zA-Z]{4,6}$/).gen()
return this.id
},
toJSON : function() {
var jsons = this.schemas.map(schema.toJSON)
var onlyEquality = true
for (var i = 0; i < jsons.length; i++) {
if (!(jsons[i]['enum'] instanceof Array && jsons[i]['enum'].length === 1)) {
onlyEquality = false
break
}
toJSON : Schema.session(function() {
var json = Schema.prototype.toJSON.call(this, true)
, subjsons = this.schemas.map(function(sch) { return sch.toJSON() })
, onlyEquality = subjsons.every(function(json) {
return json['enum'] instanceof Array && json['enum'].length === 1
})
if (json['$ref'] != null) return json
if (onlyEquality) {
json['enum'] = subjsons.map(function(json) {
return json['enum'][0]
})
} else {
json['type'] = subjsons.map(function(json) {
var simpleType = typeof json.type === 'string' && Object.keys(json).length === 1
return simpleType ? json.type : json
})
}
if (onlyEquality) return { 'enum' : jsons.map(function(json) { return json['enum'][0] }) }
var json = { 'type' : jsons.map(function(json) {
var simpleType = typeof json.type === 'string' && Object.keys(json).length === 1
return simpleType ? json.type : json
})}
if (this.id) schema.id = this.id
return json
}
}
})
})
schema.fromJS.def(function(schemas) {
Schema.fromJS.def(function(schemas) {
if (schemas instanceof Array) return new OrSchema(schemas.map(function(sch) {
return sch === undefined ? schema.self : schema.fromJS(sch)
return sch === undefined ? Schema.self : Schema.fromJS(sch)
}))
})
schema.fromJSON.def(function(sch) {
Schema.fromJSON.def(function(sch) {
if (!sch) return
if (sch['enum'] instanceof Array) {

@@ -87,8 +55,8 @@ return new OrSchema(sch['enum'].map(function(object) {

}
if (sch['type'] instanceof Array) {
return new OrSchema(sch['type'].map(function(type) {
return schema.fromJSON(typeof type === 'string' ? { type : type } : type)
return Schema.fromJSON(typeof type === 'string' ? { type : type } : type)
}))
}
})

@@ -1,26 +0,24 @@

var schema = require('../schema')
var Schema = require('../Schema')
var ReferenceSchema = module.exports = function(value) {
this.value = value
return new schema(this)
}
var ReferenceSchema = module.exports = Schema.patterns.ReferenceSchema = Schema.extend({
initialize : function(value) {
this.value = value
},
ReferenceSchema.prototype = {
compile : function() {
return { references : [this.value], expression : 'instance === {0}' }
validate : function(instance) {
return instance === this.value
},
generate : function() {
return this.value
},
toJSON : function() {
return { 'enum' : [this.value] }
var json = Schema.prototype.toJSON.call(this)
json['enum'] = [this.value]
return json
}
}
})
schema.fromJS.def(function(value) {
Schema.fromJS.def(function(value) {
return new ReferenceSchema(value)
})

@@ -1,45 +0,33 @@

var schema = require('../schema')
, RandExp = require('randexp')
var Schema = require('../Schema')
var defaultRandExp = new RandExp(/^[a-zA-Z0-9]{1,10}$/)
var RegexpSchema = module.exports = Schema.patterns.RegexpSchema = Schema.extend({
initialize : function(regexp) {
this.regexp = regexp
},
var RegexpSchema = module.exports = function(regexp) {
this.regexp = regexp
this.randexp = this.regexp ? new RandExp(this.regexp) : defaultRandExp
return new schema(this)
}
validate : function(instance) {
return Object(instance) instanceof String && (!this.regexp || this.regexp.test(instance))
},
RegexpSchema.prototype = {
compile : function() {
return { references : [this.regexp]
, expression : 'Object(instance) instanceof String'
+ (this.regexp ? ' && {0}.test(instance)' : '')
}
},
generate : function() {
return this.randexp.gen()
},
toJSON : function() {
var sch = { type : 'string' }
var json = Schema.prototype.toJSON.call(this)
json.type = 'string'
if (this.regexp) {
console.log(this.regexp.toString())
sch.pattern = this.regexp.toString()
sch.pattern = sch.pattern.substr(1, sch.pattern.length - 2)
json.pattern = this.regexp.toString()
json.pattern = json.pattern.substr(1, json.pattern.length - 2)
}
return sch
return json
}
}
})
schema.fromJSON.def(function(sch) {
Schema.fromJSON.def(function(sch) {
if (!sch || sch.type !== 'string') return
if ('pattern' in sch) {
return new RegexpSchema(RegExp('^' + sch.pattern + '$'))
} else if ('minLength' in sch || 'maxLength' in sch) {
return new RegexpSchema(RegExp('^.{' + (sch.minLength || 0) + ',' + (sch.maxLength || '') + '}$'))
return new RegexpSchema(RegExp('^.{' + [ sch.minLength || 0, sch.maxLength ].join(',') + '}$'))
} else {

@@ -50,4 +38,4 @@ return new RegexpSchema()

schema.fromJS.def(function(regexp) {
Schema.fromJS.def(function(regexp) {
if (regexp instanceof RegExp) return new RegexpSchema(regexp)
})

@@ -1,92 +0,41 @@

var def = require('def.js')
, linker = require('./linker')
var Schema = require('./Schema')
var schema = module.exports = function(schemaObject) {
// When called as simple function, forward everything to fromJS, and then seal the resulting schema
if (!(this instanceof schema)) return schema.fromJS.apply(null, arguments).seal()
// When called with new, transform the parameter schema object to a compiled schema function
if (!schemaObject.compile && !schemaObject.validate) {
throw new Error('Schema definition objects must have either compile or validate function.')
var schema = module.exports = function(schemaDescription) {
var doc, schemaObject
if (arguments.length === 2) {
doc = schemaDescription
schemaDescription = arguments[1]
}
var validate = schemaObject.compile ? linker.link(schemaObject.compile())
: schemaObject.validate.bind(schemaObject)
validate.seal = function() {
if (schemaObject.sealed) return validate
schemaObject.sealed = true
if (schemaObject.leafs) {
var leafs = schemaObject.leafs()
if (leafs.certain.indexOf(schema.self) !== -1) {
throw new Error('There\'s no object that satisfies this schema because of necessary recursion.')
}
if (leafs.uncertain.indexOf(schema.self) !== -1) {
// If the validate function is compiled then recompiling it with self inlining
if (validate.assembly) {
var newValidate = linker.link(schemaObject.compile(), schema.self)
for (var key in validate) newValidate[key] = validate[key]
newValidate.schema = newValidate
validate = newValidate
}
// schema.self needs to be pointed to this schema, and then it must be reset
schema.self.set(validate)
schema.self = new SelfSchema()
}
}
delete validate.assembly
return validate
if (this instanceof schema) {
// When called with new, create a schema object and then return the schema function
var constructor = Schema.extend(schemaDescription)
schemaObject = new constructor()
if (doc) schemaObject.doc = doc
return schemaObject.wrap()
} else {
// When called as simple function, forward everything to fromJS
// and then resolve schema.self to the resulting schema object
schemaObject = Schema.fromJS(schemaDescription)
schema.self.resolve(schemaObject)
if (doc) schemaObject.doc = doc
return schemaObject.wrap()
}
validate.schema = validate
for (var key in schemaObject) {
if (schemaObject[key] instanceof Function && !schemaObject[key].schema) {
validate[key] = schemaObject[key].bind(schemaObject)
}
}
return validate
}
schema.Schema = Schema
var SelfSchema = function() {
return new schema(this)
schema.toJSON = function(sch) {
return Schema.fromJS(sch).toJSON()
}
SelfSchema.prototype = {
set : function(target) {
if (!this.target) this.target = target
},
validate : function(instance) {
return this.target(instance)
},
generate : function() {
return this.target.generate()
},
toJSON : function() {
return { '$ref' : this.target.getId() }
}
schema.fromJS = function(sch) {
return Schema.fromJS(sch).wrap()
}
schema.self = new SelfSchema()
schema.fromJS = def()
schema.fromJSON = def()
schema.toJSON = function(sch) {
return schema(sch).toJSON()
schema.fromJSON = function(sch) {
return Schema.fromJSON(sch).wrap()
}
schema.generate = function(sch) {
return schema(sch).generate()
}
{
"author": "Gábor Molnár <gabor.molnar@sch.bme.hu>",
"name": "js-schema",
"description": "A simple and easy to use schema library.",
"description": "A simple and intuitive object validation library",
"keywords": [
"schema",
"JSON Schema",
"random generator",
"object generation",
"testing"
"validation",
"validator"
],
"version": "0.5.0",
"version": "0.6.1",
"homepage": "https://github.com/molnarg/js-schema",

@@ -19,7 +18,7 @@ "repository": {

"dependencies": {
"def.js" : "*",
"randexp" : "*",
"underscore" : "*"
},
"devDependencies": {},
"devDependencies": {
"browserify": "*",
"uglify-js": "*"
},
"engines": {

@@ -26,0 +25,0 @@ "node": "*"

@@ -5,5 +5,7 @@ js-schema

js-schema is a new way of describing object schemas in JavaScript. It has a clean and simple syntax,
and it is capable of serializing to/from the popular JSON Schema format. Typical usecases include
object validation and random object generation.
and it is capable of serializing to/from the popular JSON Schema format. The typical usecase is
decalartive object validation.
**Latest release**: 0.6.1 (2012/08/19)
Features

@@ -15,5 +17,2 @@ ========

```javascript
var schema = require('js-schema');
// or <script src="js-schema.min.js"></script> in the browser
var Duck = schema({ // A duck

@@ -27,12 +26,15 @@ swim : Function, // - can swim

The resulting function (`Duck`) can be used for checking or validating objects:
The resulting function (`Duck`) can be used to check objects against the declared schema:
```javascript
var myDuck = { quack : function() {}, swim : function() {}, age : 2, color : 'yellow' },
myCat = { purr : function() {}, walk : function() {}, age : 3, color : 'black' },
// Some animals
var myDuck = { swim : function() {}, quack : function() {}, age : 2, color : 'yellow' },
myCat = { walk : function() {}, purr : function() {}, age : 3, color : 'black' },
animals = [ myDuck, myCat, {}, /*...*/ ];
// Simple checks
console.log( Duck(myDuck) ); // true
console.log( Duck(myCat) ); // false
// Using the schema function with filter
var ducks = animals.filter( Duck ); // every Duck-like animal

@@ -42,9 +44,2 @@ var walking = animals.filter( schema({ walk : Function }) ); // every animal that can walk

js-schema can generate random objects for a given schema for testing purposes:
```javascript
var duck = schema.generate( Duck );
var testcases = schema.generate( Array.of(5, Duck) );
```
It is also possible to define self-referencing data structures:

@@ -54,14 +49,6 @@

var Tree = schema({ left : [ Number, Tree ], right : [ Number, Tree ] });
var tree = schema.generate( Tree );
```
The schema description is _compiled_ into validation function for achieving maximal performance.
```javascript
console.log( Tree.toString() );
// function self(instance) {
// return instance != null &&
// ((Object(instance["left" ]) instanceof Number) || self(instance["left" ])) &&
// ((Object(instance["right"]) instanceof Number) || self(instance["right"]));
// }
console.log( Tree({ left : 3, right : 3 }) ); // true
console.log( Tree({ left : 3, right : { left: 5, right: 5 } }) ); // true
console.log( Tree({ left : 3, right : { left: 5, right: 's' } }) ); // false
```

@@ -72,2 +59,5 @@

Include js-schema in your project with `var schema = require('js-schema');` in node.js or with
`<script src="js-schema.min.js"></script>` in the browser.
The first parameter passed to the `schema` function describes the schema, and the return value

@@ -132,3 +122,3 @@ is a new function called validator. Then the validator can be used to check any object against

b : Number, // (1) 'class schema' pattern
c : /The meaning of life is \d+/, // (3) regexp pattern
c : /The meaning of life is \d+/, // (3) 'regexp' pattern
d : undefined, // (9) 'anything' pattern

@@ -255,5 +245,2 @@ e : [null, schema.self] // (5) 'or' pattern

Using the random object generation, it should be possible to build a QucikCheck-like testing
framework, which could be used to generate testcases for js-schema (yes, I like resursion).
Contributing

@@ -264,4 +251,4 @@ ============

Installation
============
Installation on node.js
=======================

@@ -272,2 +259,9 @@ Using [npm](http://npmjs.org):

Build
=====
To build the browser verison you will need node.js and two node.js packages: browserify
and uglifyjs installed globally (`npm install -g browserify uglify-js`). `build.sh`
assembles a debug version using browserify and then minifies it using uglify.
License

@@ -274,0 +268,0 @@ =======

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc