Skip to content

Commit

Permalink
Merge pull request #92 from epoberezkin/schemapath
Browse files Browse the repository at this point in the history
schemaPath in errors, closes #80
  • Loading branch information
Evgeny Poberezkin committed Dec 19, 2015
2 parents 8b98518 + ca80b2e commit 4ff5662
Show file tree
Hide file tree
Showing 19 changed files with 152 additions and 72 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,7 @@ Each error is an object with the following properties:

- _keyword_: validation keyword. For user defined validation keywords it is set to `"custom"` (with the exception of macro keywords and unless keyword definition defines its own errors).
- _dataPath_: the path to the part of the data that was validated. By default `dataPath` uses JavaScript property access notation (e.g., `".prop[1].subProp"`). When the option `jsonPointers` is true (see [Options](#options)) `dataPath` will be set using JSON pointer standard (e.g., `"/prop/1/subProp"`).
- _schemaPath_: the path (JSON pointer) to the schema of the keyword that failed validation.
- _params_: the object with the additional information about error that can be used to create custom error messages (e.g., using [ajv-i18n](https://github.com/epoberezkin/ajv-i18n) package). See below for parameters set by all keywords.
- _message_: the standard error message (can be excluded with option `messages` set to false).
- _schema_: the schema of the keyword (added with `verbose` option).
Expand Down
1 change: 1 addition & 0 deletions lib/compile/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ function compile(schema, root, localRefs, baseId) {
baseId: baseId,
root: _root,
schemaPath: '',
errSchemaPath: '#',
errorPath: '""',
RULES: RULES,
validate: validateGenerator,
Expand Down
17 changes: 2 additions & 15 deletions lib/compile/resolve.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ function getJsonPointer(parsedRef, baseId, schema, root) {
for (var i = 1; i < parts.length; i++) {
var part = parts[i];
if (part) {
part = unescapeFragment(part);
part = util.unescapeFragment(part);
schema = schema[part];
if (!schema) break;
if (schema.id && !PREVENT_SCOPE_CHANGE[part]) baseId = resolveUrl(baseId, schema.id);
Expand Down Expand Up @@ -176,19 +176,6 @@ function countKeys(schema) {
}


function unescapeFragment(str) {
return decodeURIComponent(str)
.replace(/~1/g, '/')
.replace(/~0/g, '~');
}


function escapeFragment(str) {
str = str.replace(/~/g, '~0').replace(/\//g, '~1');
return encodeURIComponent(str);
}


function getFullPath(id, normalize) {
if (normalize !== false) id = normalizeId(id);
var p = url.parse(id, false, true);
Expand Down Expand Up @@ -246,7 +233,7 @@ function resolveIds(schema) {
}
}
for (var key in schema)
_resolveIds.call(this, schema[key], fullPath+'/'+escapeFragment(key), baseId);
_resolveIds.call(this, schema[key], fullPath+'/'+util.escapeFragment(key), baseId);
}
}
}
24 changes: 20 additions & 4 deletions lib/compile/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ module.exports = {
stableStringify: require('json-stable-stringify'),
toQuotedString: toQuotedString,
getPathExpr: getPathExpr,
getPath: getPath
getPath: getPath,
unescapeFragment: unescapeFragment,
escapeFragment: escapeFragment
};


Expand Down Expand Up @@ -176,16 +178,16 @@ function toQuotedString (str) {


function getPathExpr (currentPath, expr, jsonPointers, isNumber) {
var path = jsonPointers
var path = jsonPointers // false by default
? '\'/\' + ' + expr + (isNumber ? '' : '.replace(/~/g, \'~0\').replace(/\\//g, \'~1\')')
: (isNumber ? '\'[\' + ' + expr + ' + \']\'' : '\'[\\\'\' + ' + expr + ' + \'\\\']\'');
return joinPaths(currentPath, path);
}


function getPath (currentPath, prop, jsonPointers) {
var path = jsonPointers
? toQuotedString('/' + prop.replace(/~/g, '~0').replace(/\//g, '~1'))
var path = jsonPointers // false by default
? toQuotedString('/' + escapeFragment(prop))
: toQuotedString(getProperty(prop));
return joinPaths(currentPath, path);
}
Expand All @@ -195,3 +197,17 @@ function joinPaths (a, b) {
if (a == '""') return b;
return (a + ' + ' + b).replace(/' \+ '/g, '');
}


function unescapeFragment(str) {
return decodeURIComponent(str)
.replace(/~1/g, '/')
.replace(/~0/g, '~');
}


function escapeFragment(str) {
str = str.replace(/~/g, '~0').replace(/\//g, '~1');
return encodeURIComponent(str);
}

1 change: 1 addition & 0 deletions lib/dot/allOf.jst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
{{
$it.schema = $sch;
$it.schemaPath = $schemaPath + '[' + $i + ']';
$it.errSchemaPath = $errSchemaPath + '/' + $i;
}}

{{= it.validate($it) }}
Expand Down
1 change: 1 addition & 0 deletions lib/dot/anyOf.jst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
{{
$it.schema = $sch;
$it.schemaPath = $schemaPath + '[' + $i + ']';
$it.errSchemaPath = $errSchemaPath + '/' + $i;
}}

{{= it.validate($it) }}
Expand Down
1 change: 1 addition & 0 deletions lib/dot/custom.def
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
, $ruleValidate = it.useCustomRule($rule, $schema, it.schema, it)
, $ruleErrs = $ruleValidate.code + '.errors'
, $schemaPath = it.schemaPath + '.' + $rule.keyword
, $errSchemaPath = it.errSchemaPath + '/' + $rule.keyword
, $errs = 'errs' + $lvl
, $i = 'i' + $lvl
, $ruleErr = 'ruleErr' + $lvl
Expand Down
1 change: 1 addition & 0 deletions lib/dot/definitions.def
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
, $dataLvl = it.dataLevel
, $schema = it.schema[_keyword]
, $schemaPath = it.schemaPath + '.' + _keyword
, $errSchemaPath = it.errSchemaPath + '/' + _keyword
, $breakOnError = !it.opts.allErrors;

var $data = 'data' + ($dataLvl || '')
Expand Down
1 change: 1 addition & 0 deletions lib/dot/dependencies.jst
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ var missing{{=$lvl}};
{{
$it.schema = $sch;
$it.schemaPath = $schemaPath + it.util.getProperty($property);
$it.errSchemaPath = $errSchemaPath + '/' + it.util.escapeFragment($property);
}}

{{= it.validate($it) }}
Expand Down
2 changes: 1 addition & 1 deletion lib/dot/errors.def
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
{
keyword: '{{=_rule}}'
, dataPath: (dataPath || '') + {{= it.errorPath }}
, schemaPath: "{{=$schemaPath}}"
, schemaPath: "{{=$errSchemaPath}}"
, params: {{# def._errorParams[_rule] }}
{{? it.opts.messages !== false }}
, message: {{# def._errorMessages[_rule] }}
Expand Down
8 changes: 8 additions & 0 deletions lib/dot/items.jst
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,12 @@ var {{=$valid}};
{{ var $additionalItems = it.schema.additionalItems; }}
{{? $additionalItems === false }}
{{=$valid}} = {{=$data}}.length <= {{= $schema.length }};
{{
var $currErrSchemaPath = $errSchemaPath;
$errSchemaPath = it.errSchemaPath + '/additionalItems';
}}
{{# def.checkError:'additionalItems' }}
{{ $errSchemaPath = $currErrSchemaPath; }}
{{# def.elseIfValid}}
{{?}}

Expand All @@ -45,6 +50,7 @@ var {{=$valid}};
{{
$it.schema = $sch;
$it.schemaPath = $schemaPath + '[' + $i + ']';
$it.errSchemaPath = $errSchemaPath + '/' + $i;
$it.errorPath = it.util.getPathExpr(it.errorPath, $i, it.opts.jsonPointers, true);
var $passData = $data + '[' + $i + ']';
}}
Expand All @@ -61,6 +67,7 @@ var {{=$valid}};
{{
$it.schema = $additionalItems;
$it.schemaPath = it.schemaPath + '.additionalItems';
$it.errSchemaPath = it.errSchemaPath + '/additionalItems';
}}
valid{{=$it.level}} = true;

Expand All @@ -76,6 +83,7 @@ var {{=$valid}};
{{
$it.schema = $schema;
$it.schemaPath = $schemaPath;
$it.errSchemaPath = $errSchemaPath;
}}
{{# def.validateItems: 0 }}
{{# def.ifResultValid }}
Expand Down
1 change: 1 addition & 0 deletions lib/dot/not.jst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
{{
$it.schema = $schema;
$it.schemaPath = $schemaPath;
$it.errSchemaPath = $errSchemaPath;
}}

var {{=$errs}} = errors;
Expand Down
1 change: 1 addition & 0 deletions lib/dot/oneOf.jst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ var {{=$valid}} = false;
{{
$it.schema = $sch;
$it.schemaPath = $schemaPath + '[' + $i + ']';
$it.errSchemaPath = $errSchemaPath + '/' + $i;
}}

{{= it.validate($it) }}
Expand Down
24 changes: 23 additions & 1 deletion lib/dot/properties.jst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
{{ /* additionalProperties is schema */
$it.schema = $aProperties;
$it.schemaPath = it.schemaPath + '.additionalProperties';
$it.errSchemaPath = it.errSchemaPath + '/additionalProperties';
$it.errorPath = it.opts._errorDataPathProperty
? it.errorPath
: it.util.getPathExpr(it.errorPath, 'key' + $lvl, it.opts.jsonPointers);
Expand Down Expand Up @@ -87,7 +88,12 @@ var valid{{=$it.level}} = true;
delete {{=$data}}[key{{=$lvl}}];
{{??}}
valid{{=$it.level}} = false;
{{
var $currErrSchemaPath = $errSchemaPath;
$errSchemaPath = it.errSchemaPath + '/additionalProperties';
}}
{{# def.error:'additionalProperties' }}
{{ $errSchemaPath = $currErrSchemaPath; }}
{{? $breakOnError }} break; {{?}}
{{?}}
{{?? $additionalIsSchema }}
Expand Down Expand Up @@ -132,6 +138,7 @@ var valid{{=$it.level}} = true;
var $prop = it.util.getProperty($propertyKey)
, $passData = $data + $prop;
$it.schemaPath = $schemaPath + $prop;
$it.errSchemaPath = $errSchemaPath + '/' + it.util.escapeFragment($propertyKey);
$it.errorPath = it.util.getPath(it.errorPath, $propertyKey, it.opts.jsonPointers);
}}

Expand All @@ -152,12 +159,15 @@ var valid{{=$it.level}} = true;
valid{{=$it.level}} = false;
{{
var $currentErrorPath = it.errorPath
, $currErrSchemaPath = $errSchemaPath
, $missingProperty = it.util.escapeQuotes($propertyKey);
if (it.opts._errorDataPathProperty) {
it.errorPath = it.util.getPath($currentErrorPath, $propertyKey, it.opts.jsonPointers);
}
$errSchemaPath = it.errSchemaPath + '/required';
}}
{{# def.error:'required' }}
{{ $errSchemaPath = $currErrSchemaPath; }}
{{ it.errorPath = $currentErrorPath; }}
} else {
{{??}}
Expand Down Expand Up @@ -185,6 +195,8 @@ var valid{{=$it.level}} = true;
{{
$it.schema = $sch;
$it.schemaPath = it.schemaPath + '.patternProperties' + it.util.getProperty($pProperty);
$it.errSchemaPath = it.errSchemaPath + '/patternProperties/'
+ it.util.escapeFragment($pProperty);
}}

for (var key{{=$lvl}} in {{=$data}}) {
Expand Down Expand Up @@ -217,7 +229,10 @@ var valid{{=$it.level}} = true;
{{? {{# def.nonEmptySchema:$sch}} }}
{{
$it.schema = $sch;
$it.schemaPath = it.schemaPath + '.patternGroups' + it.util.getProperty($pgProperty);
$it.schemaPath = it.schemaPath + '.patternGroups' + it.util.getProperty($pgProperty) + '.schema';
$it.errSchemaPath = it.errSchemaPath + '/patternGroups/'
+ it.util.escapeFragment($pgProperty)
+ '/schema';
}}

var pgPropCount{{=$lvl}} = 0;
Expand Down Expand Up @@ -247,9 +262,13 @@ var valid{{=$it.level}} = true;
}}
{{? $pgMin !== undefined || $pgMax !== undefined }}
var {{=$valid}} = true;

{{ var $currErrSchemaPath = $errSchemaPath; }}

{{? $pgMin !== undefined }}
{{ var $limit = $pgMin, $reason = 'minimum', $moreOrLess = 'less'; }}
{{=$valid}} = pgPropCount{{=$lvl}} >= {{=$pgMin}};
{{ $errSchemaPath = it.errSchemaPath + '/patternGroups/minimum'; }}
{{# def.checkError:'patternGroups' }}
{{? $pgMax !== undefined }}
else
Expand All @@ -259,9 +278,12 @@ var valid{{=$it.level}} = true;
{{? $pgMax !== undefined }}
{{ var $limit = $pgMax, $reason = 'maximum', $moreOrLess = 'more'; }}
{{=$valid}} = pgPropCount{{=$lvl}} <= {{=$pgMax}};
{{ $errSchemaPath = it.errSchemaPath + '/patternGroups/maximum'; }}
{{# def.checkError:'patternGroups' }}
{{?}}

{{ $errSchemaPath = $currErrSchemaPath; }}

{{# def.ifValid }}
{{?}}
{{?}} {{ /* def.nonEmptySchema */ }}
Expand Down
1 change: 1 addition & 0 deletions lib/dot/ref.jst
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
{{
$it.schema = $refVal.schema;
$it.schemaPath = '';
$it.errSchemaPath = $schema;
}}
{{ var $code = it.validate($it).replace(/validate\.schema/g, $refVal.code); }}
{{= $code }}
Expand Down
1 change: 1 addition & 0 deletions lib/dot/v5/switch.jst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
{{
$it.schema = $sch._clause;
$it.schemaPath = $schemaPath + '[' + $caseIndex + ']._clause';
$it.errSchemaPath = $errSchemaPath + '/' + $caseIndex + '/_clause';
}}
{{= it.validate($it) }}
#}}
Expand Down
6 changes: 5 additions & 1 deletion lib/dot/validate.jst
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,10 @@
{{? $typeSchema && $typeSchema === $rulesGroup.type }}
{{ var $typeChecked = true; }}
else {
{{ var $schemaPath = it.schemaPath + '.type'; }}
{{
var $schemaPath = it.schemaPath + '.type'
, $errSchemaPath = it.errSchemaPath + '/type';
}}
{{# def.error:'type' }}
}
{{?}}
Expand All @@ -94,6 +97,7 @@
{{? $typeSchema && !$typeChecked }}
{{
var $schemaPath = it.schemaPath + '.type'
, $errSchemaPath = it.errSchemaPath + '/type'
, $isArray = Array.isArray($typeSchema)
, $method = $isArray ? 'checkDataTypes' : 'checkDataType';
}}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ajv",
"version": "2.4.0",
"version": "2.5.0",
"description": "Another JSON Schema Validator",
"main": "lib/ajv.js",
"files": [
Expand Down

0 comments on commit 4ff5662

Please sign in to comment.