From e69a51025efa7dec7d60d0067200a1466988ebbc Mon Sep 17 00:00:00 2001 From: Harttle Date: Fri, 22 Apr 2022 00:26:51 +0800 Subject: [PATCH] fix: support integer arithmetic for `divided_by`, closes #465 --- docs/source/filters/divided_by.md | 19 ++++++++++++++++++- docs/source/zh-cn/filters/divided_by.md | 19 ++++++++++++++++++- src/builtin/filters/math.ts | 2 +- test/e2e/issues.ts | 5 +++++ test/integration/builtin/filters/math.ts | 2 ++ 5 files changed, 44 insertions(+), 3 deletions(-) diff --git a/docs/source/filters/divided_by.md b/docs/source/filters/divided_by.md index 88038f748..13fe10228 100644 --- a/docs/source/filters/divided_by.md +++ b/docs/source/filters/divided_by.md @@ -26,6 +26,23 @@ Output 1.6666666666666667 ``` -{% note info Integer Arithmetic %}Since JavaScript doesn't differentiate integers and floats, LiquidJS is not capable of integer arithmetic and the return type is always `number`, the string representation of which depends on its value.{% endnote %} +In JavaScript, float and integer shares the same type `number` and we cannot tell the difference. For example: + +```javascript +// always true +5.0 === 5 +``` + +You'll need to pass another `integerArithmetic` argument to enforce integer divide: + +Input +```liquid +{{ 5 | divided_by: 3, true }} +``` + +Output +```text +1 +``` [floor]: ./floor.html diff --git a/docs/source/zh-cn/filters/divided_by.md b/docs/source/zh-cn/filters/divided_by.md index aedc2a20a..2eb2d4264 100644 --- a/docs/source/zh-cn/filters/divided_by.md +++ b/docs/source/zh-cn/filters/divided_by.md @@ -26,6 +26,23 @@ title: divided_by 1.6666666666666667 ``` -{% note info Integer Arithmetic %}Since JavaScript doesn't differentiate integers and floats, LiquidJS is not capable of integer arithmetic and the return type is always `number`, the string representation of which depends on its value.{% endnote %} +在 JavaScript 里数字没有浮点和整数的区分,它们的类型都是 `number`: + +```javascript +// always true +5.0 === 5 +``` + +因此如果需要做整数运算,需要传入额外的 `integerArithmetic` 参数: + +Input +```liquid +{{ 5 | divided_by: 3, true }} +``` + +Output +```text +1 +``` [floor]: ./floor.html diff --git a/src/builtin/filters/math.ts b/src/builtin/filters/math.ts index 350fc1735..28be0cf82 100644 --- a/src/builtin/filters/math.ts +++ b/src/builtin/filters/math.ts @@ -4,7 +4,7 @@ export const abs = argumentsToValue(Math.abs) export const atLeast = argumentsToValue(Math.max) export const atMost = argumentsToValue(Math.min) export const ceil = argumentsToValue(Math.ceil) -export const dividedBy = argumentsToValue((v: number, arg: number) => v / arg) +export const dividedBy = argumentsToValue((dividend: number, divisor: number, integerArithmetic = false) => integerArithmetic ? Math.floor(dividend / divisor) : dividend / divisor) export const floor = argumentsToValue(Math.floor) export const minus = argumentsToValue((v: number, arg: number) => v - arg) export const modulo = argumentsToValue((v: number, arg: number) => v % arg) diff --git a/test/e2e/issues.ts b/test/e2e/issues.ts index c56941947..d1e058724 100644 --- a/test/e2e/issues.ts +++ b/test/e2e/issues.ts @@ -199,6 +199,11 @@ describe('Issues', function () { const html = engine.parseAndRenderSync('{{foo | size}}-{{bar.coo}}', { foo: 'foo', bar: Object.create({ coo: 'COO' }) }) expect(html).to.equal('3-') }) + it('#465 Liquidjs divided_by not compatible with Ruby/Shopify Liquid', () => { + const engine = new Liquid({ ownPropertyOnly: true }) + const html = engine.parseAndRenderSync('{{ 5 | divided_by: 3, true }}') + expect(html).to.equal('1') + }) it('#479 url_encode throws on undefined value', async () => { const engine = new Liquid({ strictVariables: false diff --git a/test/integration/builtin/filters/math.ts b/test/integration/builtin/filters/math.ts index 1d1247a48..0220609ea 100644 --- a/test/integration/builtin/filters/math.ts +++ b/test/integration/builtin/filters/math.ts @@ -25,6 +25,8 @@ describe('filters/math', function () { it('should return 2 for 4,2', () => test('{{4 | divided_by: 2}}', '2')) it('should return 4 for 16,4', () => test('{{16 | divided_by: 4}}', '4')) it('should return 1 for 5,3', () => test('{{5 | divided_by: 3}}', (5 / 3).toString())) + it('should support integer arithmetic', () => test('{{5 | divided_by: 3, true}}', '1')) + it('should floor the result in integer arithmetic', () => test('{{ -5 | divided_by: 3, true}}', '-2')) it('should convert string to number', () => test('{{"6" | divided_by: "3"}}', '2')) }) describe('floor', function () {