Skip to content

Commit

Permalink
add safeguard to circular references
Browse files Browse the repository at this point in the history
  • Loading branch information
Joe Harlow committed Feb 8, 2018
1 parent 61c88c1 commit 98edb3b
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 11 deletions.
2 changes: 1 addition & 1 deletion package.json
@@ -1,6 +1,6 @@
{
"name": "@f5io/jsonpath",
"version": "1.0.6",
"version": "1.0.7",
"description": "Performant JSONPath implementation",
"main": "lib/index.js",
"scripts": {
Expand Down
12 changes: 8 additions & 4 deletions src/utils/index.js
Expand Up @@ -39,23 +39,27 @@ export const pathFilter = f => x => {
return output;
}

export const searchFor = (o, p) => {
export const searchFor = (o, p, visited = new Set()) => {
let result = [];
if (visited.has(o)) return result;
visited.add(o);
for (const k in o) {
if (k === p) result = result.concat(o[k]);
if (isPlainObject(o[k]) || Array.isArray(o[k]))
result = result.concat(searchFor(o[k], p));
result = result.concat(searchFor(o[k], p, visited));
}
return result;
}

export const searchForPath = (o, p, ps = []) => {
export const searchForPath = (o, p, ps = [], visited = new Set()) => {
let result = [];
if (visited.has(o)) return result;
visited.add(o);
const coerce = Array.isArray(o) ? Number : x => x;
for (const k in o) {
if (k === p) result = result.concat([ ps.concat(coerce(k)) ]);
if (isPlainObject(o[k]) || Array.isArray(o[k]))
result = result.concat(searchForPath(o[k], p, ps.concat(coerce(k))));
result = result.concat(searchForPath(o[k], p, ps.concat(coerce(k)), visited));
}
return result;
}
Expand Down
35 changes: 29 additions & 6 deletions test/index.js
Expand Up @@ -3,7 +3,7 @@ import query, { paths } from '../src';
import tokenizer from '../src/tokenizer';
import parser from '../src/parser';
import maybe from '../src/maybe';
import { isPlainObject, isObject, searchForPath } from '../src/utils';
import { isPlainObject, isObject } from '../src/utils';

const data = require('./data.json');

Expand Down Expand Up @@ -31,7 +31,7 @@ const runQueries = (test, queries, expected, d = data) => {
const runPaths = (test, queries, expected, d = data) => {
queries.forEach(q => {
const result = measure(`paths: '${q}'`, paths, q, d);
test.deepEquals(result, expected, `'${q}' should return expected paths`);
test.deepEquals(result, expected, `'${q}' should return expected paths`);
});
};

Expand Down Expand Up @@ -69,15 +69,15 @@ test('isPlainObject - constructor not a function', t => {

test('isPlainObject - constructor null prototype', t => {
t.plan(1);
function f() {};
function f() {}
f.prototype = null;
const obj = { constructor: f };
t.notOk(isPlainObject(obj), 'should return false');
});

test('isPlainObject - constructor no isPrototypeOf', t => {
t.plan(1);
function f() {};
function f() {}
delete f.prototype.isPrototypeOf;
const obj = { constructor: f };
t.notOk(isPlainObject(obj), 'should return false');
Expand Down Expand Up @@ -136,7 +136,7 @@ test('simple prop with no prev', t => {
const expected = data.store;
const queries = [
'store'
]
];
const paths = [ [ 'store' ] ];
runQueries(t, queries, expected);
runPaths(t, queries, paths);
Expand Down Expand Up @@ -300,7 +300,7 @@ test('get specific author', t => {
];
const paths = [
[ 'store', 'book', 0, 'author' ]
]
];
runQueries(t, queries, expected);
runPaths(t, queries, paths);
t.end();
Expand Down Expand Up @@ -410,6 +410,29 @@ test('get authors with omember', t => {
t.end();
});

test('circular reference guard', t => {
const foo = {
a: 1,
};
const bar = {
b: 2,
foo,
};
foo.bar = bar;
const data = {
bar,
foo,
};

const expected = [ bar.b ];
const path = [ [ 'bar', 'b' ] ];
t.doesNotThrow(() => query('$..b', data), 'should not throw a stack size exceeded');
t.deepEquals(query('$..b', data), expected, 'should return expected results');
t.doesNotThrow(() => paths('$..b', data), 'should not throw stack size exceeded');
t.deepEquals(paths('$..b', data), path, 'should return expected results');
t.end();
});

test('changejs example', t => {
const expected = [
[ 1, 2, 3 ], [ 4, 5, 6 ],
Expand Down

0 comments on commit 98edb3b

Please sign in to comment.