Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

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.2.0 to 0.3.0

lib/extensions/Boolean.js

21

index.js
module.exports = require('./lib/schema')
// Core schemas
require('./lib/core/reference')
require('./lib/patterns/reference')
require('./lib/core/nothing')
require('./lib/core/anything')
require('./lib/patterns/nothing')
require('./lib/patterns/anything')
require('./lib/core/object')
require('./lib/patterns/object')
require('./lib/core/or')
require('./lib/core/and')
require('./lib/patterns/or')
require('./lib/core/instanceof')
require('./lib/core/schema')
require('./lib/patterns/instanceof')
require('./lib/patterns/schema')
require('./lib/patterns/regexp')
// Extensions
require('./lib/extensions/Boolean')
require('./lib/extensions/Number')
require('./lib/extensions/Function')
require('./lib/extensions/String')
require('./lib/extensions/Object')
require('./lib/extensions/Array')
require('./lib/extensions/Function')
var schema = require('../schema')
var ArraySchema = module.exports = function(itemSchema) {
this.itemSchema = schema(itemSchema)
var ArraySchema = module.exports = function(itemSchema, max, min) {
if (itemSchema !== undefined) this.itemSchema = schema(itemSchema)
this.min = min
this.max = max

@@ -10,27 +12,63 @@ return new schema(this)

ArraySchema.prototype = {
validate : function(instance) {
for (var i = 0; i < instance.length; i++) {
if (!this.itemSchema.validate(instance[i])) return false
compile : function() {
var compiled = { }
// Instance must be an instance of Array
compiled.fn = 'if (!(instance instanceof Array)) return false;'
// Checking length
if (this.min !== undefined || this.max !== undefined) {
var checks = []
if (this.min === this.max) {
checks.push('instance.length !== ' + this.min)
} else {
if (this.min !== undefined) checks.push('instance.length < ' + this.min)
if (this.max !== undefined) checks.push('instance.length > ' + this.max)
}
compiled.fn += 'if (' + checks.join(' || ') + ') return false;'
}
return true
// Checking conformance to the given item schema
if (this.itemSchema !== undefined) {
compiled.references = [this.itemSchema]
compiled.fn += 'for (var i = 0; i < instance.length; i++) {'
+ ' if (!{0}(instance[i])) return false;'
+ '}'
}
// If every check passes, return true
compiled.fn += 'return true;'
return compiled
},
compile : function() {
var compiled = { }
generate : function() {
var min = this.min === undefined ? 0 : this.min
, max = this.max === undefined ? 10 : this.max
, length = min + Math.floor(Math.random()*(max - min + 1))
, array = []
compiled.references = [this.itemSchema]
for (var i = 0; i < length; i++) array.push(this.itemSchema.generate())
compiled.fn = 'if (!(instance instanceof Array)) return false;'
compiled.fn += 'for (var i = 0; i < instance.length; i++) {'
compiled.fn += ' if (!{0}(instance[i])) return false;'
compiled.fn += '}'
compiled.fn += 'return true;'
return array
},
toJSON : function() {
var schema = { type : 'array' }
return compiled
if (this.min !== undefined) schema.minItems = this.min
if (this.max !== undefined) schema.maxItems = this.max
if (this.itemSchema) schema.items = this.itemSchema.toJSON()
return schema
}
}
Array.of = function(itemSchema) {
return new ArraySchema(itemSchema)
Array.of = function() {
// Possible signatures : (schema)
// (length, schema)
// (minLength, maxLength, schema)
var args = Array.prototype.reverse.call(arguments)
if (args.length === 2) args[2] = args[1]
return new ArraySchema(args[0], args[1], args[2])
}

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

var ReferenceSchema = require('../core/reference')
var ReferenceSchema = require('../patterns/reference')

@@ -3,0 +3,0 @@ Function.Reference = function(f) {

var schema = require('../schema')
var NumberSchema = module.exports = function(minimum, exclusiveMinimum, maximum, exclusiveMaximum) {
var NumberSchema = module.exports = function(minimum, exclusiveMinimum, maximum, exclusiveMaximum, divisibleBy) {
this.minimum = minimum

@@ -8,2 +8,3 @@ this.exclusiveMinimum = exclusiveMinimum

this.exclusiveMaximum = exclusiveMaximum
this.divisibleBy = divisibleBy

@@ -14,34 +15,85 @@ return new schema(this)

NumberSchema.prototype = {
validate : function(instance) {
if (!(Object(instance) instanceof Number)) return false
compile : function() {
var references = [this.minimum, this.maximum, this.divisibleBy]
, checks = ['Object(instance) instanceof Number']
if (this.minimum !== undefined) {
if (instance < this.minimum || (this.exclusiveMinimum && instance == this.minimum)) return false
checks.push('instance ' + (this.exclusiveMinimum ? '>' : '>=') + ' {0}')
}
if (this.maximum !== undefined) {
if (instance > this.maximum || (this.exclusiveMaximum && instance == this.maximum)) return false
checks.push('instance ' + (this.exclusiveMaximum ? '<' : '<=') + ' {1}')
}
return true
if (this.divisibleBy !== undefined) {
checks.push('instance % {2} === 0')
}
return { references : references, expression : checks.join(' && ') }
},
min : function(minimum) {
return new NumberSchema(minimum, false, this.maximum, this.exclusiveMaximum)
return new NumberSchema(minimum, false, this.maximum, this.exclusiveMaximum, this.divisibleBy)
},
above : function(minimum) {
return new NumberSchema(minimum, true, this.maximum, this.exclusiveMaximum)
return new NumberSchema(minimum, true, this.maximum, this.exclusiveMaximum, this.divisibleBy)
},
max : function(maximum) {
return new NumberSchema(this.minimum, this.exclusiveMinimum, maximum, false)
return new NumberSchema(this.minimum, this.exclusiveMinimum, maximum, false, this.divisibleBy)
},
below : function(maximum) {
return new NumberSchema(this.minimum, this.exclusiveMinimum, maximum, true)
return new NumberSchema(this.minimum, this.exclusiveMinimum, maximum, true, this.divisibleBy)
},
step : function(divisibleBy) {
return new NumberSchema(this.minimum, this.exclusiveMinimum, this.maximum, this.exclusiveMaximum, divisibleBy)
},
generate : function() {
var length, random
, min = this.minimum
, max = this.maximum
, step = this.divisibleBy
// If there's no decalred maximum or minimum then assigning a reasonable value
if (min == null || min === -Infinity) {
if (max == null || max === Infinity) {
min = 0
max = 10
} else {
min = max > 0 ? 0 : max*2
}
} else if (max == null || max === Infinity) {
max = this.min < 0 ? 0 : this.min*2
}
// Choosing random number from a continuous set
if (step == null || 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
},
toJSON : function() {
var schema = { type : 'number', required : true }
var schema = { type : 'number' }

@@ -58,2 +110,4 @@ if (this.minimum !== undefined) {

if (this.divisibleBy !== undefined) schema.divisibleBy = this.divisibleBy
return schema

@@ -63,6 +117,10 @@ }

Number.schema = new NumberSchema()
Number.min = Number.schema.min
Number.above = Number.schema.above
Number.max = Number.schema.max
Number.below = Number.schema.below
Number.schema = new NumberSchema()
Number.min = Number.schema.min
Number.above = Number.schema.above
Number.max = Number.schema.max
Number.below = Number.schema.below
Number.step = Number.schema.step
Number.generate = Number.schema.generate
Number.Integer = Number.step(1)

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

var ReferenceSchema = require('../core/reference')
var ReferenceSchema = require('../patterns/reference')

@@ -3,0 +3,0 @@ Object.Reference = function(o) {

@@ -64,2 +64,3 @@ var native_functions = [Boolean, Number, String, Object, Array, Function, Date]

assembly.subroutines = assembly.subroutines || []
assembly.references = assembly.references || []

@@ -66,0 +67,0 @@ var name

@@ -34,4 +34,4 @@ var def = require('def.js')

schema.random = function(sch) {
return schema(sch).random()
schema.generate = function(sch) {
return schema(sch).generate()
}

@@ -10,3 +10,3 @@ {

],
"version": "0.2.0",
"version": "0.3.0",
"homepage": "https://github.com/molnarg/js-schema",

@@ -18,3 +18,4 @@ "repository": {

"dependencies": {
"def.js" : "*"
"def.js" : "0.1.4",
"randexp" : "*"
},

@@ -21,0 +22,0 @@ "devDependencies": {},

js-schema
=========
js-schema is essentially a new way to describe JSON schemas using a
much cleaner and simpler syntax. Think of it like regexp for objects.
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.

@@ -10,3 +10,3 @@ A simple example

Object validation and filtering:
Defining a schema:

@@ -16,19 +16,33 @@ ```javascript

var Duck = schema({
quack : Function,
feed : Function,
age : Number.min(0).max(5)
color : ['yellow', 'brown']
var Duck = schema({ // A duck
quack : Function, // - can quack
feed : Function, // - can be fed
age : Number.min(0).max(5), // - is 0 to 5 years old
color : ['yellow', 'brown'] // - has either yellow or brown color
});
```
The resulting function can be used for checking or validating objects:
```javascript
var myDuck = { quack : function() {}, feed : function() {}, age : 2, color : 'yellow' };
var myCat = { purr : function() {}, feed : function() {}, age : 3, color : 'black' };
var animals = [myDuck, myCat, /*...*/ ];
var animals = [myDuck, myCat, {}, /*...*/ ];
console.log( Duck(myDuck) ); // true
console.log( Duck(myCat) ); // false
console.log( animals.filter(Duck) ); // every Duck-like object
console.log( animals.filter(Duck) ); // every Duck-like object
console.log( animals.filter(schema({ feed : Function })) ); // every animal that can be fed
```
It is also possible to generate random objects for testing purposes:
```javascript
console.log( Duck.generate() );
var testcases = Array.of(10, Duck).generate();
test(testcases);
```
Usage

@@ -66,6 +80,6 @@ =====

2. `Class` (where `Class` is a function) matches `x` if `x instanceof Class`
3. `[[pattern1, pattern2, ...]]` matches `x` if _all_ of the given patterns match `x`
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`, `pattern2`
matches `x.b`, etc.
5. `{ '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`

@@ -85,39 +99,52 @@ 7. `null` matches `x` if `x` _is_ `null` or `undefined`

```javascript
validator = schema({ // (5) 'object' pattern
a : [[ String, {length : 5} ]], // (3) 'and' pattern
// (2) 'instanceof' pattern
// (5) 'object' pattern
// (8) 'primitive' pattern
b : [Color, 'red', 'blue'], // (4) 'or' pattern
// (2) 'instanceof' pattern
// (8) 'primitive' pattern
c : undefined, // (6) 'anything' pattern
d : null // (7) 'nothing' pattern
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
});
console.log( validate(x) );
```
The `schema` function compiles the pattern, and returns the value of the following expression
(the validator function):
`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
### The object pattern ###
The object pattern is more complex than the others. Using the object pattern it is possible to
define optional properties, regexp properties, etc. This extra information can be encoded in
the property names.
The property names in an object pattern are always regular expressions, and the given schema
applies to instance properties whose name match this regexp. The number of expected matches can
also be specified with `?`, `+` or `*` as the first character of the property name. `?` means
0 or 1, `*` means 0 or more, and `+` means 1 or more. A single `*` as a property name
matches any instance property that is not matched by other regexps.
An example of using these:
```javascript
(functon(r0){
return function(instance){
return instance != null && (
(Object(instance["a"]) instanceof String) &&
(instance["a"] != null && (instance["a"]["length"] === 5))
) && (
(Object(instance["b"]) instanceof r0) ||
(instance["b"] === "red") || (instance["b"] === "blue")
) && (
instance["c"] != null
) && (
instance["d"] == null
);
};
}(Color));
var x = { /* ... */ };
validate = schema({
'name' : String, // x.name must be string
'colou?r' : String // x must have a string type property called either
// 'color' or 'colour' but not both
'?location' : String, // if x has a property called 'location' then it must be string
'*identifier-.*' : Number, // if the name of a property of x matches /identifier-.*/ then
// it must be a number
'+serialnumber-.*' : Number, // if the name of a property of x matches /serialnumber-.*/ then
// it must be a number and there should be at least one such property
'*' : Boolean // any other property that doesn't match any of these rules
// must be Boolean
});
assert( validate(x) === true );
```
As you can see, the compiled function is nearly optimal, and looks like what anyone would
write when following the rules described above.
Extensions

@@ -136,9 +163,12 @@ ==========

`Array.of(pattern)` matches `x` if `x instanceof Array` and `pattern` matches every element of `x`.
The `Array.of` method has three signatures:
- `Array.of(pattern)` matches `x` if `x instanceof Array` and `pattern` matches every element of `x`.
- `Array.of(length, pattern)` additionally checks the length of the instance and returns true only if it equals to `length`.
- `Array.of(minLength, maxLength, pattern)` is similar, but checks if the length is in the given interval.
### Numbers ###
There are four functions that can be used for describing number ranges: `min`, `max`, `below`
and `above`. All of these are chainable, so for example `Number.min(a).below(b)` matches `x` if
`a <= x && x < b`.
There are five functions that can be used for describing number ranges: `min`, `max`, `below`,
`above` and `step`. All of these are chainable, so for example `Number.min(a).below(b)` matches `x`
if `a <= x && x < b`. The `Number.step(a)` matches `x` if `x` is a divisble by `a`.

@@ -149,4 +179,4 @@ Future plans

Better JSON Schema support. js-schema should be able to parse any valid JSON schema and generate
JSON Schema for most of the patterns (there are cases when 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, e.g. patterns that have
external references like the instanceof pattern).

@@ -164,13 +194,2 @@ Defining and validating resursive data structures:

Generating random objects based on schema description:
```javascript
// generating random trees
console.log( schema.random(Tree) ); // {left : 0.123, right : {left : 0.2, right : 0.9}}
// generating an array of random trees for testing
var testcases = schema.random(Array.of(Tree));
test(testcases);
```
Using the random object generation, it should be possible to build a QucikCheck-like testing

@@ -177,0 +196,0 @@ framework, which could be used to generate testcases for js-schema (yes, I like resursion).

Sorry, the diff of this file is not supported yet

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