From 568bd5f9cb99f596292c09fd70b00284b8216f0c Mon Sep 17 00:00:00 2001 From: spokodev Date: Thu, 25 Jun 2026 18:19:59 +0100 Subject: [PATCH] fix(filters): modulo should follow divisor sign for negative operands (#922) The `modulo` filter used JavaScript's `%` (truncated remainder, sign follows the dividend). Shopify/Ruby Liquid uses floored modulo, where the result takes the sign of the divisor. Since liquidjs advertises Shopify compatibility, negative operands produced the wrong sign. Use `((v % arg) + arg) % arg` to match Ruby's `%`. Positive-operand results are unchanged. --- src/filters/math.ts | 2 +- test/integration/filters/math.spec.ts | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/filters/math.ts b/src/filters/math.ts index cb6775bff..61b8e5a95 100644 --- a/src/filters/math.ts +++ b/src/filters/math.ts @@ -8,7 +8,7 @@ export const divided_by = argumentsToNumber((dividend: number, divisor: number, export const floor = argumentsToNumber(Math.floor) export const minus = argumentsToNumber((v: number, arg: number) => v - arg) export const plus = argumentsToNumber((lhs: number, rhs: number) => lhs + rhs) -export const modulo = argumentsToNumber((v: number, arg: number) => v % arg) +export const modulo = argumentsToNumber((v: number, arg: number) => ((v % arg) + arg) % arg) export const times = argumentsToNumber((v: number, arg: number) => v * arg) export function round (v: number, arg = 0) { diff --git a/test/integration/filters/math.spec.ts b/test/integration/filters/math.spec.ts index ab52cb4be..3f4f7ba0a 100644 --- a/test/integration/filters/math.spec.ts +++ b/test/integration/filters/math.spec.ts @@ -50,6 +50,9 @@ describe('filters/math', function () { expect(Number(html)).toBeCloseTo(3.357, 3) }) it('should convert string', () => test('{{ "24" | modulo: "7" }}', '3')) + it('should follow divisor sign for negative dividend', () => test('{{ -7 | modulo: 3 }}', '2')) + it('should follow divisor sign for negative divisor', () => test('{{ 7 | modulo: -3 }}', '-2')) + it('should follow divisor sign for negative float', () => test('{{ -4.5 | modulo: 3 }}', '1.5')) }) describe('plus', function () { it('should return "6" for 4,2', () => test('{{ 4 | plus: 2 }}', '6'))