From d253cc370b49abd56725cc7d6242d8207d7d49a9 Mon Sep 17 00:00:00 2001 From: Jay Hayes Date: Wed, 16 Aug 2017 19:54:39 -0400 Subject: [PATCH 1/4] Detect circular references and return early --- lib/handlers.js | 6 ++++++ test/query.js | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/lib/handlers.js b/lib/handlers.js index c00e6b0..aa7d6ad 100755 --- a/lib/handlers.js +++ b/lib/handlers.js @@ -192,6 +192,7 @@ function traverser(recurse) { var results = []; + var seen = new Set(); var descend = function(value, path) { if (is_array(value)) { @@ -208,6 +209,11 @@ function traverser(recurse) { } }); } else if (is_object(value)) { + if (seen.has(value)) { + return; + } else { + seen.add(value); + } this.keys(value).forEach(function(k) { if (results.length >= count) { return } if (passable(k, value[k], ref)) { diff --git a/test/query.js b/test/query.js index 6a2a184..7e64852 100644 --- a/test/query.js +++ b/test/query.js @@ -355,5 +355,12 @@ suite('query', function() { assert.deepEqual(jp.query({a: 1, b: 2, c: null}, '$..["a","b","c","d"]'), [1, 2, null]); }); + test('circular reference', function() { + var obj = { foo: 'bar' }; + obj.circularReference = obj; + var results = jp.query(obj, '$..*'); + assert.deepEqual(results, ['bar', obj]); + }); + }); From 4ce22ac8d81f4247a4689761f2c01eb8facecca4 Mon Sep 17 00:00:00 2001 From: Jay Hayes Date: Wed, 16 Aug 2017 20:18:39 -0400 Subject: [PATCH 2/4] Fix bug in circular detection This corrects an issue where non-circular references were falsely detected as _all_ seen objects were stored across the entire recursion. --- lib/handlers.js | 8 ++++---- test/query.js | 7 +++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/handlers.js b/lib/handlers.js index aa7d6ad..52998a0 100755 --- a/lib/handlers.js +++ b/lib/handlers.js @@ -192,8 +192,8 @@ function traverser(recurse) { var results = []; - var seen = new Set(); - var descend = function(value, path) { + var descend = function(value, path, seen) { + seen = new Set(seen) if (is_array(value)) { value.forEach(function(element, index) { @@ -205,7 +205,7 @@ function traverser(recurse) { value.forEach(function(element, index) { if (results.length >= count) { return } if (recurse) { - descend(element, path.concat(index)); + descend(element, path.concat(index), seen); } }); } else if (is_object(value)) { @@ -223,7 +223,7 @@ function traverser(recurse) { this.keys(value).forEach(function(k) { if (results.length >= count) { return } if (recurse) { - descend(value[k], path.concat(k)); + descend(value[k], path.concat(k), seen); } }); } diff --git a/test/query.js b/test/query.js index 7e64852..e0d6cbe 100644 --- a/test/query.js +++ b/test/query.js @@ -360,6 +360,13 @@ suite('query', function() { obj.circularReference = obj; var results = jp.query(obj, '$..*'); assert.deepEqual(results, ['bar', obj]); + + var obj = {}; + var o = { foo: 'bar' } + obj.foo = o + obj.bar = o + var results = jp.query(obj, '$..*'); + assert.deepEqual(results, [o, o, 'bar', 'bar']); }); }); From e3b6bb42369b3980f7aacc294321ce4550939a95 Mon Sep 17 00:00:00 2001 From: Jay Hayes Date: Wed, 16 Aug 2017 20:23:46 -0400 Subject: [PATCH 3/4] =?UTF-8?q?SEMICOLONS=20=D1=89=EF=BC=88=EF=BE=9F=D0=94?= =?UTF-8?q?=EF=BE=9F=D1=89=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/handlers.js | 2 +- test/query.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/handlers.js b/lib/handlers.js index 52998a0..43b0582 100755 --- a/lib/handlers.js +++ b/lib/handlers.js @@ -193,7 +193,7 @@ function traverser(recurse) { var results = []; var descend = function(value, path, seen) { - seen = new Set(seen) + seen = new Set(seen); if (is_array(value)) { value.forEach(function(element, index) { diff --git a/test/query.js b/test/query.js index e0d6cbe..0543668 100644 --- a/test/query.js +++ b/test/query.js @@ -363,8 +363,8 @@ suite('query', function() { var obj = {}; var o = { foo: 'bar' } - obj.foo = o - obj.bar = o + obj.foo = o; + obj.bar = o; var results = jp.query(obj, '$..*'); assert.deepEqual(results, [o, o, 'bar', 'bar']); }); From 12fdd6cfb40a8abbd19d231e6ea7df32f071ac6f Mon Sep 17 00:00:00 2001 From: Jay Hayes Date: Wed, 16 Aug 2017 20:29:32 -0400 Subject: [PATCH 4/4] Use array as Set isn't available in CI version --- lib/handlers.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/handlers.js b/lib/handlers.js index 43b0582..57c7991 100755 --- a/lib/handlers.js +++ b/lib/handlers.js @@ -193,7 +193,7 @@ function traverser(recurse) { var results = []; var descend = function(value, path, seen) { - seen = new Set(seen); + seen = (seen || []).slice() if (is_array(value)) { value.forEach(function(element, index) { @@ -209,10 +209,10 @@ function traverser(recurse) { } }); } else if (is_object(value)) { - if (seen.has(value)) { - return; + if (seen.indexOf(value) === -1) { + seen.push(value); } else { - seen.add(value); + return; } this.keys(value).forEach(function(k) { if (results.length >= count) { return }