Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handling of object type (Boolean, String, Number) #351

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/attribute.js
Original file line number Diff line number Diff line change
Expand Up @@ -914,7 +914,7 @@ validators['enum'] = function validateEnum (instance, schema, options, ctx) {
throw new SchemaError("enum expects an array", schema);
}
var result = new ValidatorResult(instance, schema, options, ctx);
if (!schema['enum'].some(helpers.deepCompareStrict.bind(null, instance))) {
if (!schema['enum'].some(helpers.deepCompareStrict.bind(null, instance.valueOf()))) {
result.addError({
name: 'enum',
argument: schema['enum'],
Expand Down
74 changes: 39 additions & 35 deletions lib/helpers.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
'use strict';

// BUG: quick fix
Error.captureStackTrace = () => { };
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What bug is this fixing? We can't modify the builtin objects (Error, Number, Math, etc), this could interfere with other libraries in the same environment.

Error.prototype.captureStackTrace = () => { };

var uri = require('url');

var ValidationError = exports.ValidationError = function ValidationError (message, instance, schema, path, name, argument) {
if(Array.isArray(path)){
var ValidationError = exports.ValidationError = function ValidationError(message, instance, schema, path, name, argument) {
if (Array.isArray(path)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please try to keep changes strictly relevant to the purpose of the PR... avoid making whitespace changes. We can consider these sorts of changes, but this is best done in a separate task.

this.path = path;
this.property = path.reduce(function(sum, item){
this.property = path.reduce(function (sum, item) {
return sum + makeSuffix(item);
}, 'instance');
}else if(path !== undefined){
} else if (path !== undefined) {
this.property = path;
}
if (message) {
Expand Down Expand Up @@ -57,7 +61,7 @@ ValidatorResult.prototype.addError = function addError(detail) {
this.errors.push(err);
if (this.throwFirst) {
throw new ValidatorResultError(this);
}else if(this.throwError){
} else if (this.throwError) {
throw err;
}
return err;
Expand All @@ -71,20 +75,20 @@ ValidatorResult.prototype.importErrors = function importErrors(res) {
}
};

function stringizer (v,i){
return i+': '+v.toString()+'\n';
function stringizer(v, i) {
return i + ': ' + v.toString() + '\n';
}
ValidatorResult.prototype.toString = function toString(res) {
return this.errors.map(stringizer).join('');
};

Object.defineProperty(ValidatorResult.prototype, "valid", { get: function() {
return !this.errors.length;
return !this.errors.length;
} });

module.exports.ValidatorResultError = ValidatorResultError;
function ValidatorResultError(result) {
if(Error.captureStackTrace){
if (Error.captureStackTrace) {
Error.captureStackTrace(this, ValidatorResultError);
}
this.instance = result.instance;
Expand All @@ -101,43 +105,43 @@ ValidatorResultError.prototype.name = "Validation Error";
* @name SchemaError
* @constructor
*/
var SchemaError = exports.SchemaError = function SchemaError (msg, schema) {
var SchemaError = exports.SchemaError = function SchemaError(msg, schema) {
this.message = msg;
this.schema = schema;
Error.call(this, msg);
Error.captureStackTrace(this, SchemaError);
};
SchemaError.prototype = Object.create(Error.prototype,
{
constructor: {value: SchemaError, enumerable: false},
name: {value: 'SchemaError', enumerable: false},
constructor: { value: SchemaError, enumerable: false },
name: { value: 'SchemaError', enumerable: false },
});

var SchemaContext = exports.SchemaContext = function SchemaContext (schema, options, path, base, schemas) {
var SchemaContext = exports.SchemaContext = function SchemaContext(schema, options, path, base, schemas) {
this.schema = schema;
this.options = options;
if(Array.isArray(path)){
if (Array.isArray(path)) {
this.path = path;
this.propertyPath = path.reduce(function(sum, item){
this.propertyPath = path.reduce(function (sum, item) {
return sum + makeSuffix(item);
}, 'instance');
}else{
} else {
this.propertyPath = path;
}
this.base = base;
this.schemas = schemas;
};

SchemaContext.prototype.resolve = function resolve (target) {
SchemaContext.prototype.resolve = function resolve(target) {
return uri.resolve(this.base, target);
};

SchemaContext.prototype.makeChild = function makeChild(schema, propertyName){
var path = (propertyName===undefined) ? this.path : this.path.concat([propertyName]);
SchemaContext.prototype.makeChild = function makeChild(schema, propertyName) {
var path = (propertyName === undefined) ? this.path : this.path.concat([propertyName]);
var id = schema.$id || schema.id;
var base = uri.resolve(this.base, id||'');
var base = uri.resolve(this.base, id || '');
var ctx = new SchemaContext(schema, this.options, path, base, Object.create(this.schemas));
if(id && !ctx.schemas[base]){
if (id && !ctx.schemas[base]) {
ctx.schemas[base] = schema;
}
return ctx;
Expand Down Expand Up @@ -211,7 +215,7 @@ FORMAT_REGEXPS.regexp = FORMAT_REGEXPS.regex;
FORMAT_REGEXPS.pattern = FORMAT_REGEXPS.regex;
FORMAT_REGEXPS.ipv4 = FORMAT_REGEXPS['ip-address'];

exports.isFormat = function isFormat (input, format, validator) {
exports.isFormat = function isFormat(input, format, validator) {
if (typeof input === 'string' && FORMAT_REGEXPS[format] !== undefined) {
if (FORMAT_REGEXPS[format] instanceof RegExp) {
return FORMAT_REGEXPS[format].test(input);
Expand All @@ -220,13 +224,13 @@ exports.isFormat = function isFormat (input, format, validator) {
return FORMAT_REGEXPS[format](input);
}
} else if (validator && validator.customFormats &&
typeof validator.customFormats[format] === 'function') {
typeof validator.customFormats[format] === 'function') {
return validator.customFormats[format](input);
}
return true;
};

var makeSuffix = exports.makeSuffix = function makeSuffix (key) {
var makeSuffix = exports.makeSuffix = function makeSuffix(key) {
key = key.toString();
// This function could be capable of outputting valid a ECMAScript string, but the
// resulting code for testing which form to use would be tens of thousands of characters long
Expand All @@ -240,7 +244,7 @@ var makeSuffix = exports.makeSuffix = function makeSuffix (key) {
return '[' + JSON.stringify(key) + ']';
};

exports.deepCompareStrict = function deepCompareStrict (a, b) {
exports.deepCompareStrict = function deepCompareStrict(a, b) {
if (typeof a !== typeof b) {
return false;
}
Expand Down Expand Up @@ -271,7 +275,7 @@ exports.deepCompareStrict = function deepCompareStrict (a, b) {
return a === b;
};

function deepMerger (target, dst, e, i) {
function deepMerger(target, dst, e, i) {
if (typeof e === 'object') {
dst[i] = deepMerge(target[i], e);
} else {
Expand All @@ -281,11 +285,11 @@ function deepMerger (target, dst, e, i) {
}
}

function copyist (src, dst, key) {
function copyist(src, dst, key) {
dst[key] = src[key];
}

function copyistWithDeepMerge (target, src, dst, key) {
function copyistWithDeepMerge(target, src, dst, key) {
if (typeof src[key] !== 'object' || !src[key]) {
dst[key] = src[key];
}
Expand All @@ -298,7 +302,7 @@ function copyistWithDeepMerge (target, src, dst, key) {
}
}

function deepMerge (target, src) {
function deepMerge(target, src) {
var array = Array.isArray(src);
var dst = array && [] || {};

Expand Down Expand Up @@ -328,23 +332,23 @@ module.exports.deepMerge = deepMerge;
exports.objectGetPath = function objectGetPath(o, s) {
var parts = s.split('/').slice(1);
var k;
while (typeof (k=parts.shift()) == 'string') {
var n = decodeURIComponent(k.replace(/~0/,'~').replace(/~1/g,'/'));
while (typeof (k = parts.shift()) == 'string') {
var n = decodeURIComponent(k.replace(/~0/, '~').replace(/~1/g, '/'));
if (!(n in o)) return;
o = o[n];
}
return o;
};

function pathEncoder (v) {
return '/'+encodeURIComponent(v).replace(/~/g,'%7E');
function pathEncoder(v) {
return '/' + encodeURIComponent(v).replace(/~/g, '%7E');
}
/**
* Accept an Array of property names and return a JSON Pointer URI fragment
* @param Array a
* @return {String}
*/
exports.encodePath = function encodePointer(a){
exports.encodePath = function encodePointer(a) {
// ~ must be encoded explicitly because hacks
// the slash is encoded by encodeURIComponent
return a.map(pathEncoder).join('');
Expand Down Expand Up @@ -384,7 +388,7 @@ exports.getDecimalPlaces = function getDecimalPlaces(number) {
return decimalPlaces;
};

exports.isSchema = function isSchema(val){
exports.isSchema = function isSchema(val) {
return (typeof val === 'object' && val) || (typeof val === 'boolean');
};

22 changes: 21 additions & 1 deletion lib/validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -304,16 +304,36 @@ Validator.prototype.testType = function validateType (instance, schema, options,

var types = Validator.prototype.types = {};
types.string = function testString (instance) {

if (instance instanceof String) {
return true;
}

return typeof instance == 'string';
};
types.number = function testNumber (instance) {

if (instance instanceof Number && isFinite(instance.valueOf())) {
return true;
}

// isFinite returns false for NaN, Infinity, and -Infinity
return typeof instance == 'number' && isFinite(instance);
};
types.integer = function testInteger (instance) {

if (instance instanceof Number && instance.valueOf() % 1 === 0) {
return true;
}

return (typeof instance == 'number') && instance % 1 === 0;
};
types.boolean = function testBoolean (instance) {

if (instance instanceof Boolean) {
return true;
}

return typeof instance == 'boolean';
};
types.array = function testArray (instance) {
Expand All @@ -330,7 +350,7 @@ types.any = function testAny (instance) {
};
types.object = function testObject (instance) {
// TODO: fix this - see #15
return instance && (typeof instance === 'object') && !(Array.isArray(instance)) && !(instance instanceof Date);
return instance && (typeof instance === 'object') && !(Array.isArray(instance)) && !(instance instanceof Date) && !(instance instanceof Number) && !(instance instanceof String) && !(instance instanceof Boolean);
};

module.exports = Validator;
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"author": "Tom de Grunt <[email protected]>",
"name": "jsonschema",
"version": "1.4.0",
"version": "1.4.1",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull requests don't need to touch this file, we can do that at the appropriate time.

"license": "MIT",
"dependencies": {},
"contributors": [
Expand Down Expand Up @@ -39,4 +39,4 @@
"stryker": "stryker run",
"test": "./node_modules/.bin/mocha -R spec"
}
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And finally, make sure lines are terminated with a newline. Git has trouble with lines that are missing a newline character at the end.