From 1b115fd46343bdf697f7eb0e00697863cce9989b Mon Sep 17 00:00:00 2001 From: Ousama Ben Younes Date: Sun, 12 Apr 2026 22:32:25 +0000 Subject: [PATCH] fix: enable case-insensitive array comparison in jsonLogic operators The ==, ===, !=, and !== operators compared arrays by reference (JS default), so two arrays with identical normalized values would always mismatch. Added an areEqual helper that compares normalized arrays element-by-element, and unskipped the previously-failing test. Generated by Claude Code Vibe coded by ousamabenyounes Co-Authored-By: Claude --- packages/lib/raqb/jsonLogic.test.ts | 59 ++++++++++++++++++++++++++++- packages/lib/raqb/jsonLogic.ts | 20 ++++++++-- 2 files changed, 74 insertions(+), 5 deletions(-) diff --git a/packages/lib/raqb/jsonLogic.test.ts b/packages/lib/raqb/jsonLogic.test.ts index 72a0f80a62a594..e9d8d3e3483202 100644 --- a/packages/lib/raqb/jsonLogic.test.ts +++ b/packages/lib/raqb/jsonLogic.test.ts @@ -9,7 +9,7 @@ describe("jsonLogic", () => { expect(jsonLogic.apply({ "==": ["hello", "world"] })).toBe(false); }); - it.skip("should compare arrays case-insensitively", () => { + it("should compare arrays case-insensitively", () => { expect( jsonLogic.apply({ "==": [ @@ -34,6 +34,25 @@ describe("jsonLogic", () => { expect(jsonLogic.apply({ "===": ["hello", "HELLO"] })).toBe(true); expect(jsonLogic.apply({ "===": ["hello", "world"] })).toBe(false); }); + + it("should compare arrays case-insensitively", () => { + expect( + jsonLogic.apply({ + "===": [ + ["hello", "WORLD"], + ["HELLO", "world"], + ], + }) + ).toBe(true); + expect( + jsonLogic.apply({ + "===": [ + ["hello"], + ["hello", "world"], + ], + }) + ).toBe(false); + }); }); describe("!== operation", () => { @@ -41,6 +60,25 @@ describe("jsonLogic", () => { expect(jsonLogic.apply({ "!==": ["hello", "HELLO"] })).toBe(false); expect(jsonLogic.apply({ "!==": ["hello", "world"] })).toBe(true); }); + + it("should compare arrays case-insensitively", () => { + expect( + jsonLogic.apply({ + "!==": [ + ["hello", "WORLD"], + ["HELLO", "world"], + ], + }) + ).toBe(false); + expect( + jsonLogic.apply({ + "!==": [ + ["hello"], + ["hi"], + ], + }) + ).toBe(true); + }); }); describe("!= operation", () => { @@ -48,6 +86,25 @@ describe("jsonLogic", () => { expect(jsonLogic.apply({ "!=": ["hello", "HELLO"] })).toBe(false); expect(jsonLogic.apply({ "!=": ["hello", "world"] })).toBe(true); }); + + it("should compare arrays case-insensitively", () => { + expect( + jsonLogic.apply({ + "!=": [ + ["hello", "WORLD"], + ["HELLO", "world"], + ], + }) + ).toBe(false); + expect( + jsonLogic.apply({ + "!=": [ + ["a", "b"], + ["c", "d"], + ], + }) + ).toBe(true); + }); }); describe("in operation", () => { diff --git a/packages/lib/raqb/jsonLogic.ts b/packages/lib/raqb/jsonLogic.ts index f3edbb03725982..6cf6b9f6f5cf7e 100644 --- a/packages/lib/raqb/jsonLogic.ts +++ b/packages/lib/raqb/jsonLogic.ts @@ -18,24 +18,36 @@ function normalize(input: T): T { return input; } +// JS == and === compare array references, not values. +// This compares normalized arrays element-by-element. +function areEqual(a: any, b: any): boolean { + const na = normalize(a); + const nb = normalize(b); + if (Array.isArray(na) && Array.isArray(nb)) { + if (na.length !== nb.length) return false; + return na.every((val: any, i: number) => val === nb[i]); + } + return na === nb; +} + /** * Single Select equals and not equals uses it * Short Text equals and not equals uses it */ jsonLogic.add_operation("==", function (a: any, b: any) { - return normalize(a) == normalize(b); + return areEqual(a, b); }); jsonLogic.add_operation("===", function (a: any, b: any) { - return normalize(a) === normalize(b); + return areEqual(a, b); }); jsonLogic.add_operation("!==", function (a: any, b: any) { - return normalize(a) !== normalize(b); + return !areEqual(a, b); }); jsonLogic.add_operation("!=", function (a: any, b: any) { - return normalize(a) != normalize(b); + return !areEqual(a, b); }); /**