js-schema
Advanced tools
Comparing version 0.3.0 to 0.4.0
@@ -5,14 +5,9 @@ module.exports = require('./lib/schema') | ||
require('./lib/patterns/reference') | ||
require('./lib/patterns/nothing') | ||
require('./lib/patterns/anything') | ||
require('./lib/patterns/object') | ||
require('./lib/patterns/or') | ||
require('./lib/patterns/instanceof') | ||
require('./lib/patterns/schema') | ||
require('./lib/patterns/equality') | ||
require('./lib/patterns/regexp') | ||
require('./lib/patterns/class') | ||
@@ -19,0 +14,0 @@ // Extensions |
var schema = require('../schema') | ||
, EqualitySchema = require('../patterns/equality') | ||
var ArraySchema = module.exports = function(itemSchema, max, min) { | ||
if (itemSchema !== undefined) this.itemSchema = schema(itemSchema) | ||
this.itemSchema = itemSchema | ||
this.min = min | ||
@@ -66,2 +67,11 @@ this.max = max | ||
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) | ||
}) | ||
Array.of = function() { | ||
@@ -73,3 +83,8 @@ // Possible signatures : (schema) | ||
if (args.length === 2) args[2] = args[1] | ||
return new ArraySchema(args[0], args[1], args[2]) | ||
return new ArraySchema(schema(args[0]), args[1], args[2]) | ||
} | ||
Array.like = function(other) { | ||
return new EqualitySchema(other) | ||
} | ||
@@ -21,3 +21,11 @@ var schema = require('../schema') | ||
Boolean.schema = new BooleanSchema() | ||
var booleanSchema = new BooleanSchema() | ||
schema.fromJSON.def(function(sch) { | ||
if (!sch || sch.type !== 'boolean') return | ||
return booleanSchema | ||
}) | ||
Boolean.schema = booleanSchema | ||
Boolean.generate = Boolean.schema.generate |
var ReferenceSchema = require('../patterns/reference') | ||
, ClassSchema = require('../patterns/class') | ||
Function.Reference = function(f) { | ||
// 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) | ||
} |
@@ -18,11 +18,11 @@ var schema = require('../schema') | ||
if (this.minimum !== undefined) { | ||
if (this.minimum !== undefined && this.minimum !== -Infinity) { | ||
checks.push('instance ' + (this.exclusiveMinimum ? '>' : '>=') + ' {0}') | ||
} | ||
if (this.maximum !== undefined) { | ||
if (this.maximum !== undefined && this.maximum !== Infinity) { | ||
checks.push('instance ' + (this.exclusiveMaximum ? '<' : '<=') + ' {1}') | ||
} | ||
if (this.divisibleBy !== undefined) { | ||
if (this.divisibleBy !== undefined && this.divisibleBy !== 0) { | ||
checks.push('instance % {2} === 0') | ||
@@ -97,7 +97,8 @@ } | ||
toJSON : function() { | ||
var schema = { type : 'number' } | ||
var integer = this.divisibleBy !== 0 && this.divisibleBy === Math.floor(this.divisibleBy) | ||
var schema = { type : integer ? 'integer' : 'number' } | ||
if (this.minimum !== undefined) { | ||
schema.minimum = this.minimum | ||
schema.exclusiveMinimum = (this.exclusiveMinimum === true) | ||
if (this.exclusiveMinimum === true) schema.exclusiveMinimum = true | ||
} | ||
@@ -107,6 +108,7 @@ | ||
schema.maximum = this.maximum | ||
schema.exclusiveMaximum = (this.exclusiveMaximum === true) | ||
if (this.exclusiveMaximum === true) schema.exclusiveMaximum = true | ||
} | ||
if (this.divisibleBy !== undefined) schema.divisibleBy = this.divisibleBy | ||
var step = this.divisibleBy | ||
if (step !== undefined && step !== 0 && step !== 1) schema.divisibleBy = step | ||
@@ -117,2 +119,11 @@ return schema | ||
schema.fromJSON.def(function(sch) { | ||
if (!sch || (sch.type !== 'number' && sch.type !== 'integer')) return | ||
return new NumberSchema( sch.minimum, sch.exclusiveMinimum | ||
, sch.maximum, sch.exclusiveMaximum | ||
, sch.divisibleBy || (sch.type === 'integer' ? 1 : 0) | ||
) | ||
}) | ||
Number.schema = new NumberSchema() | ||
@@ -119,0 +130,0 @@ Number.min = Number.schema.min |
var ReferenceSchema = require('../patterns/reference') | ||
, EqualitySchema = require('../patterns/equality') | ||
Object.Reference = function(o) { | ||
Object.like = function(other) { | ||
return new EqualitySchema(other) | ||
} | ||
Object.reference = function(o) { | ||
return new ReferenceSchema(o) | ||
} |
@@ -1,22 +0,17 @@ | ||
var schema = require('../schema') | ||
var RegexpSchema = require('../patterns/regexp') | ||
var StringSchema = function() { | ||
return new schema(this) | ||
} | ||
StringSchema.prototype = { | ||
compile : function() { | ||
return { expression : 'Object(instance) instanceof String' } | ||
}, | ||
String.of = function() { | ||
// Possible signatures : (charset) | ||
// (length, charset) | ||
// (minLength, maxLength, charset) | ||
var args = Array.prototype.reverse.call(arguments) | ||
, charset = args[0] ? ('[' + args[0] + ']') : '[a-zA-Z0-9]' | ||
, max = args[1] | ||
, min = (args.length > 2) ? args[2] : args[1] | ||
, regexp = '^' + charset + '{' + (min || 0) + ',' + (max || '') + '}$' | ||
generate : function() { | ||
return schema(/[a-zA-Z0-9]+/).generate() | ||
}, | ||
toJSON : function() { | ||
return { type : 'string' } | ||
} | ||
return new RegexpSchema(RegExp(regexp)) | ||
} | ||
String.schema = new StringSchema() | ||
String.schema = new RegexpSchema() | ||
String.generate = String.schema.generate |
@@ -34,2 +34,6 @@ var native_functions = [Boolean, Number, String, Object, Array, Function, Date] | ||
resolved = reference.name + '$1' | ||
} else if (reference instanceof RegExp) { | ||
// regexps can be converted to strings easily | ||
resolved = reference.toString() + '$1' | ||
@@ -36,0 +40,0 @@ } else { |
var schema = require('../schema') | ||
, RandExp = require('randexp') | ||
, utils = require('../utils') | ||
var ObjectSchema = module.exports = function(regexp, other) { | ||
var ObjectSchema = module.exports = function(properties, other) { | ||
var self = this | ||
this.other = other | ||
this.regexp = regexp || [] | ||
for (var i in this.regexp) this.regexp[i].key = RegExp('^' + this.regexp[i].key + '$') | ||
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) | ||
@@ -13,53 +26,83 @@ } | ||
ObjectSchema.prototype = { | ||
validate : function(instance) { | ||
// TODO: treat non-regexps differently | ||
// regexpElementTests = '[](){}^$?*+'.split('').map(function(element) { | ||
// return RegExp('(^|[^\\\\])\\' + element) | ||
// }) | ||
var i, matches = this.regexp.map(function(){ return 0 }), match = false | ||
for (var property in instance) { | ||
match = false | ||
for (i in this.regexp) { | ||
if (this.regexp[i].key.test(property)) { | ||
if (!this.regexp[i].value(instance[property])) return false | ||
matches[i] += 1 | ||
match = true | ||
} | ||
compile : function() { | ||
var checks = ['instance != null'] | ||
, references = [] | ||
, ref = utils.referenceHandler(references) | ||
// 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) | ||
} | ||
if (!match && this.other && !this.other(instance[property])) return false | ||
checks.push(check) | ||
} | ||
for (i in this.regexp) { | ||
if (!(this.regexp[i].min <= matches[i] && matches[i] <= this.regexp[i].max)) return false | ||
if (!this.regexpProps.length && !this.other) { | ||
return { references : references, expression : checks.join(' && ') } | ||
} | ||
// Regexp and other properties | ||
var stringPropNames = Object.keys(this.stringProps) | ||
var fn = 'if (!( {checks} )) return false;'.replace('{checks}', checks.join(' && ')) | ||
if (this.other) fn += 'var checked;' | ||
// Iterating over the keys in the instance | ||
fn += 'for (var key in instance) {' | ||
return true | ||
// Checking the key against every key regexps | ||
if (this.other) fn += 'checked = false;' | ||
for (var i = 0; i < this.regexpProps.length; i++) { | ||
if (this.other) { | ||
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) { | ||
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 | ||
// If all checks passed, the instance conforms to the schema | ||
fn += 'return true;' | ||
return { references : references, fn : fn } | ||
}, | ||
generate : function() { | ||
var i, key, object = {} | ||
var object = {} | ||
for (i in this.regexp) { | ||
var n = 0 | ||
for (key in object) { | ||
if (this.regexp[i].key.test(key)) n += 1 | ||
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 | ||
while (n < this.regexp[i].min) { | ||
key = new RandExp(this.regexp[i].key).gen() | ||
if (!(key in object)) { | ||
object[key] = this.regexp[i].value.generate() | ||
n += 1 | ||
} | ||
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 | ||
} | ||
while (n < this.regexp[i].max && Math.random() < 0.5) { | ||
key = new RandExp(this.regexp[i].key).gen() | ||
if (!(key in object)) { | ||
object[key] = this.regexp[i].value.generate() | ||
n += 1 | ||
} | ||
} | ||
} | ||
@@ -75,9 +118,76 @@ | ||
return object | ||
}, | ||
toJSON : function() { | ||
var i, property, regexp, json = { type : 'object' } | ||
for (i in this.stringProps) { | ||
property = this.stringProps[i] | ||
json.properties = json.properties || {} | ||
json.properties[property.key] = property.value.toJSON() | ||
if (property.min === 1) json.properties[property.key].required = true | ||
} | ||
for (i = 0; i < this.regexpProps.length; i++) { | ||
property = this.regexpProps[i] | ||
json.patternProperties = json.patternProperties || {} | ||
regexp = property.key.toString() | ||
regexp = regexp.substr(2, regexp.length - 4) | ||
json.patternProperties[regexp] = property.value.toJSON() | ||
} | ||
if (this.other && this.other !== schema(undefined)) { | ||
json.additionalProperties = (this.other === schema(null)) ? false : this.other.toJSON() | ||
} | ||
return json | ||
} | ||
} | ||
// Testing if a given string is a real regexp or just a single string escaped | ||
// If it is just a string escaped, return the string. Otherwise return the regexp | ||
var regexpString = global.regexpString = (function() { | ||
// Special characters that should be escaped when describing a regular string in regexp | ||
var shouldBeEscaped = '[](){}^$?*+.'.split('').map(function(element) { | ||
return RegExp('(\\\\)*\\' + element, 'g') | ||
}) | ||
// Special characters that shouldn't be escaped when describing a regular string in regexp | ||
var shouldntBeEscaped = 'bBwWdDsS'.split('').map(function(element) { | ||
return RegExp('(\\\\)*' + element, 'g') | ||
}) | ||
return function(string) { | ||
var i, j, match | ||
for (i = 0; i < shouldBeEscaped.length; i++) { | ||
match = string.match(shouldBeEscaped[i]) | ||
if (!match) continue | ||
for (j = 0; j < match.length; j++) { | ||
// If it is not escaped, it must be a regexp (e.g. [, \\[, \\\\[, etc.) | ||
if (match[j].length % 2 === 1) return RegExp('^' + string + '$') | ||
} | ||
} | ||
for (i = 0; i < shouldntBeEscaped.length; i++) { | ||
match = string.match(shouldntBeEscaped[i]) | ||
if (!match) continue | ||
for (j = 0; j < match.length; j++) { | ||
// If it is escaped, it must be a regexp (e.g. \b, \\\b, \\\\\b, etc.) | ||
if (match[j].length % 2 === 0) return RegExp('^' + string + '$') | ||
} | ||
} | ||
// It is not a real regexp. Removing the escaping. | ||
for (i = 0; i < shouldBeEscaped.length; i++) { | ||
string = string.replace(shouldBeEscaped[i], function(match) { | ||
return match.substr(1) | ||
}) | ||
} | ||
return string | ||
} | ||
})() | ||
schema.fromJS.def(function(object) { | ||
if (!(object instanceof Object)) return | ||
var first, min, max, value, properties = [], other | ||
@@ -87,2 +197,7 @@ for (var key in object) { | ||
if (key === '*') { | ||
other = value | ||
continue | ||
} | ||
first = key[0] | ||
@@ -93,7 +208,5 @@ min = (first === '*' || first === '?') ? 0 : 1 | ||
if (key === '') { | ||
other = value | ||
} else { | ||
properties.push({ min : min, max : max, key : key, value : value }) | ||
} | ||
key = regexpString(key) | ||
properties.push({ min : min, max : max, key : key, value : value }) | ||
} | ||
@@ -103,1 +216,28 @@ | ||
}) | ||
schema.fromJSON.def(function(sch) { | ||
if (!sch || sch.type !== 'object') return | ||
var key, properties = [] | ||
for (key in sch.properties) { | ||
properties.push({ min : sch.properties[key].required ? 1 : 0 | ||
, max : 1 | ||
, key : key | ||
, value : schema.fromJSON(sch.properties[key]) | ||
}) | ||
} | ||
for (key in sch.patternProperties) { | ||
properties.push({ min : 0 | ||
, max : Infinity | ||
, key : RegExp('^' + key + '$') | ||
, value : schema.fromJSON(sch.properties[key]) | ||
}) | ||
} | ||
var other | ||
if (sch.additionalProperties !== undefined) { | ||
other = sch.additionalProperties === false ? schema(null) : schema.fromJSON(sch.additionalProperties) | ||
} | ||
return new ObjectSchema(properties, other) | ||
}) |
var schema = require('../schema') | ||
, EqualitySchema = require('../patterns/equality') | ||
var OrSchema = module.exports = function(schemas) { | ||
this.schemas = schemas.map(schema.fromJS) | ||
this.schemas = schemas | ||
@@ -21,2 +22,20 @@ return new schema(this) | ||
return this.schemas[Math.floor(Math.random()*this.schemas.length)].generate() | ||
}, | ||
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 | ||
} | ||
} | ||
if (onlyEquality) return { 'enum' : jsons.map(function(json) { return json['enum'][0] }) } | ||
return { 'type' : jsons.map(function(json) { | ||
var simpleType = typeof json.type === 'string' && Object.keys(json).length === 1 | ||
return simpleType ? json.type : json | ||
})} | ||
} | ||
@@ -27,3 +46,19 @@ } | ||
schema.fromJS.def(function(schemas) { | ||
if (schemas instanceof Array) return new OrSchema(schemas) | ||
if (schemas instanceof Array) return new OrSchema(schemas.map(schema.fromJS)) | ||
}) | ||
schema.fromJSON.def(function(sch) { | ||
if (!sch) return | ||
if (sch['enum'] instanceof Array) { | ||
return new OrSchema(sch['enum'].map(function(object) { | ||
return new EqualitySchema(object) | ||
})) | ||
} | ||
if (sch['type'] instanceof Array) { | ||
return new OrSchema(sch['type'].map(function(type) { | ||
return schema.fromJSON(typeof type === 'string' ? { type : type } : type) | ||
})) | ||
} | ||
}) |
var schema = require('../schema') | ||
, RandExp = require('randexp') | ||
var defaultRandExp = new RandExp(/[a-zA-Z0-9]*/) | ||
var RegexpSchema = module.exports = function(regexp) { | ||
this.regexp = regexp | ||
this.randexp = this.regexp ? new RandExp(this.regexp) : defaultRandExp | ||
@@ -12,10 +15,36 @@ return new schema(this) | ||
compile : function() { | ||
return { references : [this.regexp], expression : '{0}.test(instance)' } | ||
return { references : [this.regexp] | ||
, expression : 'Object(instance) instanceof String' | ||
+ (this.regexp ? ' && {0}.test(instance)' : '') | ||
} | ||
}, | ||
generate : function() { | ||
return (new RandExp(this.regexp)).gen() | ||
return this.randexp.gen() | ||
}, | ||
toJSON : function() { | ||
var sch = { 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) | ||
} | ||
return 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 || '') + '}$')) | ||
} else { | ||
return new RegexpSchema() | ||
} | ||
}) | ||
@@ -22,0 +51,0 @@ schema.fromJS.def(function(regexp) { |
{ | ||
"author": "Gábor Molnár <gabor.molnar@sch.bme.hu>", | ||
"name": "js-schema", | ||
"description": "A simple and easy to use JSON Schema library.", | ||
"description": "A simple and easy to use schema library.", | ||
"keywords": [ | ||
"schema", | ||
"json", | ||
"random generator" | ||
"JSON Schema", | ||
"random generator", | ||
"object generation", | ||
"testing" | ||
], | ||
"version": "0.3.0", | ||
"version": "0.4.0", | ||
"homepage": "https://github.com/molnarg/js-schema", | ||
@@ -17,3 +19,3 @@ "repository": { | ||
"dependencies": { | ||
"def.js" : "0.1.4", | ||
"def.js" : "0.1.5", | ||
"randexp" : "*" | ||
@@ -20,0 +22,0 @@ }, |
106
README.md
js-schema | ||
========= | ||
js-schema is a new way of describing object schemas in JavaScript. It has a clean and simple syntax. | ||
Usecases include object validation and random object generation. | ||
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. | ||
@@ -42,4 +43,4 @@ A simple example | ||
var testcases = Array.of(10, Duck).generate(); | ||
test(testcases); | ||
var testcases = Array.of(5, Duck).generate(); | ||
console.log(testcases); | ||
``` | ||
@@ -67,3 +68,4 @@ | ||
For serialization to JSON Schema use the `toJSON()` method of any schema. For deserialization | ||
use `schema.fromJSON()`. _Warning_: JSON support is still incomplete. | ||
use `schema.fromJSON(json)`. JSON Schema support is still incomplete, but it can reliably | ||
deserialize JSON Schemas generated by js-schema itself. | ||
@@ -75,14 +77,15 @@ Patterns | ||
There are 8 basic rules used by js-schema: | ||
There are 9 basic rules used for describing schemas: | ||
1. `Class` (where `Class` is a function, and has a function type property called | ||
`schema`) matches `x` if `Class.schema(x)` is true | ||
2. `Class` (where `Class` is a function) matches `x` if `x instanceof Class` | ||
3. `/regexp/` matches `x` if `/regexp/.test(x) === true` | ||
4. `[pattern1, pattern2, ...]` matches `x` if _any_ of the given patterns match `x` | ||
5. `{ 'a' : pattern1, 'b' : pattern2, ... }` matches `x` if `pattern1` matches `x.a`, | ||
1. `Class` (where `Class` is a function, and has a function type property called `schema`) | ||
matches `x` if `Class.schema(x) === true`. | ||
2. `Class` (where `Class` is a function) matches `x` if `x instanceof Class`. | ||
3. `/regexp/` matches `x` if `/regexp/.test(x) === true`. | ||
4. `[object]` matches `x` if `x` is deep equal to `object` | ||
5. `[pattern1, pattern2, ...]` matches `x` if _any_ of the given patterns match `x`. | ||
6. `{ 'a' : pattern1, 'b' : pattern2, ... }` matches `x` if `pattern1` matches `x.a`, | ||
`pattern2` matches `x.b`, etc. For details see the object pattern subsection. | ||
6. `undefined` matches `x` if `x` _is not_ `null` or `undefined` | ||
7. `null` matches `x` if `x` _is_ `null` or `undefined` | ||
8. `primitive` (where `primitive` is boolean, number, or string) matches `x` if `primitive === x` | ||
7. `undefined` matches `x` if `x` _is not_ `null` or `undefined`. | ||
8. `null` matches `x` if `x` _is_ `null` or `undefined`. | ||
9. `primitive` (where `primitive` is boolean, number, or string) matches `x` if `primitive === x`. | ||
@@ -95,13 +98,17 @@ The order is important. When calling `schema(pattern)`, the rules are examined one by one, | ||
The following example contains patterns for all of the rules, except the first. The comments | ||
The following example contains patterns for all of the rules. The comments | ||
denote the number of the rules used and the nesting level of the subpatterns (indentation). | ||
```javascript | ||
validate = schema({ // (5) 'object' pattern | ||
a : [Color, 'red', 'blue'], // (4) 'or' pattern | ||
// (2) 'instanceof' pattern | ||
// (8) 'primitive' pattern | ||
b : /The meaning of life is \d+/, // (3) regexp pattern | ||
c : undefined, // (6) 'anything' pattern | ||
d : null // (7) 'nothing' pattern | ||
var Color = function() {}, x = { /* ... */ }; | ||
var validate = schema({ // (6) 'object' pattern | ||
a : [ Color, 'red', 'blue', [[0,0,0]] ], // (5) 'or' pattern | ||
// (2) 'instanceof' pattern | ||
// (9) 'primitive' pattern | ||
// (4) 'deep equality' pattern | ||
b : Number, // (1) 'class schema' pattern | ||
c : /The meaning of life is \d+/, // (3) regexp pattern | ||
d : undefined, // (7) 'anything' pattern | ||
e : null // (8) 'nothing' pattern | ||
}); | ||
@@ -113,6 +120,8 @@ | ||
`validate(x)` returns true if all of these are true: | ||
* `x.a` is either 'red' or 'blue' or an instance of the Color class | ||
* `x.b` is a string that matches the /The meaning of life is \d+/ regexp | ||
* `x` does have a property called `c` | ||
* `x` doesn't have a property called `d`, or it does but it is null or undefined | ||
* `x.a` is either 'red', 'blue', an instance of the Color class, | ||
or an array that is exactly like `[0,0,0]` | ||
* `x.b` conforms to Number.schema (it return true if `x.b instanceof Number`) | ||
* `x.c` is a string that matches the /The meaning of life is \d+/ regexp | ||
* `x` does have a property called `d` | ||
* `x` doesn't have a property called `e`, or it does but it is `null` or `undefined` | ||
@@ -135,3 +144,3 @@ ### The object pattern ### | ||
validate = schema({ | ||
var validate = schema({ | ||
'name' : String, // x.name must be string | ||
@@ -157,10 +166,14 @@ 'colou?r' : String // x must have a string type property called either | ||
`Object.Reference(object)` matches `x` if `x === object`. | ||
`Object.reference(object)` matches `x` if `x === object`. | ||
`Object.like(object)` matches `x` if `x` deep equals `object`. | ||
### Functions ### | ||
`Function.Reference(func)` matches `x` if `x === func`. | ||
`Function.reference(func)` matches `x` if `x === func`. | ||
### Arrays ### | ||
The `Array.like(array)` matches `x` if `x instanceof Array` and it deep equals `array`. | ||
The `Array.of` method has three signatures: | ||
@@ -177,2 +190,15 @@ - `Array.of(pattern)` matches `x` if `x instanceof Array` and `pattern` matches every element of `x`. | ||
### Strings ### | ||
The `String.of` method has three signatures: | ||
- `String.of(charset)` matches `x` if it is a string and contains characters that are included in `charset` | ||
- `String.of(length, charset)` additionally checks the length of the instance and returns true only if it equals to `length`. | ||
- `String.of(minLength, maxLength, charset)` is similar, but checks if the length is in the given interval. | ||
`charset` must be given in a format that can be directly inserted in a regular expression when | ||
wrapped by `[]`. For example, `'abc'` means a character set containing the first 3 lowercase letters | ||
of the english alphabet, while `'a-zA-C'` means a character set of all english lowercase letters, | ||
and the first 3 uppercase letters. If `charset` is `undefined` then the `a-zA-Z0-9` character set | ||
is used. | ||
Future plans | ||
@@ -182,10 +208,17 @@ ============ | ||
Better JSON Schema support. js-schema should be able to parse any valid JSON schema and generate | ||
JSON Schema for most of the patterns (this is not possible in general, e.g. patterns that have | ||
external references like the instanceof pattern). | ||
JSON Schema for most of the patterns (this is not possible in general, because of patterns that hold | ||
external references like the 'instanceof' 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). | ||
Defining and validating resursive data structures: | ||
```javascript | ||
// defining the data structure | ||
// Defining the data structure: | ||
var Tree = schema({ left : [Tree, Number], right : [Tree, Number] }); | ||
// The schema function gets this as argument: | ||
// { left : [undefined, Number], right : [undefined, Number] } | ||
// Since providing 'undefined' as part of an 'or' patterns doesn't make sense, | ||
// it must be a self-reference. Self-reference usually occur as part of 'or' patterns. | ||
@@ -197,10 +230,6 @@ // validation | ||
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 | ||
============ | ||
Feel free to open an issue if you would like to help imporving js-schema, find a bug, or even | ||
if there's a feature that would be useful for you but don't have the time to implement it yourself. | ||
Feel free to open an issue if you would like to help imporving js-schema or find a bug. | ||
@@ -220,2 +249,1 @@ Installation | ||
Copyright (C) 2012 Gábor Molnár <gabor.molnar@sch.bme.hu> | ||
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
39924
22
751
239
0
+ Addeddef.js@0.1.5(transitive)
- Removeddef.js@0.1.4(transitive)
Updateddef.js@0.1.5