refactor with defs; use numbered variable names in different levels

master
Evgeny Poberezkin 2015-06-03 01:36:59 +01:00
parent 4a54f9bb73
commit 34a98e273a
30 changed files with 458 additions and 472 deletions

View File

@ -64,34 +64,36 @@ function copy(o, to) {
}
function checkDataType(dataType) {
function checkDataType(dataType, lvl) {
var data = 'data' + lvl;
switch (dataType) {
case 'null': return 'data === null';
case 'array': return 'Array.isArray(data)';
case 'object': return '(data && typeof data == "object" && !Array.isArray(data))';
case 'integer': return '(typeof data == "number" && !(data % 1))'
default: return 'typeof data == "' + dataType + '"';
case 'null': return data + ' === null';
case 'array': return 'Array.isArray(' + data + ')';
case 'object': return '(' + data + ' && typeof ' + data + ' == "object" && !Array.isArray(' + data + '))';
case 'integer': return '(typeof ' + data + ' == "number" && !(' + data + ' % 1))'
default: return 'typeof ' + data + ' == "' + dataType + '"';
}
}
function checkDataTypes(dataTypes) {
function checkDataTypes(dataTypes, lvl) {
var data = 'data' + lvl;
switch (dataTypes.length) {
case 0: return 'true';
case 1: return checkDataType(dataTypes[0]);
case 1: return checkDataType(dataTypes[0], lvl);
default:
var code = ''
var types = toHash(dataTypes);
if (types.array && types.object) {
code = types.null ? '(': '(data && '
code += 'typeof data == "object")';
code = types.null ? '(': '(' + data + ' && '
code += 'typeof ' + data + ' == "object")';
delete types.null;
delete types.array;
delete types.object;
}
if (types.number) delete types.integer;
for (var t in types)
code += (code ? '||' : '' ) + checkDataType(t);
code += (code ? '||' : '' ) + checkDataType(t, lvl);
return code;
}

View File

@ -1,13 +1,11 @@
{{? it.resolveRef(it.schema.$ref) }}
var result = validateRef('{{= it.schema.$ref }}', data, dataPath);
if (!result.valid) validate.errors.push.apply(validate.errors, result.errors);
var valid = result.valid;
{{# def.definitions }}
{{# def.setup:'$ref' }}
{{? it.resolveRef($schema) }}
var result{{=$lvl}} = validateRef('{{=$schema}}', data{{=$dataLvl}}, dataPath{{=$dataLvl}});
valid = result{{=$lvl}}.valid;
if (!valid) validate.errors.push.apply(validate.errors, result{{=$lvl}}.errors);
{{??}}
validate.errors.push({
keyword: '$ref',
dataPath: dataPath,
message: 'can\'t resolve reference {{= it.schema.$ref}}'
{{? it.opts.verbose }}, schema: '{{= it.schema.$ref }}', data: data{{?}}
});
var valid = false;
{{# def.error:'$ref' }}
valid = false;
{{?}}

View File

@ -1,24 +1,18 @@
{{# def.definitions }}
{{# def.setup:'allOf' }}
{{# def.setupNextLevel }}
var valid = true;
{{
var $it = it.copy(it)
, $closingBraces = ''
, $level = it.level;
$it.level++;
}}
{{~ it.schema.allOf:$schema:$i }}
{{? !it.opts.allErrors && $i }}
{{ $closingBraces += '}'; }}
if (valid) {
{{?}}
{{~ $schema:$sch:$i }}
{{? $i}} {{# def.ifValid }} {{?}}
{{
$it.schema = $schema;
$it.schemaPath = it.schemaPath + '.allOf[' + $i + ']';
$it.schema = $sch;
$it.schemaPath = $schemaPath + '[' + $i + ']';
}}
valid = valid && ({{= it.validate($it) }})(data, dataPath);
valid = valid && ({{= it.validate($it) }})(data{{=$dataLvl}}, dataPath{{=$dataLvl}});
{{~}}
{{= $closingBraces }}

View File

@ -1,27 +1,24 @@
{{
var $it = it.copy(it)
, $closingBraces = ''
, $level = it.level;
$it.level++;
}}
{{# def.definitions }}
{{# def.setup:'anyOf' }}
{{# def.setupNextLevel }}
var errs{{= $level}} = validate.errors.length;
var errs{{=$lvl}} = validate.errors.length;
var valid = false;
{{~ it.schema.anyOf:$schema:$i }}
{{~ $schema:$sch:$i }}
{{? $i }}
{{ $closingBraces += '}'; }}
if (!valid) {
{{?}}
{{
$it.schema = $schema;
$it.schemaPath = it.schemaPath + '.anyOf[' + $i + ']';
$it.schema = $sch;
$it.schemaPath = $schemaPath + '[' + $i + ']';
}}
valid = valid || ({{= it.validate($it) }})(data, dataPath);
valid = valid || ({{= it.validate($it) }})(data{{=$dataLvl}}, dataPath{{=$dataLvl}});
{{~}}
{{= $closingBraces }}
if (valid) validate.errors.length = errs{{= $level}};
if (valid) validate.errors.length = errs{{=$lvl}};

View File

@ -0,0 +1,104 @@
{{## def.setup:keyword:
{{
var $lvl = it.level
, $dataLvl = it.dataLevel
, $schema = it.schema[keyword]
, $schemaPath = it.schemaPath + '.' + keyword;
}}
#}}
{{## def.setupNextLevel:
{{
var $it = it.copy(it)
, $closingBraces = ''
, $breakOnError = !it.opts.allErrors;
$it.level++;
}}
#}}
{{## def.ifValid:
{{? $breakOnError }}
if (valid) {
{{ $closingBraces += '}'; }}
{{?}}
#}}
{{## def.elseIfValid:
{{? $breakOnError }}
{{ $closingBraces += '}'; }}
else {
{{?}}
#}}
{{## def.cleanUp:
{{ out = out.replace(/if \(valid\) \{\s*\}/g, ''); }}
#}}
{{## def.error:keyword:
validate.errors.push({
keyword: '{{=keyword}}',
dataPath: dataPath{{=$dataLvl}},
message: {{# def._errorMessages[keyword] }}
{{? it.opts.verbose }}, schema: {{# def._errorSchemas[keyword] }}, data: data{{=$dataLvl}}{{?}}
});
#}}
{{## def.checkError:keyword:
if (!valid) {{# def.error:keyword }}
#}}
{{## def._errorMessages = {
$ref: "'can\\\'t resolve reference {{=$schema}}'",
additionalItems: "'should NOT have more than {{=$schema.length}} items'",
additionalProperties: "'additional properties NOT allowed'",
dependencies: "'{{? $deps.length == 1 }}property {{= $deps[0] }} is{{??}}properties {{= $deps.join(\", \") }} are{{?}} required when property {{= $property }} is present'",
enum: "'should be equal to one of values'",
format: "'should match format {{=$schema}}'",
maximum: "'should be {{=$op}} {{=$schema}}'",
minimum: "'should be {{=$op}} {{=$schema}}'",
maxItems: "'should NOT have more than {{=$schema}} items'",
minItems: "'should NOT have less than {{=$schema}} items'",
maxLength: "'should NOT be longer than {{=$schema}} characters'",
minLength: "'should NOT be shorter than {{=$schema}} characters'",
maxProperties: "'should NOT have more than {{=$schema}} properties'",
minProperties: "'should NOT have less than {{=$schema}} properties'",
multipleOf: "'should be multiple of {{=$schema}}'",
not: "'should NOT be valid'",
oneOf: "'should match exactly one schema in oneOf'",
pattern: "'should match pattern \"{{=$schema}}\"'",
required: "'properties {{=$schema.slice(0,7).join(\", \") }}{{? $schema.length > 7}}...{{?}} are required'",
type: "'should be {{? $isArray }}{{= $schema.join(\",\") }}{{??}}{{=$schema}}{{?}}'",
uniqueItems: "'items ## ' + j{{=$lvl}} + ' and ' + i{{=$lvl}} + ' are duplicate'"
} #}}
{{## def._errorSchemas = {
$ref: "'{{=$schema}}'",
additionalItems: "false",
additionalProperties: "false",
dependencies: "validate.schema{{=$schemaPath}}",
enum: "validate.schema{{=$schemaPath}}",
format: "'{{=$schema}}'",
maximum: "{{=$schema}}",
minimum: "{{=$schema}}",
maxItems: "{{=$schema}}",
minItems: "{{=$schema}}",
maxLength: "{{=$schema}}",
minLength: "{{=$schema}}",
maxProperties: "{{=$schema}}",
minProperties: "{{=$schema}}",
multipleOf: "{{=$schema}}",
not: "validate.schema{{=$schemaPath}}",
oneOf: "validate.schema{{=$schemaPath}}",
pattern: "'{{=$schema}}'",
required: "validate.schema{{=$schemaPath}}",
type: "{{? $isArray }}validate.schema{{=$schemaPath}}{{??}}'{{=$schema}}'{{?}}",
uniqueItems: "{{=$schema}}"
} #}}

View File

@ -1,63 +1,48 @@
{{
var $it = it.copy(it)
, $breakOnError = !it.opts.allErrors
, $closingBraces = ''
, $schemaDeps = {}
, $propertyDeps = {}
, $level = it.level;
$it.level++;
{{# def.definitions }}
{{# def.setup:'dependencies' }}
{{# def.setupNextLevel }}
for ($property in it.schema.dependencies) {
var $schema = it.schema.dependencies[$property];
var $deps = Array.isArray($schema) ? $propertyDeps : $schemaDeps;
$deps[$property] = $schema;
{{
var $schemaDeps = {}
, $propertyDeps = {};
for ($property in $schema) {
var $sch = $schema[$property];
var $deps = Array.isArray($sch) ? $propertyDeps : $schemaDeps;
$deps[$property] = $sch;
}
}}
var errs{{= $level}} = validate.errors.length;
var errs{{=$lvl}} = validate.errors.length;
var valid;
{{ for ($property in $propertyDeps) { }}
if (data.hasOwnProperty('{{= $property }}')) {
if (data{{=$dataLvl}}.hasOwnProperty('{{= $property }}')) {
{{ $deps = $propertyDeps[$property]; }}
valid = {{~ $deps:$dep:$i }}{{?$i}} && {{?}}data.hasOwnProperty('{{= $dep}}'){{~}};
if (!valid) {
validate.errors.push({
keyword: 'dependencies',
dataPath: dataPath,
message: '{{? $deps.length == 1 }}property {{= $deps[0] }} is{{??}}properties {{= $deps.join(",") }} are{{?}} required when property {{= $property }} is present'
{{? it.opts.verbose }}, schema: validate.schema{{= it.schemaPath + '.dependencies' }}, data: data{{?}}
});
}
{{? $breakOnError }}
{{ $closingBraces += '}'; }}
else {
{{?}}
valid = {{~ $deps:$dep:$i }}{{?$i}} && {{?}}data{{=$dataLvl}}.hasOwnProperty('{{= $dep}}'){{~}};
{{# def.checkError:'dependencies' }}
{{# def.elseIfValid }}
}
{{ } }}
{{ for ($property in $schemaDeps) { }}
if (data.hasOwnProperty('{{= $property }}')) {
if (data{{=$dataLvl}}.hasOwnProperty('{{= $property }}')) {
{{
var $schema = $schemaDeps[$property];
$it.schema = $schema;
$it.schemaPath = it.schemaPath + '.dependencies["' + it.escapeQuotes($property) + '"]';
$it.schema = $schemaDeps[$property];
$it.schemaPath = $schemaPath + '[\'' + it.escapeQuotes($property) + '\']';
}}
{{? $breakOnError }} valid = {{?}}
({{= it.validate($it) }})(data, dataPath);
valid = ({{= it.validate($it) }})(data{{=$dataLvl}}, dataPath{{=$dataLvl}});
}
{{? $breakOnError }}
{{ $closingBraces += '}'; }}
if (valid) {
{{?}}
{{# def.ifValid }}
{{ } }}
{{? $breakOnError }}{{= $closingBraces }}{{?}}
valid = errs{{= $level}} == validate.errors.length;
valid = errs{{=$lvl}} == validate.errors.length;
{{ out = out.replace(/if \(valid\) \{\s*\}/g, ''); }}
{{# def.cleanUp }}

View File

@ -1,11 +1,11 @@
{{ var $itemsHash = it.toHash(it.schema.enum, it.stableStringify); }}
{{# def.definitions }}
{{# def.setup:'enum' }}
var itemsHash{{= it.level }} = {{= JSON.stringify($itemsHash) }};
var valid = itemsHash{{= it.level }}[stableStringify(data)] || false;
{{
var $itemsHash = it.toHash($schema, it.stableStringify);
}}
if (!valid) validate.errors.push({
keyword: 'enum',
dataPath: dataPath,
message: 'should be equal to one of values'
{{? it.opts.verbose }}, schema: validate.schema{{= it.schemaPath + '.enum' }}, data: data{{?}}
});
var itemsHash{{=$lvl}} = {{= JSON.stringify($itemsHash) }};
var valid = itemsHash{{=$lvl}}[stableStringify(data{{=$dataLvl}})] || false;
{{# def.checkError:'enum' }}

View File

@ -1,16 +1,14 @@
{{? it.opts.format !== false }}
{{ var $format = 'format' + it.level; }}
var {{=$format}} = formats['{{= it.schema.format }}'];
var valid = typeof {{=$format}} == 'function'
? {{=$format}}(data)
: !{{=$format}} || {{=$format}}.test(data);
{{# def.definitions }}
if (!valid) validate.errors.push({
keyword: 'format',
dataPath: dataPath,
message: 'should match format "{{= it.schema.format }}"'
{{? it.opts.verbose }}, schema: '{{= it.schema.format }}', data: data{{?}}
});
{{? it.opts.format !== false }}
{{# def.setup:'format' }}
var format{{=$lvl}} = formats['{{=$schema}}'];
var valid = typeof format{{=$lvl}} == 'function'
? format{{=$lvl}}(data{{=$dataLvl}})
: !format{{=$lvl}} || format{{=$lvl}}.test(data{{=$dataLvl}});
{{# def.checkError:'format' }}
{{??}}
var valid = true;
{{?}}

View File

@ -3,6 +3,7 @@
var fs = require('fs')
, doT = require('dot');
var defs = fs.readFileSync(__dirname + '/definitions.def.js');
var RULES = module.exports = [
{ type: 'number',
@ -22,7 +23,7 @@ RULES.forEach(function (group) {
var template = fs.readFileSync(__dirname + '/' + keyword + '.dot.js');
return {
keyword: keyword,
code: doT.compile(template)
code: doT.compile(template, { definitions: defs })
};
});
});

View File

@ -1,66 +1,47 @@
{{## def.ifValid:
{{? $breakOnError }}
if (valid) {
{{ $closingBraces += '}'; }}
{{?}}
#}}
{{# def.definitions }}
{{# def.setup:'items' }}
{{# def.setupNextLevel }}
{{## def.validateItems:startFrom:
for (var i = {{= startFrom }}; i < data.length; i++) {
var data{{=$level}} = data[i]
, dataPath{{=$level}} = dataPath + '[' + i + ']';
for (var i = {{= startFrom }}; i < data{{=$dataLvl}}.length; i++) {
var data{{=$dataNxt}} = data{{=$dataLvl}}[i]
, dataPath{{=$dataNxt}} = dataPath{{=$dataLvl}} + '[' + i + ']';
{{? $breakOnError }} valid = {{?}}
validateItems(data{{=$level}}, dataPath{{=$level}});
validateItems(data{{=$dataNxt}}, dataPath{{=$dataNxt}});
{{? $breakOnError }} if (!valid) break; {{?}}
}
#}}
{{
var $it = it.copy(it)
, $level = it.level
, $breakOnError = !it.opts.allErrors
, $closingBraces = ''
, $itemsSchema = it.schema.items;
$it.level++;
}}
{{ var $dataNxt = $it.dataLevel = it.dataLevel + 1; }}
var errs{{=$level}} = validate.errors.length;
var errs{{=$lvl}} = validate.errors.length;
var valid;
{{? Array.isArray($itemsSchema) }}
{{? Array.isArray($schema) }}
{{ /* 'items' is an array of schemas */}}
{{ var $additionalItems = it.schema.additionalItems; }}
{{? $additionalItems === false }}
valid = data.length <= {{= $itemsSchema.length }};
if (!valid) {
validate.errors.push({
keyword: 'additionalItems',
dataPath: dataPath,
message: 'should NOT have more than {{= $itemsSchema.length }} items'
{{? it.opts.verbose }}, schema: false, data: data{{?}}
});
}
{{? $breakOnError }}
{{ $closingBraces += '}'; }}
else {
{{?}}
valid = data{{=$dataLvl}}.length <= {{= $schema.length }};
{{# def.checkError:'additionalItems' }}
{{# def.elseIfValid}}
{{?}}
{{~ $itemsSchema:$schema:$index }}
{{? Object.keys($schema).length }}
{{~ $schema:$sch:$i }}
{{? Object.keys($sch).length }}
valid = true;
if (data.length > {{= $index }}) {
if (data{{=$dataLvl}}.length > {{=$i}}) {
{{
$it.schema = $schema;
$it.schemaPath = it.schemaPath + '.items[' + $index + ']';
$it.schema = $sch;
$it.schemaPath = $schemaPath + '[' + $i + ']';
}}
var data{{=$level}} = data[{{= $index }}]
, dataPath{{=$level}} = dataPath + '[{{= $index }}]';
var data{{=$dataNxt}} = data{{=$dataLvl}}[{{= $i }}]
, dataPath{{=$dataNxt}} = dataPath{{=$dataLvl}} + '[{{=$i}}]';
{{? $breakOnError }} valid = {{?}}
({{= it.validate($it) }})(data{{=$level}}, dataPath{{=$level}});
valid = ({{= it.validate($it) }})(data{{=$dataNxt}}, dataPath{{=$dataNxt}});
}
{{# def.ifValid }}
@ -73,18 +54,19 @@ var valid;
$it.schemaPath = it.schemaPath + '.additionalItems';
}}
if (data.length > {{= $itemsSchema.length }}) {
if (data{{=$dataLvl}}.length > {{= $schema.length }}) {
var validateItems = ({{= it.validate($it) }});
{{# def.validateItems: $itemsSchema.length }}
{{# def.validateItems: $schema.length }}
}
{{# def.ifValid }}
{{?}}
{{?? Object.keys($itemsSchema).length }}
{{?? Object.keys($schema).length }}
{{ /* 'items' is a single schema */}}
{{
$it.schema = $itemsSchema;
$it.schemaPath = it.schemaPath + '.items';
$it.schema = $schema;
$it.schemaPath = $schemaPath;
}}
var validateItems = ({{= it.validate($it) }});
{{# def.validateItems: 0 }}
@ -94,6 +76,6 @@ var valid;
{{? $breakOnError }} {{= $closingBraces }} {{?}}
valid = errs{{=$level}} == validate.errors.length;
valid = errs{{=$lvl}} == validate.errors.length;
{{ out = out.replace(/if \(valid\) \{\s*\}/g, ''); }}
{{# def.cleanUp }}

View File

@ -1,8 +1,6 @@
var valid = data.length <= {{= it.schema.maxItems }};
{{# def.definitions }}
{{# def.setup:'maxItems' }}
if (!valid) validate.errors.push({
keyword: 'maxItems',
dataPath: dataPath,
message: 'should NOT have more than {{= it.schema.maxItems }} items'
{{? it.opts.verbose }}, schema: {{= it.schema.maxItems }}, data: data{{?}}
});
var valid = data{{=$dataLvl}}.length <= {{=$schema}};
{{# def.checkError:'maxItems' }}

View File

@ -1,8 +1,6 @@
var valid = data.length <= {{= it.schema.maxLength }};
{{# def.definitions }}
{{# def.setup:'maxLength' }}
if (!valid) validate.errors.push({
keyword: 'maxLength',
dataPath: dataPath,
message: 'should NOT be longer than {{= it.schema.maxLength }} characters'
{{? it.opts.verbose }}, schema: {{= it.schema.maxLength }}, data: data{{?}}
});
var valid = data{{=$dataLvl}}.length <= {{=$schema}};
{{# def.checkError:'maxLength' }}

View File

@ -1,9 +1,6 @@
var propertiesNum = Object.keys(data).length;
var valid = propertiesNum <= {{= it.schema.maxProperties }};
{{# def.definitions }}
{{# def.setup:'maxProperties' }}
if (!valid) validate.errors.push({
keyword: 'maxProperties',
dataPath: dataPath,
message: 'should NOT have more than {{= it.schema.maxProperties }} properties'
{{? it.opts.verbose }}, schema: {{= it.schema.maxProperties }}, data: data{{?}}
});
var valid = Object.keys(data{{=$dataLvl}}).length <= {{=$schema}};
{{# def.checkError:'maxProperties' }}

View File

@ -1,13 +1,12 @@
{{# def.definitions }}
{{# def.setup:'maximum' }}
{{
var $exclusive = it.schema.exclusiveMaximum === true
, $op = $exclusive ? '<' : '<=';
}}
var valid = data {{= $op }} {{= it.schema.maximum }};
var valid = data{{=$dataLvl}} {{=$op}} {{=$schema}};
{{# def.checkError:'maximum' }}
if (!valid) validate.errors.push({
keyword: 'maximum',
dataPath: dataPath,
message: 'should be {{= $op }} {{= it.schema.maximum }}'
{{? it.opts.verbose }}, schema: {{= it.schema.maximum }}, data: data{{?}}
});

View File

@ -1,8 +1,6 @@
var valid = data.length >= {{= it.schema.minItems }};
{{# def.definitions }}
{{# def.setup:'minItems' }}
if (!valid) validate.errors.push({
keyword: 'minItems',
dataPath: dataPath,
message: 'should NOT have less than {{= it.schema.minItems }} items'
{{? it.opts.verbose }}, schema: {{= it.schema.minItems }}, data: data{{?}}
});
var valid = data{{=$dataLvl}}.length >= {{=$schema}};
{{# def.checkError:'minItems' }}

View File

@ -1,8 +1,6 @@
var valid = data.length >= {{= it.schema.minLength }};
{{# def.definitions }}
{{# def.setup:'minLength' }}
if (!valid) validate.errors.push({
keyword: 'minLength',
dataPath: dataPath,
message: 'should NOT be shorter than {{= it.schema.minLength }} characters'
{{? it.opts.verbose }}, schema: {{= it.schema.minLength }}, data: data{{?}}
});
var valid = data{{=$dataLvl}}.length >= {{=$schema}};
{{# def.checkError:'minLength' }}

View File

@ -1,9 +1,6 @@
var propertiesNum = Object.keys(data).length;
var valid = propertiesNum >= {{= it.schema.minProperties }};
{{# def.definitions }}
{{# def.setup:'minProperties' }}
if (!valid) validate.errors.push({
keyword: 'minProperties',
dataPath: dataPath,
message: 'should NOT have less than {{= it.schema.minProperties }} properties'
{{? it.opts.verbose }}, schema: {{= it.schema.minProperties }}, data: data{{?}}
});
var valid = Object.keys(data{{=$dataLvl}}).length >= {{=$schema}};
{{# def.checkError:'minProperties' }}

View File

@ -1,13 +1,11 @@
{{# def.definitions }}
{{# def.setup:'minimum' }}
{{
var $exclusive = it.schema.exclusiveMinimum === true
, $op = $exclusive ? '>' : '>=';
}}
var valid = data {{= $op }} {{= it.schema.minimum }};
var valid = data {{=$op}} {{=$schema}};
if (!valid) validate.errors.push({
keyword: 'minimum',
dataPath: dataPath,
message: 'should be {{= $op }} {{= it.schema.minimum }}'
{{? it.opts.verbose }}, schema: {{= it.schema.minimum }}, data: data{{?}}
});
{{# def.checkError:'minimum' }}

View File

@ -1,9 +1,7 @@
var division = data / {{= it.schema.multipleOf }};
var valid = division === parseInt(division);
{{# def.definitions }}
{{# def.setup:'multipleOf' }}
if (!valid) validate.errors.push({
keyword: 'multipleOf',
dataPath: dataPath,
message: 'should be multiple of {{= it.schema.multipleOf }}'
{{? it.opts.verbose }}, schema: {{= it.schema.multipleOf }}, data: data{{?}}
});
var division{{=$lvl}} = data{{=$dataLvl}} / {{=$schema}};
var valid = division{{=$lvl}} === parseInt(division{{=$lvl}});
{{# def.checkError:'multipleOf' }}

View File

@ -1,20 +1,16 @@
{{# def.definitions }}
{{# def.setup:'not' }}
{{# def.setupNextLevel }}
{{
var $it = it.copy(it)
, $level = it.level;
$it.level++;
$it.schema = it.schema.not;
$it.schemaPath = it.schemaPath + '.not';
$it.schema = $schema;
$it.schemaPath = $schemaPath;
}}
var errs{{= $level }} = validate.errors.length;
var errs{{=$lvl}} = validate.errors.length;
var valid = ({{= it.validate($it) }})(data, dataPath);
var valid = ({{= it.validate($it) }})(data{{=$dataLvl}}, dataPath{{=$dataLvl}});
valid = !valid;
if (valid) validate.errors.length = errs{{= $level }};
else validate.errors.push({
keyword: 'not',
dataPath: dataPath,
message: 'should NOT be valid'
{{? it.opts.verbose }}, schema: validate.schema{{= it.schemaPath + '.not' }}, data: data{{?}}
});
if (valid) validate.errors.length = errs{{=$lvl}};
else {{# def.error:'not' }}

View File

@ -1,36 +1,29 @@
{{
var $it = it.copy(it)
, $level = it.level
, $closingBraces = '';
$it.level++;
}}
{{# def.definitions }}
{{# def.setup:'oneOf' }}
{{# def.setupNextLevel }}
var errs{{= $level }} = validate.errors.length;
var validCount{{= $level }} = 0;
{{~ it.schema.oneOf:$schema:$i }}
var errs{{=$lvl}} = validate.errors.length;
var validCount{{=$lvl}} = 0;
{{~ $schema:$sch:$i }}
{{? $i }}
{{ $closingBraces += '}'; }}
if (validCount{{= $level }} < 2) {
if (validCount{{=$lvl}} < 2) {
{{?}}
{{
$it.schema = $schema;
$it.schemaPath = it.schemaPath + '.oneOf[' + $i + ']';
$it.schema = $sch;
$it.schemaPath = $schemaPath + '[' + $i + ']';
}}
var valid = ({{= it.validate($it) }})(data, dataPath);
if (valid) validCount{{= $level }}++;
var valid = ({{= it.validate($it) }})(data{{=$dataLvl}}, dataPath{{=$dataLvl}});
if (valid) validCount{{=$lvl}}++;
{{~}}
{{= $closingBraces }}
if (validCount{{= $level }} == 1) validate.errors.length = errs{{= $level }};
else validate.errors.push({
keyword: 'oneOf',
dataPath: dataPath,
message: 'should match exactly one schema in oneOf'
{{? it.opts.verbose }}, schema: validate.schema{{= it.schemaPath + '.oneOf'}}, data: data{{?}}
});
var valid = validCount{{=$lvl}} == 1;
var valid = validCount{{= $level }} == 1;
if (valid) validate.errors.length = errs{{=$lvl}};
else {{# def.error:'oneOf' }}

View File

@ -1,9 +1,7 @@
{{ new RegExp(it.schema.pattern); /* test if regexp is valid to fail at compile time rather than in eval */}}
var valid = /{{= it.schema.pattern }}/.test(data);
{{# def.definitions }}
{{# def.setup:'pattern' }}
if (!valid) validate.errors.push({
keyword: 'minimum',
dataPath: dataPath,
message: 'should match pattern "{{= it.schema.pattern }}"'
{{? it.opts.verbose }}, schema: '{{= it.schema.pattern }}', data: data{{?}}
});
{{ new RegExp($schema); /* test if regexp is valid to fail at compile time rather than in eval */}}
var valid = /{{=$schema}}/.test(data);
{{# def.checkError:'pattern' }}

View File

@ -1,60 +1,40 @@
{{## def.ifValid:
{{? $breakOnError }}
if (valid) {
{{ $closingBraces += '}'; }}
{{?}}
#}}
{{# def.definitions }}
{{# def.setup:'properties' }}
{{# def.setupNextLevel }}
{{## def.validateProperty:useKey:
var data{{=$lvl}} = data[{{= useKey }}]
, dataPath{{=$lvl}} = dataPath + '.' + {{= useKey }};
var data{{=$dataNxt}} = data{{=$dataLvl}}[{{= useKey }}]
, dataPath{{=$dataNxt}} = dataPath{{=$dataLvl}} + '.' + {{= useKey }};
{{? $breakOnError }} var valid = {{?}}
({{= it.validate($it) }})(data{{=$lvl}}, dataPath{{=$lvl}});
({{= it.validate($it) }})(data{{=$dataNxt}}, dataPath{{=$dataNxt}});
#}}
{{
var $it = it.copy(it)
, $lvl = it.level
, $breakOnError = !it.opts.allErrors
, $closingBraces = ''
, $pProperties = it.schema.patternProperties || {}
var $dataNxt = $it.dataLevel = it.dataLevel + 1;
var $pProperties = it.schema.patternProperties || {}
, $pPropertyKeys = Object.keys($pProperties)
, $aProperties = it.schema.additionalProperties
, $noAdditional = $aProperties === false
, $additionalIsSchema = typeof $aProperties == 'object'
&& Object.keys($aProperties).length
, $checkAdditional = $noAdditional || $additionalIsSchema;
$it.level++;
}}
var errs{{=$lvl}} = validate.errors.length;
var valid = true;
{{? $checkAdditional }}
var propertiesSchema{{=$lvl}} = validate.schema{{= it.schemaPath + '.properties' }} || {};
var propertiesSchema{{=$lvl}} = validate.schema{{=$schemaPath}} || {};
{{?}}
{{? $noAdditional }}
var propertiesSchemaKeys{{=$lvl}} = Object.keys(propertiesSchema{{=$lvl}});
var dataKeys{{=$lvl}} = Object.keys(data);
var valid = dataKeys{{=$lvl}}.length <= propertiesSchemaKeys{{=$lvl}}.length;
if (!valid) {
validate.errors.push({
keyword: 'properties',
dataPath: dataPath,
message: 'additional properties NOT allowed'
{{? it.opts.verbose }}, schema: propertiesSchema{{=$lvl}}, data: data{{?}}
});
}
{{? $breakOnError }}
{{ $closingBraces += '}'; }}
else {
{{?}}
var valid = Object.keys(data{{=$dataLvl}}).length <= Object.keys(propertiesSchema{{=$lvl}}).length;
{{# def.checkError:'additionalProperties' }}
{{# def.elseIfValid }}
{{?}}
{{? $pPropertyKeys.length }}
@ -67,41 +47,34 @@ var valid = true;
{{? $checkAdditional }}
for (var key in data) {
var isAdditional = !propertiesSchema{{=$lvl}}.hasOwnProperty(key);
for (var key{{=$lvl}} in data{{=$dataLvl}}) {
var isAdditional{{=$lvl}} = !propertiesSchema{{=$lvl}}.hasOwnProperty(key{{=$lvl}});
{{? $pPropertyKeys.length }}
if (isAdditional) {
if (isAdditional{{=$lvl}}) {
for (var pProperty{{=$lvl}} in pPropertiesSchema{{=$lvl}}) {
var keyMatches = pPropertiesRegexps{{=$lvl}}[pProperty{{=$lvl}}].test(key);
if (keyMatches) {
isAdditional = false;
var keyMatches{{=$lvl}} = pPropertiesRegexps{{=$lvl}}[pProperty{{=$lvl}}].test(key{{=$lvl}});
if (keyMatches{{=$lvl}}) {
isAdditional{{=$lvl}} = false;
break;
}
}
}
{{?}}
if (isAdditional) {
if (isAdditional{{=$lvl}}) {
{{? $noAdditional }}
valid = false;
validate.errors.push({
keyword: 'properties',
dataPath: dataPath,
message: 'property ' + key + ' NOT allowed'
{{? it.opts.verbose }}, schema: propertiesSchema{{=$lvl}}, data: data{{?}}
});
{{# def.error:'additionalProperties' }}
{{? $breakOnError }} break; {{?}}
{{??}}
{{
/* additionalProperties is schema */
{{ /* additionalProperties is schema */
$it.schema = $aProperties;
$it.schemaPath = it.schemaPath + '.additionalProperties';
}}
{{# def.validateProperty:'key' }}
{{ var $useKey = 'key' + $lvl; }}
{{# def.validateProperty:$useKey }}
{{? $breakOnError }} if (!valid) break; {{?}}
{{?}}
}
@ -110,18 +83,18 @@ var valid = true;
{{# def.ifValid }}
{{?}}
{{? it.schema.properties }}
{{ for (var $propertyKey in it.schema.properties) { }}
{{ var $schema = it.schema.properties[$propertyKey]; }}
{{? $schema }}
{{ for (var $propertyKey in $schema) { }}
{{ var $sch = $schema[$propertyKey]; }}
{{? Object.keys($schema).length }}
{{? Object.keys($sch).length }}
{{
$it.schema = $schema;
$it.schemaPath = it.schemaPath + '.properties["' + it.escapeQuotes($propertyKey) + '"]';
$it.schema = $sch;
$it.schemaPath = $schemaPath + '["' + it.escapeQuotes($propertyKey) + '"]';
}}
{{? $breakOnError }} valid = true; {{?}}
if (data.hasOwnProperty('{{= $propertyKey }}')) {
if (data{{=$dataLvl}}.hasOwnProperty('{{= $propertyKey }}')) {
{{ /* TODO cache data types and paths by keys for patternProperties */ }}
{{ var $useKey = '"' + $propertyKey + '"'; }}
{{# def.validateProperty:$useKey }}
@ -133,18 +106,18 @@ var valid = true;
{{?}}
{{~ $pPropertyKeys:$propertyKey }}
{{ var $schema = $pProperties[$propertyKey]; }}
{{ var $sch = $pProperties[$propertyKey]; }}
{{? Object.keys($schema).length }}
{{? Object.keys($sch).length }}
{{
$it.schema = $schema;
$it.schema = $sch;
$it.schemaPath = it.schemaPath + '.patternProperties.' + $propertyKey;
}}
for (var key{{=$lvl}} in data) {
var keyMatches = pPropertiesRegexps{{=$lvl}}['{{= $propertyKey }}'].test(key{{=$lvl}});
for (var key{{=$lvl}} in data{{=$dataLvl}}) {
var keyMatches{{=$lvl}} = pPropertiesRegexps{{=$lvl}}['{{= $propertyKey }}'].test(key{{=$lvl}});
if (keyMatches) {
if (keyMatches{{=$lvl}}) {
{{ var $useKey = 'key' + $lvl; }}
{{# def.validateProperty:$useKey }}
{{? $breakOnError }} if (!valid) break; {{?}}
@ -159,5 +132,4 @@ var valid = true;
var valid = errs{{=$lvl}} == validate.errors.length;
{{ out = out.replace(/if \(valid\) \{\s*\}/g, ''); }}
{{# def.cleanUp }}

View File

@ -1,25 +1,18 @@
{{ var $schema = it.schema.required; }}
{{# def.definitions }}
{{# def.setup:'required' }}
{{? $schema.length <= 100 }}
var valid = {{~ $schema:$property:$i }}
{{? $i}} && {{?}}
data.hasOwnProperty('{{= it.escapeQuotes($property) }}')
{{~}};
valid = {{~ $schema:$property:$i }}
{{? $i}} && {{?}}
data{{=$dataLvl}}.hasOwnProperty('{{= it.escapeQuotes($property) }}')
{{~}};
{{??}}
{{ var $lvl = it.level; }}
var valid = true;
var schema{{=$lvl}} = validate.schema{{= it.schemaPath + '.required' }};
var schema{{=$lvl}} = validate.schema{{=$schemaPath}};
for (var i = 0; i < schema{{=$lvl}}.length; i++) {
var property = schema{{=$lvl}}[i]
, valid = valid && data.hasOwnProperty(schema{{=$lvl}}[i]);
{{? !it.opts.allErrors }} if (!valid) break; {{?}}
for (var i{{=$lvl}} = 0; i{{=$lvl}} < schema{{=$lvl}}.length; i{{=$lvl}}++) {
valid = data.hasOwnProperty(schema{{=$lvl}}[i{{=$lvl}}]);
if (!valid) break;
}
{{?}}
if (!valid) validate.errors.push({
keyword: 'required',
dataPath: dataPath,
message: 'properties {{= $schema.slice(0, 7).join(",") }}{{? $schema.length > 7}}...{{?}} are required'
{{? it.opts.verbose }}, schema: validate.schema{{= it.schemaPath + '.required' }}, data: data{{?}}
});
{{# def.checkError:'required' }}

View File

@ -1,15 +1,12 @@
{{ var $isArray = Array.isArray(it.schema.type); }}
{{# def.definitions }}
{{# def.setup:'type' }}
{{ var $isArray = Array.isArray($schema); }}
{{? $isArray }}
var valid = {{= it.checkDataTypes(it.schema.type) }};
var valid = {{= it.checkDataTypes($schema, $dataLvl) }};
{{??}}
var valid = {{= it.checkDataType(it.schema.type) }};
var valid = {{= it.checkDataType($schema, $dataLvl) }};
{{?}}
if (!valid) validate.errors.push({
keyword: 'type',
dataPath: dataPath,
message: 'should be {{? $isArray }}{{= it.schema.type.join(",") }}{{??}}{{= it.schema.type }}{{?}}'
{{? it.opts.verbose }}, schema: {{? $isArray }}validate.schema{{= it.schemaPath + '.type' }}{{??}}'{{= it.schema.type }}'{{?}}, data: data{{?}}
});
{{# def.checkError:'type' }}

View File

@ -1,27 +1,21 @@
{{# def.definitions }}
{{# def.setup:'uniqueItems' }}
var valid = true;
{{ var $lvl = it.level; }}
{{? it.schema.uniqueItems && it.opts.uniqueItems !== false }}
if (data.length > 1) {
var i{{=$lvl}} = data.length, j{{=$lvl}};
{{? $schema && it.opts.uniqueItems !== false }}
if (data{{=$dataLvl}}.length > 1) {
var i{{=$lvl}} = data{{=$dataLvl}}.length, j{{=$lvl}};
outer:
for (;i{{=$lvl}}--;) {
for (j{{=$lvl}} = i{{=$lvl}}; j{{=$lvl}}--;) {
if (equal(data[i{{=$lvl}}], data[j{{=$lvl}}])) {
if (equal(data{{=$dataLvl}}[i{{=$lvl}}], data{{=$dataLvl}}[j{{=$lvl}}])) {
valid = false;
break outer;
}
}
}
if (!valid) {
validate.errors.push({
keyword: 'uniqueItems',
dataPath: dataPath,
message: 'items ## ' + i{{=$lvl}} + ' and ' + j{{=$lvl}} + ' are duplicate'
{{? it.opts.verbose }}, schema: {{= it.schema.uniqueItems }}, data: data{{?}}
});
}
if (!valid) {{# def.error:'uniqueItems' }}
}
{{?}}

View File

@ -9,33 +9,46 @@
* validateRef etc. are defined in the parent scope in index.js
*/ }}
function ( data {{? !it.isRoot }}, dataPath {{?}}) {
'use strict';
{{? it.isRoot}}
{{
var $breakOnErrors = !it.opts.allErrors
, $closingBraces1 = ''
, $closingBraces2 = '';
it.isRoot = false;
var $lvl = 0;
it.level = 1;
var $dataLvl = it.dataLevel = 0;
}}
{{? it.isRoot }}
{{
it.isRoot = false;
var $level = 0;
it.level = 1;
}}
var dataPath = '';
var errs{{= $level }} = validate.errors.length = 0;
{{??}}
{{ var $level = it.level++; }}
var errs{{= $level }} = validate.errors.length;
{{?}}
function ( data0 ) {
var dataPath0 = '';
var errs{{=$lvl}} = validate.errors.length = 0;
/* remove when all use dataLevel */
var data = data0;
var dataPath = dataPath0;
{{??}}
{{
var $lvl = it.level++
, $dataLvl = it.dataLevel;
}}
function ( data{{=$dataLvl}}, dataPath{{=$dataLvl}} ) {
var errs{{=$lvl}} = validate.errors.length;
/* remove when all use dataLevel */
/* var data = data{{=$dataLvl}};
var dataPath = dataPath{{=$dataLvl}}; */
{{?}}
{{
var $breakOnErrors = !it.opts.allErrors
, $closingBraces1 = ''
, $closingBraces2 = '';
}}
var valid = true;
{{~ it.RULES:$rulesGroup }}
{{? $shouldUseGroup($rulesGroup) }}
{{? $rulesGroup.type }} if ({{= it.checkDataType($rulesGroup.type) }}) { {{?}}
{{? $rulesGroup.type }} if ({{= it.checkDataType($rulesGroup.type, $dataLvl) }}) { {{?}}
{{~ $rulesGroup.rules:$rule }}
{{? $shouldUseRule($rule) }}
{{= $rule.code(it) }}
@ -60,7 +73,7 @@ function ( data {{? !it.isRoot }}, dataPath {{?}}) {
{{? $breakOnErrors }} {{= $closingBraces2 }} {{?}}
return errs{{= $level }} == validate.errors.length;
return errs{{=$lvl}} == validate.errors.length;
}
{{
@ -83,4 +96,3 @@ function ( data {{? !it.isRoot }}, dataPath {{?}}) {
}}
{{ out = out.replace(/if \(valid\) \{\s*\}/g, ''); }}

View File

@ -1,6 +1,6 @@
{
"name": "ajv",
"version": "0.1.12",
"version": "0.1.13",
"description": "Another JSON schema Validator",
"main": "lib/ajv.js",
"scripts": {

View File

@ -7,15 +7,17 @@ var glob = require('glob')
var ONLY_RULES, SKIP_RULES;
// ONLY_RULES = [
// 'type',
'not',
// 'not',
// 'allOf',
// 'anyOf',
// 'oneOf',
// 'enum',
// 'maximum', 'minimum', 'multipleOf',
// 'maximum', 'minimum',
'multipleOf',
// 'maxLength', 'minLength', 'pattern',
// 'properties', 'patternProperties', 'additionalProperties',
// 'dependencies', 'required',
// 'dependencies',
// 'required',
// 'maxProperties', 'minProperties', 'maxItems', 'minItems',
// 'items', 'additionalItems', 'uniqueItems',
// 'optional/format', 'optional/bignum',
@ -58,27 +60,27 @@ describe('JSON-Schema tests', function () {
describe(file.name, function() {
var testSets = require(file.path);
testSets.forEach(function (testSet) {
// if (testSet.description != 'not more complex schema') return;
// if (testSet.description != 'invalid string value for default') return;
describe(testSet.description, function() {
// it(testSet.description, function() {
var validate = ajv.compile(testSet.schema);
var fullValidate = fullAjv.compile(testSet.schema);
testSet.tests.forEach(function (test) {
// if (test.description != 'match') return;
// if (test.description != 'valid when property is specified') return;
// console.log(testSet.schema, '\n\n***\n\n', validate.toString());
it(test.description, function() {
var valid = validate(test.data);
// console.log('result', result);
// console.log('result', valid, validate.errors);
assert.equal(valid, test.valid);
if (valid) assert(validate.errors.length == 0);
else assert(validate.errors.length > 0);
var valid = fullValidate(test.data);
// console.log('full result', result);
// console.log('full result', valid, fullValidate.errors);
assert.equal(valid, test.valid);
if (valid) assert(validate.errors.length == 0);
else assert(validate.errors.length > 0);
if (valid) assert(fullValidate.errors.length == 0);
else assert(fullValidate.errors.length > 0);
});
});
});

109
try.js
View File

@ -1,62 +1,49 @@
var out = '';
out += 'function (data, dataType, dataPath) { \'use strict\'; ';
if (it.opts.allErrors) {
out += ' var errors = []; ';
}
out += ' ';
var $schemaKeys = Object.keys(it.schema);
$schemaKeys.sort(compareRules);
out += ' ';
var $checkProperties = !it.schema.properties && (it.schema.patternProperties || it.schema.hasOwnProperty('additionalProperties'));
if ($checkProperties) $schemaKeys.push('properties');
out += ' ';
var arr1 = $schemaKeys;
if (arr1) {
var $key, i1 = -1,
l1 = arr1.length - 1;
while (i1 < l1) {
$key = arr1[i1 += 1];
out += ' ';
var $rule = it.RULES[$key];
out += ' ';
if ($rule) {
out += ' var rule = RULES.' + ($key) + '; if ( !rule.type || rule.type == dataType ) { ';
if ($rule.inline) {
out += ' ' + ($rule.code(it)) + ' ';
} else {
out += ' ';
var $it = it.copy(it);
$it.schema = it.schema[$key];
$it.schemaPath = it.schemaPath + '.' + $key;
$it.parentSchema = it.schema;
$it.parentSchemaPath = it.schemaPath;
out += ' var result = (' + ($rule.code($it)) + ')(data, dataType, dataPath); ';
}
out += ' if (!result.valid) { ';
if (it.opts.allErrors) {
out += ' errors.push.apply(errors, result.errors); ';
} else {
out += ' return result; ';
}
out += ' } } ';
}
out += ' ';
}
}
out += ' ';
if (it.opts.allErrors) {
out += ' return { valid: !errors.length, errors: errors }; ';
} else {
out += ' return { valid: true, errors: [] }; ';
}
out += ' ';
function(it) {
function compareRules(key1, key2) {
var order1 = it.RULES[key1].order,
order2 = it.RULES[key2].order;
if (order1 < order2) return -1;
if (order1 > order2) return +1;
if (order1 == order2) return 0;
}
}
return out
var $lvl = it.level,
$dataLvl = it.dataLevel,
$schema = it.schema['required'],
$schemaPath = it.schemaPath + '.' + 'required';
if ($schema.length <= 100) {
out += ' valid = ';
var arr1 = $schema;
if (arr1) {
var $property, $i = -1,
l1 = arr1.length - 1;
while ($i < l1) {
$property = arr1[$i += 1];
out += ' ';
if ($i) {
out += ' && ';
}
out += ' data' + ($dataLvl) + '.hasOwnProperty(\'' + (it.escapeQuotes($property)) + '\') ';
}
}
out += '; if (!valid) validate.errors.push({ \'required\': \'' + ('required') + '\', dataPath: dataPath' + ($dataLvl) + ', message: \'properties ' + ($schema.slice(0, 7).join(", "));
if ($schema.length > 7) {
out += '...';
}
out += ' are required\' ';
if (it.opts.verbose) {
out += ', schema: validate.schema' + ($schemaPath) + ', data: data' + ($dataLvl);
}
out += ' });';
} else {
out += ' var errs' + ($lvl) + ' = validate.errors.length; var schema' + ($lvl) + ' = validate.schema' + ($schemaPath) + '; for (var i' + ($lvl) + ' = 0; i' + ($lvl) + ' < schema' + ($lvl) + '.length; i' + ($lvl) + '++) { valid = data.hasOwnProperty(schema' + ($lvl) + '[i' + ($lvl) + ']); if (!valid) { validate.errors.push({ \'required\': \'' + ('required') + '\', dataPath: dataPath' + ($dataLvl) + ', message: \'properties ' + ($schema.slice(0, 7).join(", "));
if ($schema.length > 7) {
out += '...';
}
out += ' are required\' ';
if (it.opts.verbose) {
out += ', schema: validate.schema' + ($schemaPath) + ', data: data' + ($dataLvl);
}
out += ' }); ';
if (!it.opts.allErrors) {
out += ' break; ';
}
out += ' } } ';
if (it.opts.allErrors) {
out += ' valid = errs' + ($lvl) + ' == validate.errors.length; {{}}';
}
return out;
}