From 5ecca1b761e1a6b643d58310d8e481266f2fef79 Mon Sep 17 00:00:00 2001 From: harttle Date: Tue, 31 Jan 2017 00:07:46 +0800 Subject: [PATCH] feature: greedy trim disabled by default, working on #19 --- README.md | 6 +++--- src/tokenizer.js | 16 ++++++++++++++-- test/liquid.js | 15 +++++++++++---- test/tokenizer.js | 45 +++++++++++++++++++++++++-------------------- 4 files changed, 53 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index ca856ae6f..b8e98b090 100644 --- a/README.md +++ b/README.md @@ -84,11 +84,11 @@ Defaults to `["."]` If set to `false`, undefined variables will be rendered as empty string. Otherwise, undefined variables will cause an exception. Defaults to `false`. -* `trim_right` is used to strip whitespace (including whitespace, tabs, line feeds, etc. which is implemented by ECMA RegExp `\s`) from the right of tags (`{% %}`) and output markups (`{{ }}`). Defaults to `false`. +* `trim_right` is used to strip blank characters (including whitespace, tabs, NL) from the right of tags (`{% %}`) and output markups (`{{ }}`) until `\n` (mandatory and inclusive). Defaults to `false`. +* `trim_left` is similiar to `trim_right`, whereas it trims from the left. Defaults to `false`. See [Whitespace Control][whitespace control] for details. -* `trim_left` is the same with `trim_right`, whereas it trims from the left. Defaults to `false`. See [Whitespace Control][whitespace control] for details. - +* `greedy` is used to specify whether `trim_left`/`trim_right` is greedy. When set to `true`, all blank characters will be trimed before and after, regardless of the occurences of `\n`. Defaults to `false`. ## Use with Express.js diff --git a/src/tokenizer.js b/src/tokenizer.js index ac77490c0..92afe1e67 100644 --- a/src/tokenizer.js +++ b/src/tokenizer.js @@ -73,10 +73,22 @@ function parse(html, filepath, options) { } } + + function whiteSpaceCtrl(html, options){ options = options || {}; - var rLeft = options.trim_left ? /\s+({[{%])/g : /\s+({[{%]-)/g; - var rRight = options.trim_right ? /([}%]})\s+/g : /(-[}%]})\s+/g; + if(options.trim_left) { + html = html + .replace(/{{-?/g, '{{-') + .replace(/{%-?/g, '{%-'); + } + if(options.trim_right) { + html = html + .replace(/-?}}/g, '-}}') + .replace(/-?%}/g, '-%}'); + } + var rLeft = options.greedy ? /\s+({[{%]-)/g : /\n[\t\r ]*({[{%]-)/g; + var rRight = options.greedy ? /(-[}%]})\s+/g : /(-[}%]})[\t\r ]*\n/g; return html.replace(rLeft, '$1').replace(rRight, '$1'); } diff --git a/test/liquid.js b/test/liquid.js index 31b5586b6..f7b0582f1 100644 --- a/test/liquid.js +++ b/test/liquid.js @@ -179,16 +179,23 @@ describe('liquid', function() { engine = Liquid({ trim_left: true }); - return engine.parseAndRender('\n \t{{"foo"}} ') - .should.eventually.equal('foo '); + return engine.parseAndRender(' \n \t{{"foo"}} ') + .should.eventually.equal(' foo '); }); it('should trim_right for tags when trim_right=true', function() { engine = Liquid({ trim_right: true }); - return engine.parseAndRender('\t{{"foo"}} ') + return engine.parseAndRender('\t{{"foo"}} \n') .should.eventually.equal('\tfoo'); }); + it('should trim all blanks before and after when greedy=true', function() { + engine = Liquid({ + greedy: true + }); + return engine.parseAndRender('\t{{-"foo"-}} \n \n') + .should.eventually.equal('foo'); + }); it('should support trim using markup', function() { engine = Liquid(); var src = [ @@ -199,7 +206,7 @@ describe('liquid', function() { ' Hello there!', '{%- endif -%}\n', ].join('\n'); - var dst = 'Wow, John G. Chalmers-Smith, you have a long name!'; + var dst = ' Wow, John G. Chalmers-Smith, you have a long name!'; return engine.parseAndRender(src).should.eventually.equal(dst); }); it('should not trim when not specified', function() { diff --git a/test/tokenizer.js b/test/tokenizer.js index 024d8f648..bce5772d3 100644 --- a/test/tokenizer.js +++ b/test/tokenizer.js @@ -58,43 +58,48 @@ describe('tokenizer', function() { }); }); describe('whitespace control', function() { - it('should strip left whitespaces', function() { - expect(whiteSpaceCtrl(' {{- foo }}')).to.equal('{{- foo }}'); + it('should not strip by default', function() { + expect(whiteSpaceCtrl('\n {%foo%} \n')).to.equal('\n {%foo%} \n'); }); - it('should strip right whitespaces', function() { - expect(whiteSpaceCtrl('{{ foo -}} ')).to.equal('{{ foo -}}'); + it('should strip all blank characters before and after', function() { + expect(whiteSpaceCtrl('\n \t\r{{-foo-}} \t\n')).to.equal('{{-foo-}}'); }); - it('should not strip left when not specified', function() { - expect(whiteSpaceCtrl(' {%foo-%} ')).to.equal(' {%foo-%}'); + it('should not trim previous/next lines', function() { + expect(whiteSpaceCtrl(' \t\n {{-foo-}}')).to.equal(' \t{{-foo-}}'); + expect(whiteSpaceCtrl('{{-foo-}} \n \tfoo')).to.equal('{{-foo-}} \tfoo'); }); - it('should not strip right when not specified', function() { - expect(whiteSpaceCtrl(' {{-foo}} ')).to.equal('{{-foo}} '); + it("should not trim inter-word blanks", function() { + expect(whiteSpaceCtrl('\nhello {{-world-}}')).to.equal('\nhello {{-world-}}'); + expect(whiteSpaceCtrl('{{-hello-}} world')).to.equal('{{-hello-}} world'); }); - it('should strip all blank characters', function() { - expect(whiteSpaceCtrl('\t\r{{-foo-}}\n \n')).to.equal('{{-foo-}}'); + it('should trim exactly one trailing CR', function() { + expect(whiteSpaceCtrl('{{-foo-}} \n\n')).to.equal('{{-foo-}}\n'); + }); + it('should trim all leading/trailing blanks when options.greedy set', function() { + expect(whiteSpaceCtrl(' \n \n\t\r{{-foo-}}\n \n', { + greedy: true + })).to.equal('{{-foo-}}'); }); - it('should stop stripping when encountered normal chars', () => - expect(whiteSpaceCtrl('\ta\r{{-foo-}} b ')).to.equal('\ta{{-foo-}}b ')); it('should strip whitespaces when set trim_left', function() { - expect(whiteSpaceCtrl(' {{foo}} ', { + expect(whiteSpaceCtrl('\n {{foo}} \n', { trim_left: true - })).to.equal('{{foo}} '); + })).to.equal('{{-foo}} \n'); }); it('should strip whitespaces when set trim_right', function() { - expect(whiteSpaceCtrl(' {{foo}} ', { + expect(whiteSpaceCtrl('\n {{foo}} \n', { trim_right: true - })).to.equal(' {{foo}}'); + })).to.equal('\n {{foo-}}'); }); it('markup should has priority over options', function() { - expect(whiteSpaceCtrl(' {{-foo}} ', { + expect(whiteSpaceCtrl('\n {{-foo}} \n', { trim_left: false - })).to.equal('{{-foo}} '); + })).to.equal('{{-foo}} \n'); }); it('should support a mix of markup and options', function() { - expect(whiteSpaceCtrl(' {%-foo%} ', { + expect(whiteSpaceCtrl('\n {%-foo%} \n', { trim_left: true, trim_right: true - })).to.equal('{%-foo%}'); + })).to.equal('{%-foo-%}'); }); }); });