Skip to content

fix(evaluate): make <= and >= yield true when both operands are Nothing - #150

Merged
char0n merged 1 commit into
mainfrom
fix/nothing-non-strict-comparison
Sep 15, 2026
Merged

char0n merged 1 commit into
mainfrom
fix/nothing-non-strict-comparison

Conversation

@char0n

@char0n char0n commented Sep 15, 2026

Copy link
Copy Markdown
Member

Fixes #144

Problem

When both operands of a comparison resolve to Nothing (for example two absent members), == selected the node but <= and >= did not:

evaluate([{}], '$[?@.a == @.b]'); // [{}]
evaluate([{}], '$[?@.a <= @.b]'); // []   expected [{}]
evaluate([{}], '$[?@.a >= @.b]'); // []   expected [{}]

RFC 9535 §2.3.5.2.2 defines the non-strict operators by composition: a <= b is true iff a < b or a == b, and a >= b is true iff b < a or a == b. Since Nothing == Nothing is true, both non-strict comparisons must hold. The RFC's own example table in §2.3.5.3 lists $.absent1 <= $.absent2 as true with the comment "== implies <=".

Cause

JSONEvaluationRealm.compare() returned false early from the <= and >= branches whenever either side was Nothing, before reaching the deep equality fallback at the end of each branch.

Fix

Remove the early return from the <= and >= branches only. The number and string checks don't match undefined, so the branch falls through to deep equality, which already returns true for Nothing vs Nothing and false for Nothing vs a value. Strict < and > are unchanged and still reject Nothing.

Why the compliance suite didn't catch it

Every <=/>= test in the JSONPath Compliance Test Suite compares members that both exist, and the Nothing-related tests only use ==/!=. The RFC §2.3.5.3 example table was never transcribed into the suite. A new test/evaluate/comparison.js covers all six operators with Nothing on both sides and on one side only.

Verification

  • Reporter's reproduction now returns [{}] for ==, <=, >= and [] for !=, <, >.
  • All five absent-member rows of the RFC §2.3.5.3 table now match.
  • Full suite passes (1314 tests, compliance suite included).

RFC 9535 Section 2.3.5.2.2 defines a <= b as (a < b) or (a == b), and
a >= b as (b < a) or (a == b). Since Nothing == Nothing is true, the
non-strict comparisons must also be true when both sides are Nothing.
The RFC example table in Section 2.3.5.3 lists $.absent1 <= $.absent2
as true for this reason.

The JSON realm returned false early from the <= and >= branches whenever
either side was Nothing, before reaching the equality fallback. Remove
that early return so the branches fall through to deep equality, which
already handles Nothing correctly. Strict < and > are unchanged.

Refs #144
@char0n
char0n merged commit c3d6b30 into main Sep 15, 2026
4 checks passed
@char0n
char0n deleted the fix/nothing-non-strict-comparison branch September 15, 2026 10:19
char0n pushed a commit that referenced this pull request Sep 15, 2026
## [4.0.5](v4.0.4...v4.0.5) (2026-09-15)

### Bug Fixes

* **evaluate:** make <= and >= yield true when both operands are Nothing ([#150](#150)) ([c3d6b30](c3d6b30)), closes [#144](#144)
@char0n

char0n commented Sep 15, 2026

Copy link
Copy Markdown
Member Author

🎉 This PR is included in version 4.0.5 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

char0n added a commit to speclynx/apidom that referenced this pull request Sep 15, 2026
)

RFC 9535 §2.3.5.2.2 defines the non-strict comparison operators by
composition: `a <= b` holds iff `a < b` or `a == b`. Since Nothing ==
Nothing is true, `<=` and `>=` must also hold when both operands are
absent. The ApiDOM realm returned false for these cases before reaching
the equality check. Strict `<` and `>` are unchanged.

Ports swaggerexpert/jsonpath#150.

Signed-off-by: Vladimir Gorej <vladimir.gorej@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Non-strict comparisons return false when both operands are Nothing

1 participant