New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

alamid-schema

Package Overview
Dependencies
Maintainers
1
Versions
15
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

alamid-schema - npm Package Compare versions

Comparing version 0.4.0 to 1.0.0

.editorconfig

34

lib/determineType.js

@@ -6,22 +6,21 @@ "use strict";

var supportedTypes = [
"String",
"Number",
"Boolean",
"Date",
"Array",
"Object"
],
fnName = /function ([a-z]+?)\(/i;
"String",
"Number",
"Boolean",
"Date",
"Array",
"Object"
];
var fnName = /function ([a-z]+?)\(/i;
/**
* determine the type of an object
* inspired by mongoose
* Determine the type of an object. Inspired by mongoose.
*
* @param obj
* @return {*}
* @param {*} obj
* @returns {string}
*/
function determineType(obj) {
var type,
typeValue,
name;
var type;
var typeValue;
var name;

@@ -38,3 +37,2 @@ if (value(obj).typeOf(Object)) {

name = type.charAt(0).toUpperCase() + type.substring(1);
return supportedTypes.indexOf(name) === -1 ? "String" : name;

@@ -54,3 +52,3 @@ } else if (typeValue.typeOf(Function)) {

if (supportedTypes.indexOf(name) === -1) {
throw new TypeError("(alamid-schema) Type '" + name + "' is not supported");
throw new TypeError("Type '" + name + "' is not supported");
}

@@ -61,2 +59,2 @@

module.exports = determineType;
module.exports = determineType;

@@ -6,5 +6,5 @@ "use strict";

function merge(source, target) {
var key,
sourceValue,
targetValue;
var key;
var sourceValue;
var targetValue;

@@ -33,2 +33,2 @@ for (key in source) {

module.exports = merge;
module.exports = merge;
"use strict";
var determineType = require("./determineType.js"),
value = require("value");
var determineType = require("./determineType.js");
var value = require("value");
/**
* Normalizes the schema definition and extracts keys and types
* Normalizes the schema definition and extracts fields and types.
*
* @param {Object} definition
* @return {Object}
* @returns {Object}
*/
function processDefinition(definition) {
var key,
fieldDefinition,
type,
keys = [],
types = {};
var fields = [];
var types = {};
var key;
var fieldDefinition;
var type;
for (key in definition) {
if (definition.hasOwnProperty(key)) {
keys.push(key);
fields.push(key);

@@ -36,3 +36,3 @@ fieldDefinition = definition[key];

if (value(fieldDefinition).getConstructor() === Object) {
definition[key].writable = fieldDefinition.hasOwnProperty("writable")? fieldDefinition.writable : true;
definition[key].writable = fieldDefinition.hasOwnProperty("writable") ? fieldDefinition.writable : true;
} else {

@@ -43,3 +43,3 @@ definition[key].writable = true;

if (value(fieldDefinition).getConstructor() === Object) {
definition[key].readable = fieldDefinition.hasOwnProperty("readable")? fieldDefinition.readable : true;
definition[key].readable = fieldDefinition.hasOwnProperty("readable") ? fieldDefinition.readable : true;
} else {

@@ -54,3 +54,3 @@ definition[key].readable = true;

return {
keys: keys,
fields: fields,
types: types

@@ -60,2 +60,2 @@ };

module.exports = processDefinition;
module.exports = processDefinition;
"use strict";
var processDefinition = require("./processDefinition.js"),
merge = require("./merge.js");
var processDefinition = require("./processDefinition.js");
var merge = require("./merge.js");

@@ -13,7 +13,6 @@ var slice = Array.prototype.slice;

/**
* Creates a new Schema
* Creates a new Schema.
*
* @param {String=Anonymous} name
* @param {String|Object} definition
* @constructor
* @param {string} [name=Anonymous]
* @param {string|Object} definition
*/

@@ -33,3 +32,3 @@ Schema.prototype.constructor = function (name, definition) {

this.keys = schema.keys;
this.fields = schema.fields;
this.types = schema.types;

@@ -39,25 +38,25 @@ };

/**
* Returns a subset of the current schema with the given keys. You may pass an array with keys
* Returns a subset of the current schema with the given fields. You may pass an array with fields
* or just the keys as arguments.
*
* @param {String|Array} key1
* @param {String} key2
* @param {String} key3
* @param {string|Array} key1
* @param {string} key2
* @param {string} key3
* @returns {Schema}
*/
Schema.prototype.only = function (key1, key2, key3) {
var subset = Object.create(this),
keys;
var subset = Object.create(this);
var fields;
if (arguments.length === 1 && Array.isArray(key1)) {
keys = key1;
fields = key1;
} else {
keys = slice.call(arguments);
fields = slice.call(arguments);
}
if (keys.length === 0) {
throw new Error("(alamid-schema) Cannot create a subset of the schema with no keys");
if (fields.length === 0) {
throw new Error("Cannot create a subset of the schema with no keys");
}
subset.keys = keys;
subset.fields = fields;

@@ -68,26 +67,26 @@ return subset;

/**
* Returns a subset of the current schema without the given keys. You may pass an array with keys
* Returns a subset of the current schema without the given keys. You may pass an array with fields
* or just the keys as arguments.
*
* @param {String|Array} key1
* @param {String} key2
* @param {String} key3
* @param {string|Array} key1
* @param {string} key2
* @param {string} key3
* @returns {Schema}
*/
Schema.prototype.except = function (key1, key2, key3) {
var subset = Object.create(this),
keys;
var subset = Object.create(this);
var fields;
if (arguments.length === 1 && Array.isArray(key1)) {
keys = key1;
fields = key1;
} else {
keys = slice.call(arguments);
fields = slice.call(arguments);
}
if (keys.length === this.keys.length) {
throw new Error("(alamid-schema) Cannot create a subset of the schema with no keys");
if (fields.length === this.fields.length) {
throw new Error("Cannot create a subset of the schema with no keys");
}
subset.keys = this.keys.filter(function (value) {
return keys.indexOf(value) === -1;
subset.fields = this.fields.filter(function (value) {
return fields.indexOf(value) === -1;
});

@@ -98,10 +97,11 @@

/***
* Returns all writable Fields as Array
/**
* Returns all writable fields as array.
*
* @returns {Array}
*/
Schema.prototype.getWritableFields = function () {
Schema.prototype.writableFields = function () {
var self = this;
return this.keys.filter(function (key) {
return this.fields.filter(function (key) {
return self.definition[key].writable === true;

@@ -111,18 +111,20 @@ });

/***
* Returns a Schema with only writable fields
/**
* Returns a schema with only writable fields.
*
* @returns {Schema}
*/
Schema.prototype.getWritableSchema = function () {
return this.only(this.getWritableFields());
Schema.prototype.writable = function () {
return this.only(this.writableFields());
};
/***
* Returns all writable Fields as Array
/**
* Returns all writable Fields as array.
*
* @returns {Array}
*/
Schema.prototype.getReadableFields = function () {
Schema.prototype.readableFields = function () {
var self = this;
return this.keys.filter(function (key) {
return this.fields.filter(function (key) {
return self.definition[key].readable === true;

@@ -132,8 +134,9 @@ });

/***
* Returns a Schema with only readable fields
/**
* Returns a Schema with only readable fields.
*
* @returns {Schema}
*/
Schema.prototype.getReadableSchema = function () {
return this.only(this.getReadableFields());
Schema.prototype.readable = function () {
return this.only(this.readableFields());
};

@@ -145,3 +148,3 @@

*
* @param {String=Anonymous} name
* @param {string} [name=Anonymous]
* @param {Object} definition

@@ -160,7 +163,22 @@ * @returns {Schema}

/**
* Removes all properties that are not defined in this.fields.
* Will not remove properties that are inherited from the prototype.
*
* @param {Object} model
*/
Schema.prototype.strip = function (model) {
var fields = this.fields;
Object.keys(model)
.forEach(function (key) {
if (fields.indexOf(key) === -1) {
delete model[key];
}
});
};
/**
* Calls the given function with the Schema as first argument and the given config (optionally). Plugins can be used
* to hook into class methods by overriding them.
*
* You may call this function multiple times with the same plugin, the plugin will only be applied once.
*
* @param {Function} plugin

@@ -171,12 +189,7 @@ * @param {Object=} config

Schema.use = function (plugin, config) {
this._plugins = this._plugins || [];
plugin(this, config);
if (this._plugins.indexOf(plugin) === -1) {
plugin(this, config);
this._plugins.push(plugin);
}
return this;
};
module.exports = Schema;
module.exports = Schema;
{
"name": "alamid-schema",
"version": "0.4.0",
"version": "1.0.0",
"description": "Extendable mongoose-like schemas for node.js and the browser",
"main": "lib/Schema.js",
"scripts": {
"test": "node node_modules/mocha/bin/mocha -R spec"
"test": "mocha -R spec",
"posttest": "npm run lint",
"lint": "eslint --fix examples lib plugins test"
},

@@ -13,2 +15,5 @@ "repository": {

},
"engines": {
"node": ">=0.11"
},
"keywords": [

@@ -31,4 +36,3 @@ "schema",

"dependencies": {
"value": "0.3.x",
"when": "^3.7.3"
"value": "^0.3.0"
},

@@ -39,4 +43,6 @@ "devDependencies": {

"chai-spies": "^0.7.0",
"eslint": "^2.9.0",
"eslint-config-peerigon": "^4.0.0",
"mocha": "^2.2.5"
}
}
"use strict";
if (typeof Promise === "undefined") {
require("when/es6-shim/Promise");
}
var value = require("value");
var defaultValidators = require("./validators.js");
var value = require("value"),
defaultValidators = require("./validators.js");
/**
* Runs the given validators on a single field
* Runs the given validators on a single field.
*
* @private
* Caution: callback will be called in synchronously in some situations. This behavior should usually be avoided in
* public APIs, but since runValidation() is internal, we know how to deal with it. It allows us to speed up
* validation and to return all synchronous validation results as soon as possible.
*
* The final callback, however, is guaranteed to be asynchronous.
*
* @param {Array} validators

@@ -18,43 +19,43 @@ * @param {*} field

* @param {Function} callback
* @returns {Array}
*/
function runValidation(validators, field, context, callback) {
var result = [],
pending = validators.length;
var fieldErrors = [];
var pending = 0;
// Return immediately if the field has no validator defined
if (pending === 0) {
setTimeout(function () {
return callback(result);
}, 0);
function saveResult(result) {
if (result !== true) {
fieldErrors.push(result);
}
}
function validationDone(res) {
function doCallback() {
callback(fieldErrors);
}
function asyncValidationDone(result) {
saveResult(result);
pending--;
if (res !== true) {
result.push(res);
}
if (pending === 0) {
callback(result);
}
pending === 0 && doCallback();
}
validators.forEach(function (validator) {
//async
if (validator.length === 2) {
validator.call(context, field, validationDone);
pending++;
validator.call(context, field, asyncValidationDone);
} else {
saveResult(validator.call(context, field));
}
//sync
else {
//no setImmediate on client!
setTimeout(function () {
validationDone(validator.call(context, field));
}, 0);
}
});
if (pending === 0) {
// synchronous callback
doCallback();
}
return fieldErrors;
}
/**
* Adds validation methods to the schema
* Adds validation methods to the schema.
*

@@ -64,8 +65,7 @@ * @param {Function} Schema

function validationPlugin(Schema) {
var constructor = Schema.prototype.constructor;
Schema.prototype.constructor = function (name, schema) {
var key,
fieldDefinition;
var key;
var fieldDefinition;

@@ -76,3 +76,3 @@ if (arguments.length === 1) {

//call super constructor
// call super constructor
constructor.apply(this, arguments);

@@ -87,3 +87,3 @@

//predefined validators
// predefined validators
if (fieldDefinition.required) {

@@ -104,3 +104,20 @@ this.validators[key].push(defaultValidators.required());

//custom validators
if (value(fieldDefinition.minLength).typeOf(Number)) {
this.validators[key].push(defaultValidators.minLength(fieldDefinition.minLength));
}
if (value(fieldDefinition.maxLength).typeOf(Number)) {
this.validators[key].push(defaultValidators.maxLength(fieldDefinition.maxLength));
}
if (value(fieldDefinition.hasLength).typeOf(Number)) {
this.validators[key].push(defaultValidators.hasLength(fieldDefinition.hasLength));
}
// The matches validators works on all types, so we just check if the key is present
if ("matches" in fieldDefinition) {
this.validators[key].push(defaultValidators.matches(fieldDefinition.matches));
}
// custom validators
if (value(fieldDefinition.validate).typeOf(Function)) {

@@ -116,3 +133,5 @@ this.validators[key].push(fieldDefinition.validate);

/**
* Validate if given model matches schema-definition
* Validate if given model matches schema definition. Returns a promise with the validation result object
* which contains the intermediate result of all synchronous validators.
*
* @param {Object} model

@@ -123,10 +142,22 @@ * @param {Function=} callback

Schema.prototype.validate = function (model, callback) {
var self = this,
pending = 0,
result = {
model: model,
result: true,
failedFields: {}
};
var self = this;
var pending = 0;
var result = {
model: model,
result: true,
errors: {}
};
var promise;
function handleFieldErrors(key, fieldErrors) {
if (fieldErrors.length > 0) {
result.result = false;
result.errors[key] = fieldErrors;
}
}
function doCallback() {
callback(result);
}
if (value(model).notTypeOf(Object)) {

@@ -140,40 +171,37 @@ throw new TypeError("Model must be an object");

var promise = new Promise(function (resolve, reject) {
if (self.keys.length === 0) {
setTimeout(function () {
resolve(result);
}, 0);
promise = new Promise(function (resolve) {
function done() {
if (typeof callback === "function") {
setTimeout(doCallback, 0);
}
resolve(result);
}
self.keys.forEach(function (key) {
pending++;
runValidation(self.validators[key], model[key], model, function (failedFields) {
if (self.fields.length === 0) {
done();
return;
}
pending = self.fields.length;
self.fields.forEach(function (key) {
var fieldErrors = runValidation(self.validators[key], model[key], model, function onFieldValidation(fieldErrors) {
pending--;
handleFieldErrors(key, fieldErrors);
if (failedFields.length > 0) {
result.result = false;
result.failedFields[key] = failedFields;
}
//was final call
if (pending === 0) {
if (result.result === false) {
reject(result);
return;
}
resolve(result);
done();
}
});
handleFieldErrors(key, fieldErrors);
});
});
// Attach intermediate result to promise
promise.validation = result;
if (!callback || typeof callback !== "function") {
return promise;
}
promise.then(callback, callback);
return promise;
};
}
module.exports = validationPlugin;
module.exports = validationPlugin;
"use strict";
/**
* returns a required validator
* Returns a required validator.
*
* @returns {Function}

@@ -9,3 +10,3 @@ */

return function validateRequired(val) {
return (val !== undefined && val !== null && val !== "") || "required";
return (typeof val !== "undefined" && val !== null && val !== "") || "required";
};

@@ -15,5 +16,6 @@ }

/**
* returns an enum validator
* Returns an enum validator.
*
* @param {Array} enumValues
* @return {Function}
* @returns {Function}
*/

@@ -27,5 +29,6 @@ function enumValidator(enumValues) {

/**
* returns a min validator
* @param {Number} minValue
* @return {Function}
* Returns a min validator.
*
* @param {number} minValue
* @returns {Function}
*/

@@ -39,5 +42,6 @@ function minValidator(minValue) {

/**
* returns a max validator
* @param {Number} minValue
* @return {Function}
* Returns a max validator.
*
* @param {number} minValue
* @returns {Function}
*/

@@ -50,5 +54,68 @@ function maxValidator(minValue) {

/**
* Returns a minLength validator.
*
* @param {number} minLength
* @returns {Function}
*/
function minLengthValidator(minLength) {
return function validateMinLength(lengthable) {
return lengthable && (lengthable.length >= minLength) || "min-length";
};
}
/**
* Returns a maxLength validator.
*
* @param {number} maxLength
* @returns {Function}
*/
function maxLengthValidators(maxLength) {
return function validateMaxLength(lengthable) {
return lengthable && (lengthable.length <= maxLength) || "max-length";
};
}
/**
* Returns a hasLength validator.
*
* @param {number} hasLength
* @returns {Function}
*/
function hasLengthValidator(hasLength) {
return function validateHasLength(lengthable) {
return lengthable && (lengthable.length === hasLength) || "has-length";
};
}
/**
* Returns true if the given value matches the pattern. The pattern
* may be a value or a regular expression. If it's a value, a strict comparison
* will be performed. In case it's a regex, the test method will be invoked.
*
* @param {*|RegExp} match
* @returns {Function}
*/
function matchesValidator(match) {
return function matchValue(value) {
var result;
if (typeof match.test === "function") {
match.lastIndex = 0; // reset the lastIndex just in case the regexp is accidentally global
result = match.test(value);
} else {
result = match === value;
}
return result || "matches";
};
}
exports.required = requiredValidator;
exports.min = minValidator;
exports.max = maxValidator;
exports.enum = enumValidator;
exports.enum = enumValidator;
exports.minLength = minLengthValidator;
exports.maxLength = maxLengthValidators;
exports.hasLength = hasLengthValidator;
exports.matches = matchesValidator;
alamid-schema
========================================================================
=============
**Extendable mongoose-like schemas for node.js and the browser**

@@ -12,3 +12,3 @@

__alamid-schema__ helps you with
__alamid-schema__ helps you with

@@ -22,7 +22,7 @@ - validation of data

Use it on the server to...
- normalize and validate incoming requests
- normalize and validate incoming requests
- strip private fields from the response
Use it on the client to...
- validate forms
Use it on the client to...
- validate forms
- define view models

@@ -65,3 +65,3 @@

...or with abstract types...
...or with abstract types...

@@ -78,3 +78,3 @@ ```javascript

### Extend
### Extend

@@ -99,3 +99,3 @@ Sometimes you want to extend your Schema and add new properties.

});
```
```

@@ -113,3 +113,3 @@ We have a superpanda now... which can fly and has xray eyes!

xRay: true, //added
canFly: { //added
canFly: { //added
type: Boolean

@@ -121,5 +121,5 @@ }

__Overwriting properties__
__Overwriting properties__
If you define a property in the schema you are extending with, the extending schema takes precedence.
If you define a property in the schema you are extending with, the extending schema takes precedence.

@@ -145,3 +145,3 @@

age: Number, //overwritten
color: String //added
color: String //added
});

@@ -152,6 +152,7 @@ ```

The validation plugins adds - *suprise!* - validation support.
The validation plugins adds - *suprise!* - validation support.
```javascript
var Schema = require("alamid-schema");
Schema.use(require("alamid-schema/plugins/validation"));

@@ -173,2 +174,6 @@

},
treasures: {
type: Array,
minLength: 3
},
birthday: Date

@@ -184,5 +189,4 @@ });

PandaSchema.validate(panda, function(validation) {
if(!validation.result) {
console.log(validation);
if (!validation.result) {
console.log(validation.errors);
return;

@@ -195,3 +199,3 @@ }

outputs...
outputs...

@@ -201,4 +205,4 @@ ```javascript

result: false,
failedFields: {
age: [ 'min' ]
errors: {
age: [ 'min' ]
}

@@ -209,16 +213,20 @@ }

_Included validators:_
_Included validators:_
- required
- min (Number)
- max (Number)
- enum
- min (works on Number)
- max (works on Number)
- enum
- minLength (works on String, Array)
- maxLength (works on String, Array)
- hasLength (works on String, Array)
- matches (performs a strict comparison, also accepts RegExp)
_Writing custom validators:_
You can write sync and async validators..
You can write sync and async validators..
```javascript
//sync
// sync
function oldEnough(age) {

@@ -228,5 +236,4 @@ return age > 18 || "too-young";

//async
// async
function nameIsUnique(name, callback) {
fs.readFile(__dirname + "/names.json", function(err, names) {

@@ -238,3 +245,2 @@ if(err) {

names = JSON.parse(names);
callback(names.indexOf(name) === -1 || "name-already-taken");

@@ -264,5 +270,4 @@ });

PandaSchema.validate(panda, function(validation) {
if(!validation.result) {
console.log(validation.failedFields);
console.log(validation.errors);
return;

@@ -272,10 +277,10 @@ }

});
```
```
outputs...
outputs...
```javascript
{
name: [ "name-already-taken" ],
{
name: [ "name-already-taken" ],
age: [ "too-young" ]

@@ -285,39 +290,61 @@ }

_Note:_ validators will be called with `this` bound to `model`.
_Note:_ validators will be called with `this` bound to `model`.
### Promises
Instead of using a callback it is possible to return a Promise instead.
The `validate()` method also returns a promise:
```javascript
PandaSchema.validate(panda)
.then(function (res) {
// ...
});
.then(function (validation) {
...
})
```
We included an [ES2015 shim](https://github.com/cujojs/when/tree/master/es6-shim) in case you are using Node.js < 0.12 or a browser without native Promise support.
The promise will still be resolved even when the validation fails, because a failed validation is
not an error, it's an expected state.
## API
The promise provides a reference to the final validation result object. It contains the intermediate
result of all synchronous validators:
### Core
```javascript
var promise = PandaSchema.validate(panda);
#### Schema(name?: String, definition: Object)
if (promise.validation.result) {
console.log("Synchronous validation of " + Object.keys(validation.errors) + " failed");
}
```
Creates a new schema.
__Important notice:__ You must bring your own ES6 Promise compatible polyfill!
#### .only(key1: Array|String, key2?: String, key3?: String, ...)
## API
### Core
#### Schema([name: String, ]definition: Object)
Creates a new schema.
#### .fields: Array
The array of property names that are defined on the schema. Do not modify this array.
#### .only(key1: Array|String[, key2: String, key3: String, ...]): Schema
Returns a subset with the given keys of the current schema. You may pass an array with keys or just the keys as arguments.
#### .extend(name?: String, definition: Object)
#### .extend([name: String, ]definition: Object): Schema
Creates a new schema that inherits from the current schema. Field definitions are merged where appropriate.
Creates a new schema that inherits from the current schema. Field definitions are merged where appropriate.
If a definition conflicts with the parent definition, the child's definition supersedes.
#### .strip(model: Object)
Removes all properties from `model` that are not defined in `fields`. Will not remove properties that are inherited from the prototype.
### Readable & Writable fields
You can define readable and writable fields in the schema. As default every field is read- and writable.
You can define readable and writable fields in the schema. By default, every field is read- and writable.
```
```javascript
var PandaSchema = new Schema({

@@ -337,13 +364,38 @@ id: {

#### .getWritableFields()
#### .getWritableSchema()
#### .getReadableFields()
#### .getReadableSchema()
#### .writableFields()
Returns an array containing the keys of all writable fields:
```javascript
PandaSchema.writableFields(); // ["name", "age", "mood", "treasures", "birthday"]
```
#### .writable()
Creates a new schema that contains only the writable fields:
```javascript
var PandaWritableSchema = PandaSchema.writable();
```
#### .readableFields()
Returns an array containing the keys of all readable fields:
```javascript
PandaSchema.readableFields(); // ["name", "age", "mood", "treasures", "birthday"]
```
#### .readable()
Creates a new schema that contains only the readable fields:
```javascript
var PandaReadableSchema = PandaSchema.readable();
```
### Plugin: Validation
#### .validate(model: Object, callback: Function)
#### .validate(model: Object[, callback: Function]): Promise
Validate given model using the schema-definitions.
Callback will be called with a validation object with `result` (Boolean) and `failedFields` (Object).
Validate given model using the schema definitions. Callback will be called/Promise will be fulfilled with a validation object with `result` (Boolean) and `errors` (Object) containing the error codes.
"use strict";
var chai = require("chai"),
expect = chai.expect,
merge = require("../lib/merge.js");
var chai = require("chai");
var expect = chai.expect;
var merge = require("../lib/merge.js");
chai.config.includeStack = true;
describe("merge(source, target)", function () {
var a,
b;
var a;
var b;

@@ -38,4 +40,4 @@ it("should copy all properties from source to target", function () {

it("should not alter the source", function () {
var a = {},
b = { b: "b" };
var a = {};
var b = { b: "b" };

@@ -50,3 +52,3 @@ merge(a, b);

1: {
1: "1"
1: "1"
}

@@ -56,3 +58,3 @@ };

1: {
2: "2"
2: "2"
}

@@ -65,4 +67,4 @@ };

1: {
1: "1",
2: "2"
1: "1",
2: "2"
}

@@ -169,2 +171,2 @@ });

});
});
"use strict";
var chai = require("chai"),
expect = chai.expect,
Schema = require("../" + require("../package.json").main);
var chai = require("chai");
var expect = chai.expect;
var Schema = require("../lib/Schema.js");
chai.config.includeStack = true;
describe("Schema", function () {

@@ -11,5 +13,6 @@

var schema;
var definition;
beforeEach(function () {
schema = new Schema({
definition = {
name: {

@@ -22,5 +25,7 @@ type: "String",

friends: {
writable: false,
type: Array
}
});
};
schema = new Schema(definition);
});

@@ -30,4 +35,4 @@

it("should extract the keys from the definition", function () {
expect(schema.keys).to.eql(["name", "age", "friends"]);
it("should extract the fields from the definition", function () {
expect(schema.fields).to.eql(["name", "age", "friends"]);
});

@@ -52,3 +57,2 @@

it("should extract the types from the definition if using values", function () {

@@ -73,20 +77,20 @@

expect(schema.definition).to.eql({
"age": {
"readable": true,
"type": "Number",
"writable": true
age: {
readable: true,
type: "Number",
writable: true
},
"friends": {
"readable": true,
"type": "Array",
"writable": true
friends: {
readable: true,
type: "Array",
writable: false
},
"name": {
"readable": false,
"type": "String",
"writable": false
name: {
readable: false,
type: "String",
writable: false
}
});
});
it("should apply 'Anonymous' as schema name", function () {

@@ -102,13 +106,3 @@ expect(schema.name).to.equal("Anonymous");

beforeEach(function () {
namedSchema = new Schema("User", {
name: {
type: "String",
readable: false,
writable: false
},
age: 3,
friends: {
type: Array
}
});
namedSchema = new Schema("User", definition);
});

@@ -135,5 +129,5 @@

it("should inherit all properties prototypically except 'keys'", function () {
var ownProperties = [],
key;
it("should inherit all properties prototypically except 'fields'", function () {
var ownProperties = [];
var key;

@@ -146,3 +140,3 @@ subset = schema.only("name", "age");

}
expect(ownProperties).to.eql(["keys"]);
expect(ownProperties).to.eql(["fields"]);
expect(schema.types).to.be.an("object");

@@ -152,5 +146,5 @@ expect(schema.name).to.be.an("string");

it("should change the .keys-property to the given keys", function () {
it("should change the .fields-property to the given keys", function () {
subset = schema.only("name", "age");
expect(subset.keys).to.eql(["name", "age"]);
expect(subset.fields).to.eql(["name", "age"]);
});

@@ -171,3 +165,3 @@

subset = schema.only(["name", "age"]);
expect(subset.keys).to.eql(["name", "age"]);
expect(subset.fields).to.eql(["name", "age"]);
});

@@ -191,5 +185,5 @@

it("should inherit all properties prototypically except 'keys'", function () {
var ownProperties = [],
key;
it("should inherit all properties prototypically except 'fields'", function () {
var ownProperties = [];
var key;

@@ -202,3 +196,3 @@ subset = schema.except("name", "age");

}
expect(ownProperties).to.eql(["keys"]);
expect(ownProperties).to.eql(["fields"]);
expect(schema.types).to.be.an("object");

@@ -208,5 +202,5 @@ expect(schema.name).to.be.an("string");

it("should exclude the given keys from the keys-property", function () {
it("should exclude the given keys from the fields-property", function () {
subset = schema.except("friends", "age");
expect(subset.keys).to.eql(["name"]);
expect(subset.fields).to.eql(["name"]);
});

@@ -216,3 +210,3 @@

expect(function () {
schema.except.apply(schema, schema.keys);
schema.except.apply(schema, schema.fields);
}).to.throw("Cannot create a subset of the schema with no keys");

@@ -228,3 +222,3 @@ });

subset = schema.only(["name", "age"]);
expect(subset.keys).to.eql(["name", "age"]);
expect(subset.fields).to.eql(["name", "age"]);
});

@@ -234,3 +228,3 @@

expect(function () {
schema.except(schema.keys);
schema.except(schema.fields);
}).to.throw("Cannot create a subset of the schema with no keys");

@@ -248,3 +242,3 @@ });

expect(extended).to.not.equal(schema);
expect(extended.keys).to.not.equal(schema.keys);
expect(extended.fields).to.not.equal(schema.fields);
expect(extended.types).to.not.equal(schema.types);

@@ -262,3 +256,3 @@ expect(extended).to.eql(schema);

expect(extended.keys).to.contain("password", "token");
expect(extended.fields).to.contain("password", "token");
expect(extended.types.password).to.equal("String");

@@ -300,3 +294,3 @@ expect(extended.types.token).to.equal("String");

expect(extended.keys).to.contain("password", "token");
expect(extended.fields).to.contain("password", "token");
expect(extended.types.password).to.equal("String");

@@ -308,7 +302,8 @@ expect(extended.types.token).to.equal("String");

describe(".getWritableFields()", function () {
describe(".writableFields()", function () {
it("should return writable fields", function () {
var writableFields = schema.getWritableFields();
expect(writableFields).to.eql(["age", "friends"]);
var writableFields = schema.writableFields();
expect(writableFields).to.eql(["age"]);
});

@@ -318,7 +313,9 @@

describe(".getWritableSchema()", function () {
describe(".writable()", function () {
it("should return a schema with only writeable Fields", function () {
var writableSchema = schema.getWritableSchema();
expect(writableSchema.keys.length).to.eql(2);
it("should return a schema with only writable fields", function () {
var writableSchema = schema.writable();
expect(writableSchema).to.be.an.instanceOf(Schema);
expect(writableSchema.fields).to.eql(["age"]);
});

@@ -328,6 +325,7 @@

describe(".getReadableFields()", function () {
describe(".readableFields()", function () {
it("should return readable fields", function () {
var readableFields = schema.getReadableFields();
var readableFields = schema.readableFields();
expect(readableFields).to.eql(["age", "friends"]);

@@ -338,8 +336,9 @@ });

describe(".readable()", function () {
describe(".getReadableSchema()", function () {
it("should return a schema with only readable fields", function () {
var readableSchema = schema.readable();
it("should return a schema with only readable Fields", function () {
var readableSchema = schema.getReadableSchema();
expect(readableSchema.keys.length).to.eql(2);
expect(readableSchema).to.be.an.instanceOf(Schema);
expect(readableSchema.fields).to.eql(["age", "friends"]);
});

@@ -349,4 +348,39 @@

describe(".strip(model)", function () {
it("should remove all additional keys", function () {
var model = {
name: "Octocat",
someOtherProperty: true,
andAnArray: [1, 2, 3]
};
schema.strip(model);
expect(model).to.eql({ name: "Octocat" });
});
it("will not work with prototype inheritance", function () {
var model = Object.create({
someOtherProperty: true,
andAnArray: [1, 2, 3]
});
model.name = "Octocat";
schema.strip(model);
expect(model).to.eql(model);
});
it("should work on empty objects", function () {
var model = {};
expect(function () {
schema.strip(model);
}).to.not.throw();
expect(model).to.eql({});
});
});
});
});
});
"use strict";
var chai = require("chai"),
expect = chai.expect,
spies = require('chai-spies'),
chaiAsPromised = require("chai-as-promised");
var chai = require("chai");
var spies = require("chai-spies");
var chaiAsPromised = require("chai-as-promised");
var Schema = require("../lib/Schema.js");
var validators = require("../plugins/validation/validators.js");
var validationPlugin = require("../plugins/validation/index.js");
var expect = chai.expect;
var Schema = require("../lib/Schema.js"),
validators = require("../plugins/validation/validators.js"),
validationPlugin = require("../plugins/validation/index.js");
chai.use(spies);
chai.use(chaiAsPromised);
chai.Assertion.includeStack = true;
function oldEnough(age) {

@@ -24,2 +19,5 @@ return age > 18 || "too-young";

chai.use(spies);
chai.use(chaiAsPromised);
chai.config.includeStack = true;
Schema.use(validationPlugin);

@@ -49,7 +47,6 @@

it("should add a enum validator", function () {
var schema = new Schema({
tags: {
type: String,
"enum": ["a", "b"]
enum: ["a", "b"]
}

@@ -64,3 +61,2 @@ });

it("should add a min validator", function () {
var schema = new Schema({

@@ -79,3 +75,2 @@ age: {

it("should add a max validator", function () {
var schema = new Schema({

@@ -93,2 +88,55 @@ age: {

it("should add a minLength validator", function () {
var schema = new Schema({
name: {
type: String,
minLength: 5
}
});
expect(schema.validators.name).to.be.an("array");
expect(schema.validators.name).to.have.length(1);
expect(schema.validators.name[0].name).to.eql(validators.minLength().name);
});
it("should add a maxLength validator", function () {
var schema = new Schema({
name: {
type: String,
maxLength: 5
}
});
expect(schema.validators.name).to.be.an("array");
expect(schema.validators.name).to.have.length(1);
expect(schema.validators.name[0].name).to.eql(validators.maxLength().name);
});
it("should add a hasLength validator", function () {
var schema = new Schema({
name: {
type: String,
hasLength: 5
}
});
expect(schema.validators.name).to.be.an("array");
expect(schema.validators.name).to.have.length(1);
expect(schema.validators.name[0].name).to.eql(validators.hasLength().name);
});
it("should add a matches validator", function () {
var schema = new Schema({
age: {
type: Number,
matches: 2
}
});
expect(schema.validators.age).to.be.an("array");
expect(schema.validators.age).to.have.length(1);
expect(schema.validators.age[0].name).to.eql(validators.matches().name);
});
});

@@ -99,3 +147,2 @@

it("should accept a single validation function", function () {
var schema = new Schema({

@@ -114,3 +161,2 @@ age: {

it("should accept an array of validation functions", function () {
var schema = new Schema({

@@ -154,15 +200,15 @@ age: {

var schema = new Schema({
age: {
required: true,
max: 99,
validate: oldEnough
}
}),
extended = schema.extend({
age: {
required: false,
validate: notTooOld
}
}),
ageValidators = extended.validators.age.toString();
age: {
required: true,
max: 99,
validate: oldEnough
}
});
var extended = schema.extend({
age: {
required: false,
validate: notTooOld
}
});
var ageValidators = extended.validators.age.toString();

@@ -226,5 +272,5 @@ expect(ageValidators).to.contain(validators.max(), oldEnough, notTooOld);

schema.validate({age: 18}, function (validation) {
schema.validate({ age: 18 }, function (validation) {
expect(validation.result).to.eql(true);
expect(validation.failedFields).to.eql({});
expect(validation.errors).to.eql({});
done();

@@ -246,5 +292,5 @@ });

schema.validate({age: 18}, function (validation) {
schema.validate({ age: 18 }, function (validation) {
expect(validation.result).to.eql(true);
expect(validation.failedFields).to.eql({});
expect(validation.errors).to.eql({});
done();

@@ -266,8 +312,6 @@ });

it("should return a promise if no callback is given", function () {
expect(schema.validate({age: 2})).to.be.a("promise");
expect(schema.validate({ age: 2 })).to.be.a("promise");
});
it("should resolve if validation succeeds", function () {
schema = new Schema({

@@ -280,10 +324,9 @@ age: {

return schema.validate({age: 4})
.then(function(validation) {
expect(validation).to.eql({result: true, model: { age: 4 }, failedFields: {}});
return schema.validate({ age: 4 })
.then(function (validation) {
expect(validation).to.eql({ result: true, model: { age: 4 }, errors: {} });
});
});
it("should reject if validation fails", function () {
it("should not reject if validation fails", function () {
schema = new Schema({

@@ -296,10 +339,45 @@ age: {

return schema.validate({age: 1})
.then(function() {
throw new Error("Should not resolve");
return schema.validate({ age: 1 })
.then(function (validation) {
expect(validation).to.eql({ result: false, model: { age: 1 }, errors: { age: ["min"] } });
})
.catch(function(validation) {
expect(validation).to.eql({result: false, model: { age: 1 }, failedFields: {age: ["min"]}});
.catch(function () {
throw new Error("Should not reject");
});
});
it("should provide the intermediate result of all synchronous validators", function () {
var intermediateResult;
schema = new Schema({
age: {
type: Number,
min: 5,
validate: [
function syncTrue() {
return true;
},
function asyncTrue(value, callback) {
setTimeout(function () {
callback(true);
}, 0);
},
function syncFail() {
return "sync-fail";
},
function asyncFail(value, callback) {
setTimeout(function () {
callback("async-fail");
}, 0);
}
]
}
});
intermediateResult = schema.validate({ age: 1 }).validation;
expect(intermediateResult.result).to.equal(false);
expect(intermediateResult.errors.age).to.eql(["min", "sync-fail"]);
});
});

@@ -320,4 +398,4 @@

it("should pass if async & sync validators pass", function (done) {
var asyncSpy = chai.spy(validateAgeAsync),
syncSpy = chai.spy(validateAgeSync);
var asyncSpy = chai.spy(validateAgeAsync);
var syncSpy = chai.spy(validateAgeSync);

@@ -331,7 +409,7 @@ schema = new Schema({

schema.validate({age: 18}, function (validation) {
schema.validate({ age: 18 }, function (validation) {
expect(asyncSpy).to.have.been.called.once();
expect(syncSpy).to.have.been.called.once();
expect(validation.result).to.eql(true);
expect(validation.failedFields).to.eql({});
expect(validation.errors).to.eql({});
done();

@@ -342,4 +420,4 @@ });

it("should fail if an async and sync validator fail", function (done) {
var asyncSpy = chai.spy(validateAgeAsync),
syncSpy = chai.spy(validateAgeSync);
var asyncSpy = chai.spy(validateAgeAsync);
var syncSpy = chai.spy(validateAgeSync);

@@ -353,7 +431,7 @@ schema = new Schema({

schema.validate({age: 6}, function (validation) {
schema.validate({ age: 6 }, function (validation) {
expect(asyncSpy).to.have.been.called.once();
expect(syncSpy).to.have.been.called.once();
expect(validation.result).to.eql(false);
expect(validation.failedFields.age).to.contain("fail-async", "fail-sync");
expect(validation.errors.age).to.contain("fail-async", "fail-sync");
done();

@@ -365,7 +443,7 @@ });

var asyncSpy = chai.spy(function (age, callback) {
setTimeout(function () {
callback("fail-async");
}, 0);
}),
syncSpy = chai.spy(validateAgeSync);
setTimeout(function () {
callback("fail-async");
}, 0);
});
var syncSpy = chai.spy(validateAgeSync);

@@ -379,7 +457,7 @@ schema = new Schema({

schema.validate({age: 6}, function (validation) {
schema.validate({ age: 6 }, function (validation) {
expect(asyncSpy).to.have.been.called.once();
expect(syncSpy).to.have.been.called.once();
expect(validation.result).to.eql(false);
expect(validation.failedFields.age).to.contain("fail-async");
expect(validation.errors.age).to.contain("fail-async");
done();

@@ -389,9 +467,31 @@ });

it("should degrade gracefully with an false async validator", function (done) {
var falseAsyncSpy = chai.spy(function (age, callback) {
callback("fail-false-async"); // callback is called synchronously. This is a common error.
});
schema = new Schema({
age: {
type: Number,
validate: falseAsyncSpy
}
});
schema.validate({ age: 8 }, function (validation) {
expect(falseAsyncSpy).to.have.been.called.once();
expect(validation.result).to.equal(false);
expect(validation.errors.age).to.contain("fail-false-async");
done();
});
});
it("should fail if the sync validator fails & async passes", function (done) {
var asyncSpy = chai.spy(function (age, callback) {
callback(true);
}),
syncSpy = chai.spy(function (age) {
return "fail-sync";
});
setTimeout(function () {
callback("fail-async");
}, 0);
});
var syncSpy = chai.spy(function (age) {
return "fail-sync";
});

@@ -405,7 +505,7 @@ schema = new Schema({

schema.validate({age: 8}, function (validation) {
schema.validate({ age: 8 }, function (validation) {
expect(asyncSpy).to.have.been.called.once();
expect(syncSpy).to.have.been.called.once();
expect(validation.result).to.eql(false);
expect(validation.failedFields.age).to.contain("fail-sync");
expect(validation.result).to.equal(false);
expect(validation.errors.age).to.contain("fail-sync");
done();

@@ -419,2 +519,2 @@ });

});
});

Sorry, the diff of this file is not supported yet

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