diff --git a/src/operators/binary/arithmetic.ts b/src/operators/binary/arithmetic.ts index 0aa65128..9a0fbcc9 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 strings and at least one of them in a non-number + + // 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 is 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); + } + + // Otherwise return an error indicating that the values of mixed types cannot be added. + 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 { 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 () {