dchester / jsonpath

Query and manipulate JavaScript objects with JSONPath expressions. Robust JSONPath engine for Node.js.
MIT License
1.35k stars 216 forks source link

Replace `@` and `$` with valid javascript names before evaluation #167

Closed Cimbali closed 1 year ago

Cimbali commented 2 years ago

This is a simple yet safe traversal of the AST after it is parsed and before it is evaluated, replacing JsonPath spec-defined names @ and $ with valid names (__jsonpath_current and __jsonpath_root, but they could be any names).

This allows functions that are evaluatable statically by static-eval to work, e.g. have a script that does (@.map(function(x) { x + 1 })) as part of its computations. Previously, the evaluation of such functions failed, as the variable names are used inside static-eval to define a proper scope for the function, and this causes an error due to the variable names being invalid.

A simple example or test could be for example:

jp.query({foo: [1, 2, 3]}, '$.foo[(@.findIndex(function(x) { return x == 2 }))]')
Error: Parse error on line 1:
$[undefined]
--^
Expecting 'STAR', 'SCRIPT_EXPRESSION', 'INTEGER', 'ARRAY_SLICE', 'FILTER_EXPRESSION', 'QQ_STRING', 'Q_STRING', got 'IDENTIFIER'
[…]

This should return the same as the following:

jp.query({foo: [1, 2, 3]}, '$.foo[(@.indexOf(2))]')
[ 2 ]

With this PR it does:

jp.query({foo: [1, 2, 3]}, '$.foo[(@.findIndex(function(x) { return x == 2 }))]')
[ 2 ]

This opens the door to more interesting stuff, e.g. find the first even number:

jp.query({foo: [1, 2, 3]}, '$.foo[(@.findIndex(function(x) { return x % 2 == 0 }))]')
[ 2 ]