From 5aff220c2e6f783075b36cc8ab01d82a46dcb63d Mon Sep 17 00:00:00 2001 From: Vlad Barosan Date: Fri, 11 May 2018 15:58:53 -0700 Subject: [PATCH] Add support for x-ms-mutability --- lib/helpers.js | 32 +++------- lib/validation/custom-zschema-validators.js | 67 +++++++++++++++++++++ package.json | 2 +- 3 files changed, 76 insertions(+), 25 deletions(-) create mode 100644 lib/validation/custom-zschema-validators.js diff --git a/lib/helpers.js b/lib/helpers.js index 60896ef9..b4647161 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -27,6 +27,7 @@ var _ = require('lodash'); var formatGenerators = require('./validation/format-generators'); var formatValidators = require('./validation/format-validators'); +var customValidators = require('./validation/custom-zschema-validators'); var JsonRefs = require('json-refs'); var rewire = require('rewire'); var ZSchemaValidator = rewire('z-schema/src/JsonValidation'); @@ -107,28 +108,10 @@ function registerFormat (name, validator) { } function createJSONValidator () { - // overwrite the enum validation through rewire until z-schema supports it. - function customEnumValidator (report, schema, json) { - var match = false; - var idx = schema.enum.length; - var caseInsensitiveMatch = false; - - while (idx--) { - if (json === schema.enum[idx]) { - match = true; - return; - } else if (typeof json === 'string' && typeof schema.enum[idx] === 'string' && json.toUpperCase() === schema.enum[idx].toUpperCase()) { - caseInsensitiveMatch = true; - } - } - if (caseInsensitiveMatch === true) { - report.addCustomError('ENUM_CASE_MISMATCH', 'Enum doesn not match case for: {0}', [json], null, schema.description); - } else if (match === false) { - report.addError('ENUM_MISMATCH', [json], null, schema.description); - } - }; - ZSchemaValidator.__set__('JsonValidators.enum', customEnumValidator); + // overwrite validators through rewire until z-schema supports overriding the validators. + ZSchemaValidator.__set__('JsonValidators.enum', customValidators.enumValidator); + ZSchemaValidator.__set__('JsonValidators.required', customValidators.requiredPropertyValidator); ZSchema.__set__('JsonValidation', ZSchemaValidator); var validator = new ZSchema({ @@ -479,10 +462,11 @@ module.exports.removeCirculars = function (obj) { * @param {object} schema - The JSON Schema * @param {*} value - The value to validate * @param {string} schemaPath - The path to sub schema with the schema that needs to be validated - * + * @param {boolean} isResponse - true if the value being validated is part of a response, false otherwise + * * @returns {object} Object containing the errors and warnings of the validation */ -module.exports.validateAgainstSchema = function (validator, schema, value, schemaPath) { +module.exports.validateAgainstSchema = function (validator, schema, value, schemaPath, isResponse) { schema = _.cloneDeep(schema); // Clone the schema as z-schema alters the provided document var response = { @@ -494,7 +478,7 @@ module.exports.validateAgainstSchema = function (validator, schema, value, schem if (!schemaPath) { isValid = validator.validate(value, schema); } else { - isValid = validator.validate(value, schema, {schemaPath: schemaPath}); + isValid = validator.validate(value, schema, {schemaPath: schemaPath, isResponse: isResponse}); } if (!isValid) { diff --git a/lib/validation/custom-zschema-validators.js b/lib/validation/custom-zschema-validators.js new file mode 100644 index 00000000..7021b53f --- /dev/null +++ b/lib/validation/custom-zschema-validators.js @@ -0,0 +1,67 @@ + +'use strict'; + +function enumValidator (report, schema, json) { + var match = false; + var idx = schema.enum.length; + var caseInsensitiveMatch = false; + + while (idx--) { + if (json === schema.enum[idx]) { + match = true; + return; + } else if ( + typeof json === 'string' && + typeof schema.enum[idx] === 'string' && + json.toUpperCase() === schema.enum[idx].toUpperCase() + ) { + caseInsensitiveMatch = true; + } + } + + if (caseInsensitiveMatch === true) { + report.addCustomError( + 'ENUM_CASE_MISMATCH', + 'Enum doesn not match case for: {0}', + [json], + null, + schema.description + ); + } else if (match === false) { + report.addError('ENUM_MISMATCH', [json], null, schema.description); + } +} + +function requiredPropertyValidator (report, schema, json) { + // http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.4.3.2 + + if ( + !(typeof json === 'object' && json === Object(json) && !Array.isArray(json)) + ) { + return; + } + var idx = schema.required.length; + var requiredPropertyName; + var xMsMutability; + + while (idx--) { + requiredPropertyName = schema.required[idx]; + xMsMutability = (schema.properties && schema.properties[`${requiredPropertyName}`]) && schema.properties[`${requiredPropertyName}`]['x-ms-mutability']; + + // If a response has x-ms-mutability property and its missing the read we can skip this step + if (this.validateOptions && this.validateOptions.isResponse && xMsMutability && xMsMutability.indexOf('read') === -1) { + continue; + } + if (json[requiredPropertyName] === undefined) { + report.addError( + 'OBJECT_MISSING_REQUIRED_PROPERTY', + [requiredPropertyName], + null, + schema.description + ); + } + } +} + +module.exports.enumValidator = enumValidator; +module.exports.requiredPropertyValidator = requiredPropertyValidator; diff --git a/package.json b/package.json index 00e20579..3cca2ac0 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,6 @@ "rewire": "^4.0.0", "swagger-methods": "^1.0.0", "swagger-schema-official": "2.0.0-bab6bed", - "z-schema": "^3.19.1" + "z-schema": "^3.21.0" } }