dependencies rule

master
Evgeny Poberezkin 2015-05-29 15:58:02 +01:00
parent 4a7a586bac
commit c4816e4836
5 changed files with 143 additions and 228 deletions

View File

@ -21,6 +21,7 @@ function compile(schema) {
_validate: _validateTemplate,
copy: copy,
getDataType: getDataType,
escapeQuotes: escapeQuotes,
stableStringify: stableStringify,
opts: this.opts
});
@ -53,3 +54,7 @@ function copy(o, to) {
return to;
}
function escapeQuotes(str) {
return str.replace(/"/g, '\\"');
}

View File

@ -0,0 +1,65 @@
function (data, dataType, dataPath) {
'use strict';
var errors = [];
{{
var $schemaDeps = {}
, $propertyDeps = {};
for ($property in it.schema) {
var $schema = it.schema[$property];
var $deps = Array.isArray($schema) ? $propertyDeps : $schemaDeps;
$deps[$property] = $schema;
}
}}
{{ for ($property in $propertyDeps) { }}
if (data.hasOwnProperty('{{= $property }}')) {
{{ $deps = $propertyDeps[$property]; }}
var valid = {{~ $deps:$dep:$i }}{{?$i}} && {{?}}data.hasOwnProperty('{{= $dep}}'){{~}};
if (!valid) {
var error = {
keyword: 'dependencies',
schema: self.schema{{= it.schemaPath }},
dataPath: dataPath,
message: 'data' + dataPath + ' is not valid, {{? $deps.length == 1 }}property {{= $deps[0] }} is{{??}}properties {{= $deps.join(",") }} are{{?}} required when property {{= $property }} is present'
{{? it.opts.verbose }}, data: data{{?}}
};
{{? it.opts.allErrors }}
errors.push(error);
{{??}}
return { valid: false, errors: [error] };
{{?}}
}
}
{{ } }}
{{ for ($property in $schemaDeps) { }}
if (data.hasOwnProperty('{{= $property }}')) {
{{
var $schema = $schemaDeps[$property];
var $it = it.copy(it);
$it.schema = $schema;
$it.schemaPath = it.schemaPath + '["' + it.escapeQuotes($property) + '"]';
}}
var result = ({{= it._validate($it) }})(data, dataType, dataPath);
if (!result.valid) {
{{? it.opts.allErrors }}
errors.push.apply(errors, result.errors);
{{??}}
return { valid: false, errors: result.errors };
{{?}}
}
}
{{ } }}
{{? it.opts.allErrors }}
return { valid: !errors.length, errors: errors };
{{??}}
return { valid: true, errors: [] };
{{?}}
}

View File

@ -66,10 +66,10 @@ var RULES = module.exports = {
code: fs.readFileSync(__dirname + '/properties.dot.js'),
type: 'object'
},
// dependencies: {
// code: '',
// type: 'object'
// }
dependencies: {
code: fs.readFileSync(__dirname + '/dependencies.dot.js'),
type: 'object'
}
};

View File

@ -7,14 +7,15 @@ var fs = require('fs')
var ONLY_RULES;
// ONLY_RULES = ['enum'];
ONLY_RULES = [
'type', 'not', 'allOf', 'anyOf', 'oneOf', 'enum',
'maximum', 'minimum', 'multipleOf',
'maxLength', 'minLength', 'pattern',
'properties', 'patternProperties', 'additionalProperties',
'required', 'maxProperties', 'minProperties',
'maxItems', 'minItems', 'items', 'additionalItems', 'uniqueItems'
];
// ONLY_RULES = [
// 'type', 'not', 'allOf', 'anyOf', 'oneOf', 'enum',
// 'maximum', 'minimum', 'multipleOf',
// 'maxLength', 'minLength', 'pattern',
// 'properties', 'patternProperties', 'additionalProperties',
// 'dependencies',
// 'required', 'maxProperties', 'minProperties',
// 'maxItems', 'minItems', 'items', 'additionalItems', 'uniqueItems'
// ];
var Jv = require('../lib/jv')
@ -30,14 +31,14 @@ describe.only('JSON-Schema tests', function () {
describe(file.name, function() {
var testSets = require(file.path);
testSets.forEach(function (testSet) {
// if (testSet.description != 'additionalProperties can exist by itself') return;
// if (testSet.description != 'multiple dependencies') return;
describe(testSet.description, function() {
// it(testSet.description, function() {
var validate = jv.compile(testSet.schema);
var fullValidate = fullJv.compile(testSet.schema);
testSet.tests.forEach(function (test) {
// if (test.description != 'a single invalid match is invalid') return;
// if (test.description != 'missing dependency') return;
it(test.description, function() {
var result = validate(test.data);
// console.log('result', result);

272
try.js
View File

@ -1,215 +1,59 @@
'use strict';
validate = function(data, instance) {
var self = this;
var dataType = getDataType(data);
var result = (function(data, dataType, dataPath) {
'use strict';
var errors = [];
var rule = RULES.properties;
if (!rule.type || rule.type == dataType) {
var result = (function(data, dataType, dataPath) {
'use strict';
var errors = [];
var propertiesSchema = self.schema.properties;
var pPropertiesSchema = self.schema.patternProperties,
pPropertiesRegexps = {},
dataKeysPPs;
for (var pProperty in pPropertiesSchema) pPropertiesRegexps[pProperty] = new RegExp(pProperty);
dataKeysPPs = {};
for (var key in data) {
var isAdditional = !propertiesSchema.hasOwnProperty(key);
dataKeysPPs[key] = {};
for (var pProperty in pPropertiesSchema) {
var keyMatches = pPropertiesRegexps[pProperty].test(key);
if (keyMatches) {
dataKeysPPs[key][pProperty] = true;
isAdditional = false;
}
}
if (isAdditional) {
var _data = data[key],
_dataType = getDataType(_data),
_dataPath = dataPath + '.' + key,
result = (function(data, dataType, dataPath) {
'use strict';
var errors = [];
var rule = RULES.type;
if (!rule.type || rule.type == dataType) {
var result = (function(data, dataType, dataPath) {
'use strict';
var valid;
valid = dataType == 'number' && data === parseInt(data);
return {
valid: valid,
errors: valid ? [] : [{
keyword: 'type',
schema: 'integer',
dataPath: dataPath,
message: 'data' + dataPath + ' is not valid. Expected integer',
data: data
}]
};
})(data, dataType, dataPath);
if (!result.valid) {
errors.push.apply(errors, result.errors);
}
}
return {
valid: !errors.length,
errors: errors
};
})(_data, _dataType, _dataPath);
if (!result.valid) {
errors.push.apply(errors, result.errors);
}
}
}
if (data.hasOwnProperty('foo')) {
var _data = data['foo'],
_dataType = getDataType(_data),
_dataPath = dataPath + '.foo',
result = (function(data, dataType, dataPath) {
'use strict';
var errors = [];
var rule = RULES.type;
if (!rule.type || rule.type == dataType) {
var result = (function(data, dataType, dataPath) {
'use strict';
var valid;
valid = dataType == 'array';
return {
valid: valid,
errors: valid ? [] : [{
keyword: 'type',
schema: 'array',
dataPath: dataPath,
message: 'data' + dataPath + ' is not valid. Expected array',
data: data
}]
};
})(data, dataType, dataPath);
if (!result.valid) {
errors.push.apply(errors, result.errors);
}
}
var rule = RULES.maxItems;
if (!rule.type || rule.type == dataType) {
var result = (function(data, dataType, dataPath) {
'use strict';
var valid = data.length <= 3;
return {
valid: valid,
errors: valid ? [] : [{
keyword: 'maxItems',
schema: 3,
dataPath: dataPath,
message: 'data' + dataPath + ' is not valid, should NOT have more than 3 items',
data: data
}]
};
})(data, dataType, dataPath);
if (!result.valid) {
errors.push.apply(errors, result.errors);
}
}
return {
valid: !errors.length,
errors: errors
};
})(_data, _dataType, _dataPath);
if (!result.valid) {
errors.push.apply(errors, result.errors);
}
}
if (data.hasOwnProperty('bar')) {
var _data = data['bar'],
_dataType = getDataType(_data),
_dataPath = dataPath + '.bar',
result = (function(data, dataType, dataPath) {
'use strict';
var errors = [];
var rule = RULES.type;
if (!rule.type || rule.type == dataType) {
var result = (function(data, dataType, dataPath) {
'use strict';
var valid;
valid = dataType == 'array';
return {
valid: valid,
errors: valid ? [] : [{
keyword: 'type',
schema: 'array',
dataPath: dataPath,
message: 'data' + dataPath + ' is not valid. Expected array',
data: data
}]
};
})(data, dataType, dataPath);
if (!result.valid) {
errors.push.apply(errors, result.errors);
}
}
return {
valid: !errors.length,
errors: errors
};
})(_data, _dataType, _dataPath);
if (!result.valid) {
errors.push.apply(errors, result.errors);
}
}
for (var key in data) {
var keyMatches = dataKeysPPs[key]['f.o'];
if (keyMatches) {
var _data = data['f.o'],
_dataType = getDataType(_data),
_dataPath = dataPath + '.f.o',
result = (function(data, dataType, dataPath) {
'use strict';
var errors = [];
var rule = RULES.minItems;
if (!rule.type || rule.type == dataType) {
var result = (function(data, dataType, dataPath) {
'use strict';
var valid = data.length >= 2;
return {
valid: valid,
errors: valid ? [] : [{
keyword: 'minItems',
schema: 2,
dataPath: dataPath,
message: 'data' + dataPath + ' is not valid, should NOT have less than 2 items',
data: data
}]
};
})(data, dataType, dataPath);
if (!result.valid) {
errors.push.apply(errors, result.errors);
}
}
return {
valid: !errors.length,
errors: errors
};
})(_data, _dataType, _dataPath);
if (!result.valid) {
errors.push.apply(errors, result.errors);
}
}
}
return {
valid: !errors.length,
errors: errors
};
})(data, dataType, dataPath);
if (!result.valid) {
errors.push.apply(errors, result.errors);
}
}
return {
valid: !errors.length,
errors: errors
};
})(data, dataType, '');
return result;
var out = 'function (data, dataType, dataPath) { \'use strict\'; var errors = []; ';
var $schemaDeps = {},
$propertyDeps = {};
for ($property in it.schema) {
var $schema = it.schema[$property];
var $deps = Array.isArray($schema) ? $propertyDeps : $schemaDeps;
$deps[$property] = $schema;
}
out += ' ';
for ($property in $propertyDeps) {
out += ' if (data.hasOwnProperty(\'' + ($property) + '\')) { ';
$deps = $propertyDeps[$property] out += ' var valid = ';
var arr1 = $deps;
if (arr1) {
var $dep, $i = -1,
l1 = arr1.length - 1;
while ($i < l1) {
$dep = arr1[$i += 1];
if ($i) {
out += ' || ';
}
out += 'data.hasOwnProperty(\'' + ($dep) + '\')';
}
}
out += '; if (!valid) { var error = { keyword: \'dependencies\', schema: self.schema' + (it.schemaPath) + ', dataPath: dataPath, message: \'data\' + dataPath + \' is not valid, properties ' + ($deps.join(",")) + ' are required when property ' + ($property) + ' is present\' ';
if (it.opts.verbose) {
out += ', data: data';
}
out += ' } ';
if (it.opts.allErrors) {
out += ' errors.push(error); ';
} else {
out += ' return { valid: false, errors: [error] }; ';
}
out += ' } } ';
}
out += ' ';
for ($property in $schemaDeps) {
out += ' if (data.hasOwnProperty(\'' + ($property) + '\')) { ';
var $schema = $schemaDeps[$property];
var $it = it.copy(it);
$it.schema = $schema;
$it.schemaPath = it.schemaPath + '["' + it.escapeQuotes($property) + '"]';
out += ' var result = (' + (it._validate($it)) + ')(data, dataType, dataPath); if (!result.valid) { ';
if (it.opts.allErrors) {
out += ' errors.push.apply(errors, result.errors); ';
} else {
out += ' return { valid: false, errors: result.errors }; ';
}
out += ' } } ';
}
out += ' ';
if (it.opts.allErrors) {
out += ' return { valid: !errors.length, errors: errors }; ';
} else {
out += ' return { valid: true, errors: [] }; ';
}
out += '}';
return out;