init
This commit is contained in:
621
node_modules/z-schema/src/JsonValidation.js
generated
vendored
Normal file
621
node_modules/z-schema/src/JsonValidation.js
generated
vendored
Normal file
@ -0,0 +1,621 @@
|
||||
"use strict";
|
||||
|
||||
var FormatValidators = require("./FormatValidators"),
|
||||
Report = require("./Report"),
|
||||
Utils = require("./Utils");
|
||||
|
||||
var shouldSkipValidate = function (options, errors) {
|
||||
return options &&
|
||||
Array.isArray(options.includeErrors) &&
|
||||
options.includeErrors.length > 0 &&
|
||||
!errors.some(function (err) { return options.includeErrors.includes(err);});
|
||||
};
|
||||
|
||||
var JsonValidators = {
|
||||
multipleOf: function (report, schema, json) {
|
||||
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.1.1.2
|
||||
if (shouldSkipValidate(this.validateOptions, ["MULTIPLE_OF"])) {
|
||||
return;
|
||||
}
|
||||
if (typeof json !== "number") {
|
||||
return;
|
||||
}
|
||||
|
||||
var stringMultipleOf = String(schema.multipleOf);
|
||||
var scale = Math.pow(10, stringMultipleOf.length - stringMultipleOf.indexOf(".") - 1);
|
||||
if (Utils.whatIs((json * scale) / (schema.multipleOf * scale)) !== "integer") {
|
||||
report.addError("MULTIPLE_OF", [json, schema.multipleOf], null, schema);
|
||||
}
|
||||
},
|
||||
maximum: function (report, schema, json) {
|
||||
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.1.2.2
|
||||
if (shouldSkipValidate(this.validateOptions, ["MAXIMUM", "MAXIMUM_EXCLUSIVE"])) {
|
||||
return;
|
||||
}
|
||||
if (typeof json !== "number") {
|
||||
return;
|
||||
}
|
||||
if (schema.exclusiveMaximum !== true) {
|
||||
if (json > schema.maximum) {
|
||||
report.addError("MAXIMUM", [json, schema.maximum], null, schema);
|
||||
}
|
||||
} else {
|
||||
if (json >= schema.maximum) {
|
||||
report.addError("MAXIMUM_EXCLUSIVE", [json, schema.maximum], null, schema);
|
||||
}
|
||||
}
|
||||
},
|
||||
exclusiveMaximum: function () {
|
||||
// covered in maximum
|
||||
},
|
||||
minimum: function (report, schema, json) {
|
||||
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.1.3.2
|
||||
if (shouldSkipValidate(this.validateOptions, ["MINIMUM", "MINIMUM_EXCLUSIVE"])) {
|
||||
return;
|
||||
}
|
||||
if (typeof json !== "number") {
|
||||
return;
|
||||
}
|
||||
if (schema.exclusiveMinimum !== true) {
|
||||
if (json < schema.minimum) {
|
||||
report.addError("MINIMUM", [json, schema.minimum], null, schema);
|
||||
}
|
||||
} else {
|
||||
if (json <= schema.minimum) {
|
||||
report.addError("MINIMUM_EXCLUSIVE", [json, schema.minimum], null, schema);
|
||||
}
|
||||
}
|
||||
},
|
||||
exclusiveMinimum: function () {
|
||||
// covered in minimum
|
||||
},
|
||||
maxLength: function (report, schema, json) {
|
||||
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.2.1.2
|
||||
if (shouldSkipValidate(this.validateOptions, ["MAX_LENGTH"])) {
|
||||
return;
|
||||
}
|
||||
if (typeof json !== "string") {
|
||||
return;
|
||||
}
|
||||
if (Utils.ucs2decode(json).length > schema.maxLength) {
|
||||
report.addError("MAX_LENGTH", [json.length, schema.maxLength], null, schema);
|
||||
}
|
||||
},
|
||||
minLength: function (report, schema, json) {
|
||||
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.2.2.2
|
||||
if (shouldSkipValidate(this.validateOptions, ["MIN_LENGTH"])) {
|
||||
return;
|
||||
}
|
||||
if (typeof json !== "string") {
|
||||
return;
|
||||
}
|
||||
if (Utils.ucs2decode(json).length < schema.minLength) {
|
||||
report.addError("MIN_LENGTH", [json.length, schema.minLength], null, schema);
|
||||
}
|
||||
},
|
||||
pattern: function (report, schema, json) {
|
||||
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.2.3.2
|
||||
if (shouldSkipValidate(this.validateOptions, ["PATTERN"])) {
|
||||
return;
|
||||
}
|
||||
if (typeof json !== "string") {
|
||||
return;
|
||||
}
|
||||
if (RegExp(schema.pattern).test(json) === false) {
|
||||
report.addError("PATTERN", [schema.pattern, json], null, schema);
|
||||
}
|
||||
},
|
||||
additionalItems: function (report, schema, json) {
|
||||
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.3.1.2
|
||||
if (shouldSkipValidate(this.validateOptions, ["ARRAY_ADDITIONAL_ITEMS"])) {
|
||||
return;
|
||||
}
|
||||
if (!Array.isArray(json)) {
|
||||
return;
|
||||
}
|
||||
// if the value of "additionalItems" is boolean value false and the value of "items" is an array,
|
||||
// the json is valid if its size is less than, or equal to, the size of "items".
|
||||
if (schema.additionalItems === false && Array.isArray(schema.items)) {
|
||||
if (json.length > schema.items.length) {
|
||||
report.addError("ARRAY_ADDITIONAL_ITEMS", null, null, schema);
|
||||
}
|
||||
}
|
||||
},
|
||||
items: function () { /*report, schema, json*/
|
||||
// covered in additionalItems
|
||||
},
|
||||
maxItems: function (report, schema, json) {
|
||||
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.3.2.2
|
||||
if (shouldSkipValidate(this.validateOptions, ["ARRAY_LENGTH_LONG"])) {
|
||||
return;
|
||||
}
|
||||
if (!Array.isArray(json)) {
|
||||
return;
|
||||
}
|
||||
if (json.length > schema.maxItems) {
|
||||
report.addError("ARRAY_LENGTH_LONG", [json.length, schema.maxItems], null, schema);
|
||||
}
|
||||
},
|
||||
minItems: function (report, schema, json) {
|
||||
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.3.3.2
|
||||
if (shouldSkipValidate(this.validateOptions, ["ARRAY_LENGTH_SHORT"])) {
|
||||
return;
|
||||
}
|
||||
if (!Array.isArray(json)) {
|
||||
return;
|
||||
}
|
||||
if (json.length < schema.minItems) {
|
||||
report.addError("ARRAY_LENGTH_SHORT", [json.length, schema.minItems], null, schema);
|
||||
}
|
||||
},
|
||||
uniqueItems: function (report, schema, json) {
|
||||
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.3.4.2
|
||||
if (shouldSkipValidate(this.validateOptions, ["ARRAY_UNIQUE"])) {
|
||||
return;
|
||||
}
|
||||
if (!Array.isArray(json)) {
|
||||
return;
|
||||
}
|
||||
if (schema.uniqueItems === true) {
|
||||
var matches = [];
|
||||
if (Utils.isUniqueArray(json, matches) === false) {
|
||||
report.addError("ARRAY_UNIQUE", matches, null, schema);
|
||||
}
|
||||
}
|
||||
},
|
||||
maxProperties: function (report, schema, json) {
|
||||
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.4.1.2
|
||||
if (shouldSkipValidate(this.validateOptions, ["OBJECT_PROPERTIES_MAXIMUM"])) {
|
||||
return;
|
||||
}
|
||||
if (Utils.whatIs(json) !== "object") {
|
||||
return;
|
||||
}
|
||||
var keysCount = Object.keys(json).length;
|
||||
if (keysCount > schema.maxProperties) {
|
||||
report.addError("OBJECT_PROPERTIES_MAXIMUM", [keysCount, schema.maxProperties], null, schema);
|
||||
}
|
||||
},
|
||||
minProperties: function (report, schema, json) {
|
||||
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.4.2.2
|
||||
if (shouldSkipValidate(this.validateOptions, ["OBJECT_PROPERTIES_MINIMUM"])) {
|
||||
return;
|
||||
}
|
||||
if (Utils.whatIs(json) !== "object") {
|
||||
return;
|
||||
}
|
||||
var keysCount = Object.keys(json).length;
|
||||
if (keysCount < schema.minProperties) {
|
||||
report.addError("OBJECT_PROPERTIES_MINIMUM", [keysCount, schema.minProperties], null, schema);
|
||||
}
|
||||
},
|
||||
required: function (report, schema, json) {
|
||||
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.4.3.2
|
||||
if (shouldSkipValidate(this.validateOptions, ["OBJECT_MISSING_REQUIRED_PROPERTY"])) {
|
||||
return;
|
||||
}
|
||||
if (Utils.whatIs(json) !== "object") {
|
||||
return;
|
||||
}
|
||||
var idx = schema.required.length;
|
||||
while (idx--) {
|
||||
var requiredPropertyName = schema.required[idx];
|
||||
if (json[requiredPropertyName] === undefined) {
|
||||
report.addError("OBJECT_MISSING_REQUIRED_PROPERTY", [requiredPropertyName], null, schema);
|
||||
}
|
||||
}
|
||||
},
|
||||
additionalProperties: function (report, schema, json) {
|
||||
// covered in properties and patternProperties
|
||||
if (schema.properties === undefined && schema.patternProperties === undefined) {
|
||||
return JsonValidators.properties.call(this, report, schema, json);
|
||||
}
|
||||
},
|
||||
patternProperties: function (report, schema, json) {
|
||||
// covered in properties
|
||||
if (schema.properties === undefined) {
|
||||
return JsonValidators.properties.call(this, report, schema, json);
|
||||
}
|
||||
},
|
||||
properties: function (report, schema, json) {
|
||||
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.4.4.2
|
||||
if (shouldSkipValidate(this.validateOptions, ["OBJECT_ADDITIONAL_PROPERTIES"])) {
|
||||
return;
|
||||
}
|
||||
if (Utils.whatIs(json) !== "object") {
|
||||
return;
|
||||
}
|
||||
var properties = schema.properties !== undefined ? schema.properties : {};
|
||||
var patternProperties = schema.patternProperties !== undefined ? schema.patternProperties : {};
|
||||
if (schema.additionalProperties === false) {
|
||||
// The property set of the json to validate.
|
||||
var s = Object.keys(json);
|
||||
// The property set from "properties".
|
||||
var p = Object.keys(properties);
|
||||
// The property set from "patternProperties".
|
||||
var pp = Object.keys(patternProperties);
|
||||
// remove from "s" all elements of "p", if any;
|
||||
s = Utils.difference(s, p);
|
||||
// for each regex in "pp", remove all elements of "s" which this regex matches.
|
||||
var idx = pp.length;
|
||||
while (idx--) {
|
||||
var regExp = RegExp(pp[idx]),
|
||||
idx2 = s.length;
|
||||
while (idx2--) {
|
||||
if (regExp.test(s[idx2]) === true) {
|
||||
s.splice(idx2, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Validation of the json succeeds if, after these two steps, set "s" is empty.
|
||||
if (s.length > 0) {
|
||||
// assumeAdditional can be an array of allowed properties
|
||||
var idx3 = this.options.assumeAdditional.length;
|
||||
if (idx3) {
|
||||
while (idx3--) {
|
||||
var io = s.indexOf(this.options.assumeAdditional[idx3]);
|
||||
if (io !== -1) {
|
||||
s.splice(io, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
var idx4 = s.length;
|
||||
if (idx4) {
|
||||
while (idx4--) {
|
||||
report.addError("OBJECT_ADDITIONAL_PROPERTIES", [s[idx4]], null, schema);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
dependencies: function (report, schema, json) {
|
||||
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.4.5.2
|
||||
if (shouldSkipValidate(this.validateOptions, ["OBJECT_DEPENDENCY_KEY"])) {
|
||||
return;
|
||||
}
|
||||
if (Utils.whatIs(json) !== "object") {
|
||||
return;
|
||||
}
|
||||
|
||||
var keys = Object.keys(schema.dependencies),
|
||||
idx = keys.length;
|
||||
|
||||
while (idx--) {
|
||||
// iterate all dependencies
|
||||
var dependencyName = keys[idx];
|
||||
if (json[dependencyName]) {
|
||||
var dependencyDefinition = schema.dependencies[dependencyName];
|
||||
if (Utils.whatIs(dependencyDefinition) === "object") {
|
||||
// if dependency is a schema, validate against this schema
|
||||
exports.validate.call(this, report, dependencyDefinition, json);
|
||||
} else { // Array
|
||||
// if dependency is an array, object needs to have all properties in this array
|
||||
var idx2 = dependencyDefinition.length;
|
||||
while (idx2--) {
|
||||
var requiredPropertyName = dependencyDefinition[idx2];
|
||||
if (json[requiredPropertyName] === undefined) {
|
||||
report.addError("OBJECT_DEPENDENCY_KEY", [requiredPropertyName, dependencyName], null, schema);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
enum: function (report, schema, json) {
|
||||
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.5.1.2
|
||||
if (shouldSkipValidate(this.validateOptions, ["ENUM_CASE_MISMATCH", "ENUM_MISMATCH"])) {
|
||||
return;
|
||||
}
|
||||
var match = false,
|
||||
caseInsensitiveMatch = false,
|
||||
idx = schema.enum.length;
|
||||
while (idx--) {
|
||||
if (Utils.areEqual(json, schema.enum[idx])) {
|
||||
match = true;
|
||||
break;
|
||||
} else if (Utils.areEqual(json, schema.enum[idx]), { caseInsensitiveComparison: true }) {
|
||||
caseInsensitiveMatch = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (match === false) {
|
||||
var error = caseInsensitiveMatch && this.options.enumCaseInsensitiveComparison ? "ENUM_CASE_MISMATCH" : "ENUM_MISMATCH";
|
||||
report.addError(error, [json], null, schema);
|
||||
}
|
||||
},
|
||||
type: function (report, schema, json) {
|
||||
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.5.2.2
|
||||
if (shouldSkipValidate(this.validateOptions, ["INVALID_TYPE"])) {
|
||||
return;
|
||||
}
|
||||
var jsonType = Utils.whatIs(json);
|
||||
if (typeof schema.type === "string") {
|
||||
if (jsonType !== schema.type && (jsonType !== "integer" || schema.type !== "number")) {
|
||||
report.addError("INVALID_TYPE", [schema.type, jsonType], null, schema);
|
||||
}
|
||||
} else {
|
||||
if (schema.type.indexOf(jsonType) === -1 && (jsonType !== "integer" || schema.type.indexOf("number") === -1)) {
|
||||
report.addError("INVALID_TYPE", [schema.type, jsonType], null, schema);
|
||||
}
|
||||
}
|
||||
},
|
||||
allOf: function (report, schema, json) {
|
||||
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.5.3.2
|
||||
var idx = schema.allOf.length;
|
||||
while (idx--) {
|
||||
var validateResult = exports.validate.call(this, report, schema.allOf[idx], json);
|
||||
if (this.options.breakOnFirstError && validateResult === false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
anyOf: function (report, schema, json) {
|
||||
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.5.4.2
|
||||
var subReports = [],
|
||||
passed = false,
|
||||
idx = schema.anyOf.length;
|
||||
|
||||
while (idx-- && passed === false) {
|
||||
var subReport = new Report(report);
|
||||
subReports.push(subReport);
|
||||
passed = exports.validate.call(this, subReport, schema.anyOf[idx], json);
|
||||
}
|
||||
|
||||
if (passed === false) {
|
||||
report.addError("ANY_OF_MISSING", undefined, subReports, schema);
|
||||
}
|
||||
},
|
||||
oneOf: function (report, schema, json) {
|
||||
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.5.5.2
|
||||
var passes = 0,
|
||||
subReports = [],
|
||||
idx = schema.oneOf.length;
|
||||
|
||||
while (idx--) {
|
||||
var subReport = new Report(report, { maxErrors: 1 });
|
||||
subReports.push(subReport);
|
||||
if (exports.validate.call(this, subReport, schema.oneOf[idx], json) === true) {
|
||||
passes++;
|
||||
}
|
||||
}
|
||||
|
||||
if (passes === 0) {
|
||||
report.addError("ONE_OF_MISSING", undefined, subReports, schema);
|
||||
} else if (passes > 1) {
|
||||
report.addError("ONE_OF_MULTIPLE", null, null, schema);
|
||||
}
|
||||
},
|
||||
not: function (report, schema, json) {
|
||||
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.5.6.2
|
||||
var subReport = new Report(report);
|
||||
if (exports.validate.call(this, subReport, schema.not, json) === true) {
|
||||
report.addError("NOT_PASSED", null, null, schema);
|
||||
}
|
||||
},
|
||||
definitions: function () { /*report, schema, json*/
|
||||
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.5.7.2
|
||||
// nothing to do here
|
||||
},
|
||||
format: function (report, schema, json) {
|
||||
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.7.2
|
||||
var formatValidatorFn = FormatValidators[schema.format];
|
||||
if (typeof formatValidatorFn === "function") {
|
||||
if (shouldSkipValidate(this.validateOptions, ["INVALID_FORMAT"])) {
|
||||
return;
|
||||
}
|
||||
if (formatValidatorFn.length === 2) {
|
||||
// async - need to clone the path here, because it will change by the time async function reports back
|
||||
var pathBeforeAsync = Utils.clone(report.path);
|
||||
report.addAsyncTask(formatValidatorFn, [json], function (result) {
|
||||
if (result !== true) {
|
||||
var backup = report.path;
|
||||
report.path = pathBeforeAsync;
|
||||
report.addError("INVALID_FORMAT", [schema.format, json], null, schema);
|
||||
report.path = backup;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// sync
|
||||
if (formatValidatorFn.call(this, json) !== true) {
|
||||
report.addError("INVALID_FORMAT", [schema.format, json], null, schema);
|
||||
}
|
||||
}
|
||||
} else if (this.options.ignoreUnknownFormats !== true) {
|
||||
report.addError("UNKNOWN_FORMAT", [schema.format], null, schema);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var recurseArray = function (report, schema, json) {
|
||||
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.8.2
|
||||
|
||||
var idx = json.length;
|
||||
|
||||
// If "items" is an array, this situation, the schema depends on the index:
|
||||
// if the index is less than, or equal to, the size of "items",
|
||||
// the child instance must be valid against the corresponding schema in the "items" array;
|
||||
// otherwise, it must be valid against the schema defined by "additionalItems".
|
||||
if (Array.isArray(schema.items)) {
|
||||
|
||||
while (idx--) {
|
||||
// equal to doesn't make sense here
|
||||
if (idx < schema.items.length) {
|
||||
report.path.push(idx);
|
||||
exports.validate.call(this, report, schema.items[idx], json[idx]);
|
||||
report.path.pop();
|
||||
} else {
|
||||
// might be boolean, so check that it's an object
|
||||
if (typeof schema.additionalItems === "object") {
|
||||
report.path.push(idx);
|
||||
exports.validate.call(this, report, schema.additionalItems, json[idx]);
|
||||
report.path.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (typeof schema.items === "object") {
|
||||
|
||||
// If items is a schema, then the child instance must be valid against this schema,
|
||||
// regardless of its index, and regardless of the value of "additionalItems".
|
||||
while (idx--) {
|
||||
report.path.push(idx);
|
||||
exports.validate.call(this, report, schema.items, json[idx]);
|
||||
report.path.pop();
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
var recurseObject = function (report, schema, json) {
|
||||
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.8.3
|
||||
|
||||
// If "additionalProperties" is absent, it is considered present with an empty schema as a value.
|
||||
// In addition, boolean value true is considered equivalent to an empty schema.
|
||||
var additionalProperties = schema.additionalProperties;
|
||||
if (additionalProperties === true || additionalProperties === undefined) {
|
||||
additionalProperties = {};
|
||||
}
|
||||
|
||||
// p - The property set from "properties".
|
||||
var p = schema.properties ? Object.keys(schema.properties) : [];
|
||||
|
||||
// pp - The property set from "patternProperties". Elements of this set will be called regexes for convenience.
|
||||
var pp = schema.patternProperties ? Object.keys(schema.patternProperties) : [];
|
||||
|
||||
// m - The property name of the child.
|
||||
var keys = Object.keys(json),
|
||||
idx = keys.length;
|
||||
|
||||
while (idx--) {
|
||||
var m = keys[idx],
|
||||
propertyValue = json[m];
|
||||
|
||||
// s - The set of schemas for the child instance.
|
||||
var s = [];
|
||||
|
||||
// 1. If set "p" contains value "m", then the corresponding schema in "properties" is added to "s".
|
||||
if (p.indexOf(m) !== -1) {
|
||||
s.push(schema.properties[m]);
|
||||
}
|
||||
|
||||
// 2. For each regex in "pp", if it matches "m" successfully, the corresponding schema in "patternProperties" is added to "s".
|
||||
var idx2 = pp.length;
|
||||
while (idx2--) {
|
||||
var regexString = pp[idx2];
|
||||
if (RegExp(regexString).test(m) === true) {
|
||||
s.push(schema.patternProperties[regexString]);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. The schema defined by "additionalProperties" is added to "s" if and only if, at this stage, "s" is empty.
|
||||
if (s.length === 0 && additionalProperties !== false) {
|
||||
s.push(additionalProperties);
|
||||
}
|
||||
|
||||
// we are passing tests even without this assert because this is covered by properties check
|
||||
// if s is empty in this stage, no additionalProperties are allowed
|
||||
// report.expect(s.length !== 0, 'E001', m);
|
||||
|
||||
// Instance property value must pass all schemas from s
|
||||
idx2 = s.length;
|
||||
while (idx2--) {
|
||||
report.path.push(m);
|
||||
exports.validate.call(this, report, s[idx2], propertyValue);
|
||||
report.path.pop();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.JsonValidators = JsonValidators;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Report} report
|
||||
* @param {*} schema
|
||||
* @param {*} json
|
||||
*/
|
||||
exports.validate = function (report, schema, json) {
|
||||
|
||||
report.commonErrorMessage = "JSON_OBJECT_VALIDATION_FAILED";
|
||||
|
||||
// check if schema is an object
|
||||
var to = Utils.whatIs(schema);
|
||||
if (to !== "object") {
|
||||
report.addError("SCHEMA_NOT_AN_OBJECT", [to], null, schema);
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if schema is empty, everything is valid against empty schema
|
||||
var keys = Object.keys(schema);
|
||||
if (keys.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// this method can be called recursively, so we need to remember our root
|
||||
var isRoot = false;
|
||||
if (!report.rootSchema) {
|
||||
report.rootSchema = schema;
|
||||
isRoot = true;
|
||||
}
|
||||
|
||||
// follow schema.$ref keys
|
||||
if (schema.$ref !== undefined) {
|
||||
// avoid infinite loop with maxRefs
|
||||
var maxRefs = 99;
|
||||
while (schema.$ref && maxRefs > 0) {
|
||||
if (!schema.__$refResolved) {
|
||||
report.addError("REF_UNRESOLVED", [schema.$ref], null, schema);
|
||||
break;
|
||||
} else if (schema.__$refResolved === schema) {
|
||||
break;
|
||||
} else {
|
||||
schema = schema.__$refResolved;
|
||||
keys = Object.keys(schema);
|
||||
}
|
||||
maxRefs--;
|
||||
}
|
||||
if (maxRefs === 0) {
|
||||
throw new Error("Circular dependency by $ref references!");
|
||||
}
|
||||
}
|
||||
|
||||
// type checking first
|
||||
var jsonType = Utils.whatIs(json);
|
||||
if (schema.type) {
|
||||
keys.splice(keys.indexOf("type"), 1);
|
||||
JsonValidators.type.call(this, report, schema, json);
|
||||
if (report.errors.length && this.options.breakOnFirstError) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// now iterate all the keys in schema and execute validation methods
|
||||
var idx = keys.length;
|
||||
while (idx--) {
|
||||
if (JsonValidators[keys[idx]]) {
|
||||
JsonValidators[keys[idx]].call(this, report, schema, json);
|
||||
if (report.errors.length && this.options.breakOnFirstError) { break; }
|
||||
}
|
||||
}
|
||||
|
||||
if (report.errors.length === 0 || this.options.breakOnFirstError === false) {
|
||||
if (jsonType === "array") {
|
||||
recurseArray.call(this, report, schema, json);
|
||||
} else if (jsonType === "object") {
|
||||
recurseObject.call(this, report, schema, json);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof this.options.customValidator === "function") {
|
||||
this.options.customValidator.call(this, report, schema, json);
|
||||
}
|
||||
|
||||
// we don't need the root pointer anymore
|
||||
if (isRoot) {
|
||||
report.rootSchema = undefined;
|
||||
}
|
||||
|
||||
// return valid just to be able to break at some code points
|
||||
return report.errors.length === 0;
|
||||
|
||||
};
|
Reference in New Issue
Block a user