Skip to content

Commit

Permalink
Validate v6 filter syntax (fixes #1)
Browse files Browse the repository at this point in the history
  • Loading branch information
jfirebaugh committed Oct 26, 2014
1 parent d9a938e commit 0406c27
Show file tree
Hide file tree
Showing 4 changed files with 183 additions and 9 deletions.
65 changes: 57 additions & 8 deletions lib/validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,51 @@ module.exports = function(str) {
}
};

validate.filter = function(/*key, val, spec*/) {
// TODO
validate.filter = function(key, val) {
if (typeof_(val) !== 'array') {
return error(key, val, 'array expected, %s found', typeof_(val));
}

if (val.length < 1) {
return error(key, val, 'filter array must have at least 1 element');
}

validate.enum(key + '[0]', val[0], reference.filter_operator);

switch (unbundle(val[0])) {
case '==':
case '!=':
case '<':
case '<=':
case '>':
case '>=':
if (val.length != 3) {
error(key, val, 'filter array for operator "%s" must have 3 elements', val[0]);
}
/* falls through */
case 'in':
case '!in':
if (val.length >= 2) {
validate.string(key + '[1]', val[1]);
}
for (var i = 2; i < val.length; i++) {
var type = typeof_(val[i]);
if (val[1] == '$type') {
validate.enum(key + '[' + i + ']', val[i], reference.geometry_type);
} else if (type !== 'string' && type !== 'number' && type !== 'boolean') {
error(key + '[' + i + ']', val[i], 'string, number, or boolean expected, %s found', type);
}
}
break;

case 'any':
case 'all':
case 'none':
for (i = 1; i < val.length; i++) {
validate.filter(key + '[' + i + ']', val[i]);
}
break;
}
};

validate.function = function(key, val, spec) {
Expand Down Expand Up @@ -220,12 +263,18 @@ module.exports = function(str) {
}
};

validate.number = validate.string = validate.boolean = function(key, val, spec) {
var type = typeof_(val);
if (type !== spec.type) {
error(key, val, '%s expected, %s found', spec.type, type);
}
};
function typeValidator(expected) {
return function(key, val) {
var actual = typeof_(val);
if (actual !== expected) {
error(key, val, '%s expected, %s found', expected, actual);
}
};
}

validate.number = typeValidator('number');
validate.string = typeValidator('string');
validate.boolean = typeValidator('boolean');

validate['*'] = function() {};

Expand Down
87 changes: 87 additions & 0 deletions test/fixture/filters.input.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
{
"version": 6,
"sources": {
"source": {
"type": "vector",
"url": "mapbox://mapbox.mapbox-streets-v5"
}
},
"layers": [
{
"id": "not-array",
"type": "line",
"source": "source",
"filter": {}
},
{
"id": "zero-elements",
"type": "line",
"source": "source",
"filter": []
},
{
"id": "invalid-operator",
"type": "line",
"source": "source",
"filter": [
"=",
"key",
"value"
]
},
{
"id": "missing-key",
"type": "line",
"source": "source",
"filter": ["=="]
},
{
"id": "missing-value",
"type": "line",
"source": "source",
"filter": [
"==",
"key"
]
},
{
"id": "invalid-key",
"type": "line",
"source": "source",
"filter": [
"==",
1,
"value"
]
},
{
"id": "invalid-value",
"type": "line",
"source": "source",
"filter": [
"==",
"key",
[]
]
},
{
"id": "invalid-type",
"type": "line",
"source": "source",
"filter": [
"==",
"$type",
"value"
]
},
{
"id": "invalid-nested-filter",
"type": "line",
"source": "source",
"filter": [
"any",
[]
]
}
]
}
38 changes: 38 additions & 0 deletions test/fixture/filters.output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
[
{
"line": 14,
"message": "layers[0].filter: array expected, object found"
},
{
"line": 20,
"message": "layers[1].filter: filter array must have at least 1 element"
},
{
"line": 27,
"message": "layers[2].filter[0]: expected one of [==, !=, >, >=, <, <=, in, !in, all, any, none], = found"
},
{
"line": 36,
"message": "layers[3].filter: filter array for operator \"==\" must have 3 elements"
},
{
"line": 42,
"message": "layers[4].filter: filter array for operator \"==\" must have 3 elements"
},
{
"line": 53,
"message": "layers[5].filter[1]: string expected, number found"
},
{
"line": 64,
"message": "layers[6].filter[2]: string, number, or boolean expected, array found"
},
{
"line": 74,
"message": "layers[7].filter[2]: expected one of [Point, LineString, Polygon], value found"
},
{
"line": 83,
"message": "layers[8].filter[1]: filter array must have at least 1 element"
}
]
2 changes: 1 addition & 1 deletion test/fixture/layers.input.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"type": "line",
"source": "vector",
"source-layer": "source-layer",
"filter": [],
"filter": ["any"],
"render": {}
},
{
Expand Down

0 comments on commit 0406c27

Please sign in to comment.