From ec50ecb53156330c6e3a272f37bced4a29f3c786 Mon Sep 17 00:00:00 2001 From: James Prior Date: Fri, 15 Mar 2024 20:51:23 +0000 Subject: [PATCH] Fix nondeterministic descent visitor --- src/path/selectors.ts | 75 +++++++++++++++++++------------------------ tests/path/cts | 2 +- 2 files changed, 34 insertions(+), 43 deletions(-) diff --git a/src/path/selectors.ts b/src/path/selectors.ts index 09afaa3..5876f5b 100644 --- a/src/path/selectors.ts +++ b/src/path/selectors.ts @@ -447,55 +447,46 @@ export class RecursiveDescentSegment extends JSONPathSelector { // eslint-disable-next-line sonarjs/cognitive-complexity protected nondeterministicVisitor( - node: JSONPathNode, - depth: number = 1, + root: JSONPathNode, + _: number = 1, ): JSONPathNode[] { - if (depth >= this.environment.maxRecursionDepth) { - throw new JSONPathRecursionLimitError( - "recursion limit reached", - this.token, - ); - } - const rv: JSONPathNode[] = []; - if (node.value instanceof String) return rv; - if (isArray(node.value)) { - const deferredChildren: JSONPathNode[] = []; + function children(node: JSONPathNode): JSONPathNode[] { + const _rv: JSONPathNode[] = []; + if (node.value instanceof String) return rv; + if (isArray(node.value)) { + for (let i = 0; i < node.value.length; i++) { + _rv.push( + new JSONPathNode(node.value[i], node.location.concat(i), node.root), + ); + } + } else if (isObject(node.value)) { + for (const [key, value] of Object.entries(node.value)) { + _rv.push( + new JSONPathNode(value, node.location.concat(key), node.root), + ); + } + } - for (let i = 0; i < node.value.length; i++) { - const _node = new JSONPathNode( - node.value[i], - node.location.concat(i), - node.root, - ); + return _rv; + } - rv.push(_node); + const queue: JSONPathNode[] = children(root); + const rv: JSONPathNode[] = []; - for (const __node of this.nondeterministicVisitor(_node, depth + 1)) { - // Randomly choose to defer inclusion of this child node. - if (Math.random() < 0.5) { - deferredChildren.push(__node); - } else { - rv.push(__node); + while (queue.length) { + const node = queue.shift() as JSONPathNode; + rv.push(node); + for (const child of children(node)) { + // Queue the child node or visit now? + if (Math.random() < 0.5) { + queue.push(child); + } else { + rv.push(child); + for (const _child of children(child)) { + queue.push(_child); } } } - - // Include deferred children. - for (const child of deferredChildren) { - rv.push(child); - } - } else if (isObject(node.value)) { - for (const [key, value] of this.environment.entries(node.value)) { - const _node = new JSONPathNode( - value, - node.location.concat(key), - node.root, - ); - rv.push(_node); - for (const __node of this.nondeterministicVisitor(_node, depth + 1)) { - rv.push(__node); - } - } } return rv; diff --git a/tests/path/cts b/tests/path/cts index 1d03dc6..31dec17 160000 --- a/tests/path/cts +++ b/tests/path/cts @@ -1 +1 @@ -Subproject commit 1d03dc60c0d672e955d0a44789b7b67703a90123 +Subproject commit 31dec1720dc9b9d3e8af3c61f025da93ceb6c9d1