Fix ?: operator returning wrong result when LHS has array predicate#780
Merged
andrew-coleman merged 1 commit intojsonata-js:masterfrom Apr 29, 2026
Merged
Conversation
The ?: infix handler reused the same `left` AST node reference for both the `condition` and the `then` branch. During AST post-processing, this caused the same node to be mutated twice — filter stages were pushed onto the shared node twice (turning e.g. `array[1]` into `array[1][1]`) and the unary-minus folding on number literals was applied twice (turning e.g. `-5` back into `5`). Deep-clone `left` for the condition argument so the two branches have independent AST nodes. This mirrors the fix applied to the `??` operator in jsonata-js#774 / commit fd47061 (closing jsonata-js#773). Includes new test cases under default-operator covering array predicates (positive index, out-of-range, negative index on multi-/single-element arrays) and unary-minus literal LHS. Signed-off-by: Leo Garbe <leo@respark.dev> Made-with: Cursor
andrew-coleman
approved these changes
Apr 29, 2026
Member
andrew-coleman
left a comment
There was a problem hiding this comment.
Looks good. Thank you!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Quick Note
We are using JSONata quite extensively over at Ambivio and love it!
But we have noticed some issues like this one.
Please review these changes carefully as they have been AI-assisted and I don't have a deep understanding of JSONatas parsing logic.
Summary
The
?:(elvis/default) operator returns the wrong value whenever its left-hand side is an array predicate or a negative numeric literal. For example:[true][-1] ?: "no"true"no"[1,2,3][-1] ?: "no"32array[1] ?: "no"(witharray=[10,20])20"no"-5 ?: 99-55Root cause
In
src/parser.js, the?:infix handler stored the sameleftAST node reference into bothconditionandthen:The post-parse
processASTstep then walks both branches, butprocessASTmutates the AST it receives:[(predicate) handler pushes afilterstage onto the LHS step. Run twice on the same node, you get two filters — soarray[1]becomes effectivelyarray[1][1].-handler folds-Ninto the underlying number literal by mutating itsvaluein place. Run twice, the negation is undone — so-5becomes5.This is the exact same class of bug that was fixed for the
??operator in #774 / commit fd47061 (closing #773). The fix was never propagated to?:.Fix
Deep-clone
leftfor theconditionbranch so the two branches have independent AST nodes — mirroring the??fix:Tests
Added 5 new test cases under
test/test-suite/groups/default-operator/:case014.json— array predicate on LHS exists, returns LHS valuecase015.json— array predicate on LHS does not exist, returns RHS valuecase016.json— negative array index on multi-element arraycase017.json— negative array index on single-element arraycase018.json— unary minus on number literal LHS is not double-negatedFull suite passes locally: 1768 passing, 100% coverage maintained.
Test plan
npm testpasses (1768 tests)default-operatortests still passSigned-off-by: Leo Garbe leo@respark.dev