Fixed #676: JSON Paths containing array properties with a `]` not parsed correctly
This commit is contained in:
parent
7c398aeef7
commit
3e7e1cebfd
|
@ -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
|
||||
|
|
|
@ -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, '');
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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/);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue