From 900ea727f0c86cb332d53e9621b197235d1135b0 Mon Sep 17 00:00:00 2001 From: Sander Toonen Date: Tue, 20 Jan 2026 15:42:55 +0100 Subject: [PATCH 1/5] Allow the + operator to work with more types. Throw error on incompatible types --- src/operators/binary/arithmetic.ts | 33 +++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/operators/binary/arithmetic.ts b/src/operators/binary/arithmetic.ts index 0aa65128..06255aca 100644 --- a/src/operators/binary/arithmetic.ts +++ b/src/operators/binary/arithmetic.ts @@ -8,18 +8,45 @@ export function add(a: any, b: any): any { if (a === undefined || b === undefined) { return undefined; } + + // If both values are numbers then we want to add the numbers. + if (typeof a === 'number' && typeof b === 'number') { + return a + b; + } + // If both values are strings and at least one of them in a non-number // then we want to concatenate the strings. if (typeof a === 'string' && typeof b === 'string') { const numA = Number(a); const numB = Number(b); + if (isNaN(numA) || isNaN(numB)) { - return a + b; + return `${a}${b}`; } } - // Add the numeric values. - return Number(a) + Number(b); + // If both values are arrays then we want to concatenate the arrays. + if (Array.isArray(a) && Array.isArray(b)) { + return a.concat(b); + } + + // If both values are objects then we want to merge the objects. + if ( + typeof a === 'object' && + typeof b === 'object' && + !Array.isArray(a) && + !Array.isArray(b) + ) { + return { ...a, ...b }; + } + + // If both values can be converted to numbers then we want to add the numbers. + if (!isNaN(Number(a)) && !isNaN(Number(b))) { + return Number(a) + Number(b); + } + + // Otherwhise return an error indicating that the values of mixed types cannot be added. + throw new Error(`Cannot add values of different types: ${typeof a} and ${typeof b}`); } export function sub(a: number | undefined, b: number | undefined): number | undefined { From 059a01d60c5dd1f5c016f9fad99d583530638869 Mon Sep 17 00:00:00 2001 From: Sander Toonen Date: Tue, 20 Jan 2026 15:58:47 +0100 Subject: [PATCH 2/5] Update src/operators/binary/arithmetic.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/operators/binary/arithmetic.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/operators/binary/arithmetic.ts b/src/operators/binary/arithmetic.ts index 06255aca..fcbe2705 100644 --- a/src/operators/binary/arithmetic.ts +++ b/src/operators/binary/arithmetic.ts @@ -45,7 +45,7 @@ export function add(a: any, b: any): any { return Number(a) + Number(b); } - // Otherwhise return an error indicating that the values of mixed types cannot be added. + // Otherwise return an error indicating that the values of mixed types cannot be added. throw new Error(`Cannot add values of different types: ${typeof a} and ${typeof b}`); } From c32b3ab7eceeec6eee54ebb83a0433977135afb8 Mon Sep 17 00:00:00 2001 From: Sander Toonen Date: Tue, 20 Jan 2026 16:00:04 +0100 Subject: [PATCH 3/5] Update src/operators/binary/arithmetic.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/operators/binary/arithmetic.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/operators/binary/arithmetic.ts b/src/operators/binary/arithmetic.ts index fcbe2705..b660e422 100644 --- a/src/operators/binary/arithmetic.ts +++ b/src/operators/binary/arithmetic.ts @@ -46,7 +46,7 @@ export function add(a: any, b: any): any { } // Otherwise return an error indicating that the values of mixed types cannot be added. - throw new Error(`Cannot add values of different types: ${typeof a} and ${typeof b}`); + throw new Error(`Cannot add values of incompatible types: ${typeof a} and ${typeof b}`); } export function sub(a: number | undefined, b: number | undefined): number | undefined { From cedeafd39bf2617619fbec8f3489e014bfa4844e Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 16:14:56 +0100 Subject: [PATCH 4/5] Add comprehensive test coverage for add operator's type handling (#19) * Add comprehensive unit tests for add function covering all branches Co-authored-by: Sander-Toonen <5106372+Sander-Toonen@users.noreply.github.com> --- test/functions/functions-binary-ops.ts | 46 ++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/test/functions/functions-binary-ops.ts b/test/functions/functions-binary-ops.ts index 53d47a51..12aaa5a5 100644 --- a/test/functions/functions-binary-ops.ts +++ b/test/functions/functions-binary-ops.ts @@ -16,6 +16,52 @@ describe('Binary Operators TypeScript Test', function () { assert.strictEqual(parser.evaluate('2 + undefined'), undefined); assert.strictEqual(parser.evaluate('undefined + 2'), undefined); }); + it('should concatenate non-numeric strings', function () { + const parser = new Parser(); + assert.strictEqual(parser.evaluate('"hello" + "world"'), 'helloworld'); + assert.strictEqual(parser.evaluate('"foo" + "bar"'), 'foobar'); + assert.strictEqual(parser.evaluate('"test" + "123"'), 'test123'); + }); + it('should add numeric strings as numbers', function () { + const parser = new Parser(); + assert.strictEqual(parser.evaluate('"5" + "3"'), 8); + assert.strictEqual(parser.evaluate('"10" + "20"'), 30); + assert.strictEqual(parser.evaluate('"0" + "5"'), 5); + }); + it('should concatenate arrays', function () { + const parser = new Parser(); + assert.deepStrictEqual(parser.evaluate('[1, 2] + [3, 4]'), [1, 2, 3, 4]); + assert.deepStrictEqual(parser.evaluate('[1] + [2, 3]'), [1, 2, 3]); + assert.deepStrictEqual(parser.evaluate('[] + [1, 2]'), [1, 2]); + }); + it('should merge objects', function () { + const parser = new Parser(); + assert.deepStrictEqual(parser.evaluate('{a: 1} + {b: 2}'), { a: 1, b: 2 }); + assert.deepStrictEqual(parser.evaluate('{x: 10} + {y: 20}'), { x: 10, y: 20 }); + assert.deepStrictEqual(parser.evaluate('{a: 1, b: 2} + {c: 3}'), { a: 1, b: 2, c: 3 }); + }); + it('should handle object merging with overlapping keys', function () { + const parser = new Parser(); + assert.deepStrictEqual(parser.evaluate('{a: 1} + {a: 2}'), { a: 2 }); + assert.deepStrictEqual(parser.evaluate('{x: 10, y: 20} + {y: 30}'), { x: 10, y: 30 }); + }); + it('should handle null values correctly', function () { + const parser = new Parser(); + assert.deepStrictEqual(parser.evaluate('null + null'), {}); + }); + it('should convert numeric values to numbers before adding', function () { + const parser = new Parser(); + assert.strictEqual(parser.evaluate('true + 1'), 2); + assert.strictEqual(parser.evaluate('false + 5'), 5); + assert.strictEqual(parser.evaluate('1 + true'), 2); + }); + it('should throw error for incompatible types', function () { + const parser = new Parser(); + assert.throws(() => parser.evaluate('5 + [1, 2]'), /Cannot add values of incompatible types/); + assert.throws(() => parser.evaluate('"text" + {a: 1}'), /Cannot add values of incompatible types/); + assert.throws(() => parser.evaluate('[1, 2] + {a: 1}'), /Cannot add values of incompatible types/); + assert.throws(() => parser.evaluate('5 + {x: 1}'), /Cannot add values of incompatible types/); + }); }); describe('- (subtraction)', function () { From 4584092615a47ffeaba1ee04c728b5126d2783b0 Mon Sep 17 00:00:00 2001 From: Sander Toonen Date: Tue, 20 Jan 2026 16:18:19 +0100 Subject: [PATCH 5/5] Update src/operators/binary/arithmetic.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/operators/binary/arithmetic.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/operators/binary/arithmetic.ts b/src/operators/binary/arithmetic.ts index b660e422..9a0fbcc9 100644 --- a/src/operators/binary/arithmetic.ts +++ b/src/operators/binary/arithmetic.ts @@ -14,7 +14,7 @@ export function add(a: any, b: any): any { return a + b; } - // If both values are strings and at least one of them in a non-number + // If both values are strings and at least one of them is a non-number // then we want to concatenate the strings. if (typeof a === 'string' && typeof b === 'string') { const numA = Number(a);