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.
This commit is contained in:
spokodev
2026-06-26 01:19:59 +08:00
committed by GitHub
parent ed489865b6
commit 568bd5f9cb
2 changed files with 4 additions and 1 deletions
+1 -1
View File
@@ -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) {
+3
View File
@@ -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'))