Skip to content

Commit 80e64bc

Browse files
committed
feat: deepProperties keyword
1 parent d0c14ff commit 80e64bc

File tree

5 files changed

+440
-1
lines changed

5 files changed

+440
-1
lines changed

README.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Custom JSON-Schema keywords for [ajv](https://github.com/epoberezkin/ajv) valida
1818
- [range and exclusiveRange](#range-and-exclusiverange)
1919
- [propertyNames](#propertynames)
2020
- [if/then/else](#ifthenelse)
21+
- [deepProperties](#deepproperties)
2122
- [deepRequired](#deeprequired)
2223
- [regexp](#regexp)
2324
- [dynamicDefaults](#dynamicdefaults)
@@ -226,6 +227,58 @@ var invalidData = {
226227
See [json-schema-org/json-schema-spec#203](https://github.com/json-schema-org/json-schema-spec/issues/203#issue-197211916) for an example of the equivalent schema without `deepRequired` keyword.
227228

228229

230+
## `deepProperties`
231+
232+
This keyword allows to validate deep properties (identified by JSON pointers). The value should be an object, where keys are JSON pointers to the data, starting from the current position in data, and the values are corresponding schemas.
233+
234+
```javascript
235+
var schema = {
236+
type: 'object',
237+
deepProperties: {
238+
"users/1/role": { "enum": ["admin"] }
239+
}
240+
};
241+
242+
var validData = {
243+
users: [
244+
{},
245+
{
246+
id: 123,
247+
role: 'admin'
248+
}
249+
]
250+
};
251+
252+
var alsoValidData = {
253+
users: {
254+
"1": {
255+
id: 123,
256+
role: 'admin'
257+
}
258+
}
259+
};
260+
261+
var invalidData = {
262+
users: [
263+
{},
264+
{
265+
id: 123,
266+
role: 'user'
267+
}
268+
]
269+
};
270+
271+
var alsoInvalidData = {
272+
users: {
273+
"1": {
274+
id: 123,
275+
role: 'user'
276+
}
277+
}
278+
};
279+
```
280+
281+
229282
### `regexp`
230283

231284
This keyword allows to use regular expressions with flags in schemas (the standard `pattern` keyword does not support flags). The value of this keyword can be either a string (the result of `regexp.toString()`) or an object with the properties `pattern` and `flags` (the same strings that should be passed to RegExp constructor).

keywords/deepProperties.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
'use strict';
2+
3+
module.exports = function defFunc(ajv) {
4+
defFunc.definition = {
5+
type: 'object',
6+
macro: function (schema) {
7+
var schemas = [];
8+
for (var pointer in schema)
9+
schemas.push(getSchema(pointer, schema[pointer]));
10+
return { 'allOf': schemas };
11+
}
12+
};
13+
14+
ajv.addKeyword('deepProperties', defFunc.definition);
15+
return ajv;
16+
};
17+
18+
19+
function getSchema(jsonPointer, schema) {
20+
var segments = jsonPointer.split('/');
21+
var rootSchema = {};
22+
var pointerSchema = rootSchema;
23+
for (var i=1; i<segments.length; i++) {
24+
var segment = segments[i];
25+
var isLast = i == segments.length - 1;
26+
segment = unescapeJsonPointer(segment);
27+
var properties = pointerSchema.properties = {};
28+
var items = undefined;
29+
if (/[0-9]+/.test(segment)) {
30+
var count = +segment;
31+
items = pointerSchema.items = [];
32+
while (count--) items.push({});
33+
}
34+
pointerSchema = isLast ? schema : {};
35+
properties[segment] = pointerSchema;
36+
if (items) items.push(pointerSchema);
37+
}
38+
return rootSchema;
39+
}
40+
41+
42+
function unescapeJsonPointer(str) {
43+
return str.replace(/~1/g, '/').replace(/~0/g, '~');
44+
}

keywords/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ module.exports = {
88
'typeof': require('./typeof'),
99
dynamicDefaults: require('./dynamicDefaults'),
1010
'if': require('./if'),
11+
deepProperties: require('./deepProperties'),
1112
deepRequired: require('./deepRequired')
1213
// formatMinimum: require('./formatMinimum'),
1314
// formatMaximum: require('./formatMaximum'),

spec/schema-tests.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ var defineKeywords = require('..');
77
var ajvs = [
88
// defineKeywords(getAjv(),
99
// ['switch', 'patternRequired', 'formatMinimum', 'formatMaximum']),
10-
defineKeywords(getAjv(), ['if', 'deepRequired']),
10+
defineKeywords(getAjv(), ['if', 'deepRequired', 'deepProperties']),
1111
defineKeywords(getAjv()),
1212
defineKeywords(getAjv(true))
1313
];

0 commit comments

Comments
 (0)