Fixed #676: JSON Paths containing array properties with a `]` not parsed correctly

This commit is contained in:
jos 2019-03-20 17:34:39 +01:00
parent 7c398aeef7
commit 3e7e1cebfd
4 changed files with 80 additions and 36 deletions

View File

@ -9,6 +9,8 @@ https://github.com/josdejong/jsoneditor
styling can be applied for default and non-default values. Thanks @AdamVig.
- Fixed #667: resolving JSON Schema examples and descriptions did not always
work for referenced schemas. Thanks @AdamVig.
- Fixed #676: JSON Paths containing array properties with a `]` not parsed
correctly.
## 2019-03-14, version 5.31.1

View File

@ -43,3 +43,10 @@ if (!Array.prototype.find) {
}
}
}
// Polyfill for String.trim
if (!String.prototype.trim) {
String.prototype.trim = function () {
return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
};
}

View File

@ -742,43 +742,75 @@ exports.isChildOf = function (elem, parent) {
* @return {Array}
*/
exports.parsePath = function parsePath(jsonPath) {
var prop, remainder;
var path = [];
var i = 0;
if (jsonPath.length === 0) {
return [];
}
// find a match like '.prop'
var match = jsonPath.match(/^\.([\w$]+)/);
if (match) {
prop = match[1];
remainder = jsonPath.substr(prop.length + 1);
}
else if (jsonPath[0] === '[') {
// find a match like
var end = jsonPath.indexOf(']');
if (end === -1) {
throw new SyntaxError('Character ] expected in path');
}
if (end === 1) {
throw new SyntaxError('Index expected after [');
function parseProperty () {
var prop = ''
while (jsonPath[i] !== undefined && /[\w$]/.test(jsonPath[i])) {
prop += jsonPath[i];
i++;
}
var value = jsonPath.substring(1, end);
if (value[0] === '\'') {
// ajv produces string prop names with single quotes, so we need
// to reformat them into valid double-quoted JSON strings
value = '\"' + value.substring(1, value.length - 1) + '\"';
if (prop === '') {
throw new Error('Invalid JSON path: property name expected at index ' + i);
}
prop = value === '*' ? value : JSON.parse(value); // parse string and number
remainder = jsonPath.substr(end + 1);
}
else {
throw new SyntaxError('Failed to parse path');
return prop;
}
return [prop].concat(parsePath(remainder))
function parseIndex (end) {
var name = ''
while (jsonPath[i] !== undefined && jsonPath[i] !== end) {
name += jsonPath[i];
i++;
}
if (jsonPath[i] !== end) {
throw new Error('Invalid JSON path: unexpected end, character ' + end + ' expected')
}
return name;
}
while (jsonPath[i] !== undefined) {
if (jsonPath[i] === '.') {
i++;
path.push(parseProperty());
}
else if (i > 0 && jsonPath[i] === '[') {
i++;
if (jsonPath[i] === '\'' || jsonPath[i] === '"') {
var end = jsonPath[i]
i++;
path.push(parseIndex(end));
if (jsonPath[i] !== end) {
throw new Error('Invalid JSON path: closing quote \' expected at index ' + i)
}
i++;
}
else {
var index = parseIndex(']').trim()
if (index.length === 0) {
throw new Error('Invalid JSON path: array value expected at index ' + i)
}
path.push(index);
}
if (jsonPath[i] !== ']') {
throw new Error('Invalid JSON path: closing bracket ] expected at index ' + i)
}
i++;
}
else {
throw new Error('Invalid JSON path: unexpected character "' + jsonPath[i] + '" at index ' + i);
}
}
return path;
};
/**

View File

@ -105,16 +105,19 @@ describe('util', function () {
assert.deepEqual(util.parsePath('.foo[2].bar'), ['foo', 2, 'bar']);
assert.deepEqual(util.parsePath('.foo["prop with spaces"]'), ['foo', 'prop with spaces']);
assert.deepEqual(util.parsePath('.foo[\'prop with single quotes as outputted by ajv library\']'), ['foo', 'prop with single quotes as outputted by ajv library']);
assert.deepEqual(util.parsePath('.foo["prop with . dot"]'), ['foo', 'prop with . dot']);
assert.deepEqual(util.parsePath('.foo["prop with ] character"]'), ['foo', 'prop with ] character']);
assert.deepEqual(util.parsePath('.foo[*].bar'), ['foo', '*', 'bar']);
});
it ('should throw an exception in case of an invalid path', function () {
assert.throws(function () {util.parsePath('.')}, /Error/);
assert.throws(function () {util.parsePath('[')}, /Error/);
assert.throws(function () {util.parsePath('[]')}, /Error/);
assert.throws(function () {util.parsePath('.[]')}, /Error/);
assert.throws(function () {util.parsePath('["23]')}, /Error/);
assert.throws(function () {util.parsePath('.foo bar')}, /Error/);
assert.throws(function () {util.parsePath('.')}, /Invalid JSON path: property name expected at index 1/);
assert.throws(function () {util.parsePath('[')}, /Invalid JSON path: unexpected character "\[" at index 0/);
assert.throws(function () {util.parsePath('[]')}, /Invalid JSON path: unexpected character "\[" at index 0/);
assert.throws(function () {util.parsePath('.foo[ ]')}, /Invalid JSON path: array value expected at index 7/);
assert.throws(function () {util.parsePath('.[]')}, /Invalid JSON path: property name expected at index 1/);
assert.throws(function () {util.parsePath('["23]')}, /Invalid JSON path: unexpected character "\[" at index 0/);
assert.throws(function () {util.parsePath('.foo bar')}, /Invalid JSON path: unexpected character " " at index 4/);
});
});