From 17d65eb4fd2b7f341e988d4a136297e4e1c6e933 Mon Sep 17 00:00:00 2001 From: Viktor Wensel Date: Tue, 12 Oct 2021 12:17:18 +0200 Subject: [PATCH 1/3] add handling with object type (Boolean, String, Number) --- lib/attribute.js | 2 +- lib/validator.js | 22 +++++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/attribute.js b/lib/attribute.js index 67f526a..479a1d1 100644 --- a/lib/attribute.js +++ b/lib/attribute.js @@ -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'], diff --git a/lib/validator.js b/lib/validator.js index cce1694..c92f6d3 100644 --- a/lib/validator.js +++ b/lib/validator.js @@ -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 % 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) { @@ -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; From 9de855f17c0ec1584b3cc51fd85f0d8d1fd6f4aa Mon Sep 17 00:00:00 2001 From: Viktor Wensel Date: Tue, 12 Oct 2021 12:59:14 +0200 Subject: [PATCH 2/3] fix Number is integer --- lib/validator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/validator.js b/lib/validator.js index c92f6d3..57c49e0 100644 --- a/lib/validator.js +++ b/lib/validator.js @@ -322,7 +322,7 @@ types.number = function testNumber (instance) { }; types.integer = function testInteger (instance) { - if (instance instanceof Number && instance % 1 === 0) { + if (instance instanceof Number && instance.valueOf() % 1 === 0) { return true; } From acbd29cca9826d0e9b4bcb6bc1e3396fc94a91c7 Mon Sep 17 00:00:00 2001 From: Viktor Wensel Date: Mon, 7 Mar 2022 10:42:36 +0100 Subject: [PATCH 3/3] Error.captureStackTrace quick fix --- lib/helpers.js | 74 ++++++++++++++++++++++++++------------------------ package.json | 4 +-- 2 files changed, 41 insertions(+), 37 deletions(-) diff --git a/lib/helpers.js b/lib/helpers.js index cc6cd80..077c2f3 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -1,14 +1,18 @@ 'use strict'; +// BUG: quick fix +Error.captureStackTrace = () => { }; +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)) { 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) { @@ -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; @@ -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; @@ -101,7 +105,7 @@ 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); @@ -109,35 +113,35 @@ var SchemaError = exports.SchemaError = function SchemaError (msg, schema) { }; 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; @@ -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); @@ -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 @@ -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; } @@ -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 { @@ -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]; } @@ -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 && [] || {}; @@ -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(''); @@ -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'); }; diff --git a/package.json b/package.json index 8661320..a2334ef 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "author": "Tom de Grunt ", "name": "jsonschema", - "version": "1.4.0", + "version": "1.4.1", "license": "MIT", "dependencies": {}, "contributors": [ @@ -39,4 +39,4 @@ "stryker": "stryker run", "test": "./node_modules/.bin/mocha -R spec" } -} +} \ No newline at end of file