From ddc17a6b931ba7cd54f097361ccd34da80c85f56 Mon Sep 17 00:00:00 2001 From: harttle Date: Mon, 26 Sep 2016 21:52:06 +0800 Subject: [PATCH] refactor: tests for tags --- README.md | 154 +++++++++++---------- index.js | 9 +- package.json | 2 +- src/error.js | 30 ++-- src/parser.js | 3 +- src/scope.js | 5 +- tags/assign.js | 2 +- tags/decrement.js | 2 +- tags/include.js | 2 +- tags/increment.js | 3 +- tags/layout.js | 4 +- test/liquid.js | 2 - test/tags.js | 304 ----------------------------------------- test/tags/assign.js | 23 ++++ test/tags/capture.js | 25 ++++ test/tags/case.js | 45 ++++++ test/tags/comment.js | 23 ++++ test/tags/cycle.js | 39 ++++++ test/tags/decrement.js | 32 +++++ test/tags/for.js | 81 +++++++++++ test/tags/if.js | 49 +++++++ test/tags/include.js | 82 +++++++++++ test/tags/increment.js | 32 +++++ test/tags/layout.js | 55 ++++++++ test/tags/raw.js | 24 ++++ test/tags/tablerow.js | 71 ++++++++++ test/tags/unless.js | 29 ++++ 27 files changed, 724 insertions(+), 408 deletions(-) delete mode 100644 test/tags.js create mode 100644 test/tags/assign.js create mode 100644 test/tags/capture.js create mode 100644 test/tags/case.js create mode 100644 test/tags/comment.js create mode 100644 test/tags/cycle.js create mode 100644 test/tags/decrement.js create mode 100644 test/tags/for.js create mode 100644 test/tags/if.js create mode 100644 test/tags/include.js create mode 100644 test/tags/increment.js create mode 100644 test/tags/layout.js create mode 100644 test/tags/raw.js create mode 100644 test/tags/tablerow.js create mode 100644 test/tags/unless.js diff --git a/README.md b/README.md index 7c882c126..02e30c77d 100644 --- a/README.md +++ b/README.md @@ -21,14 +21,20 @@ Parse and Render: var Liquid = require('shopify-liquid'); var engine = Liquid(); -engine.parseAndRender('{{name | capitalize}}', {name: 'alice'}); // Alice +engine.parseAndRender('{{name | capitalize}}', {name: 'alice'}) + .then(function(html){ + // html === 'Alice' + }); ``` Caching templates: ```javascript var tpl = engine.parse('{{name | capitalize}}'); -engine.render(tpl, {name: 'alice'}); // Alice +engine.render(tpl, {name: 'alice'}) + .then(function(html){ + // html === 'Alice' + }); ``` ## Render from File @@ -39,8 +45,15 @@ var engine = Liquid({ extname: '.liquid', cache: false }); -// equivalent to: engine.renderFile("hello", {name: 'alice'}); -var html = engine.renderFile("hello.liquid", {name: 'alice'}); +engine.renderFile("hello.liquid", {name: 'alice'}) + .then(function(html){ + // html === 'Alice' + }); +// equivalent to: +engine.renderFile("hello", {name: 'alice'}) + .then(function(html){ + // html === 'Alice' + }); ``` `cache` default to `false`, `extname` default to `.liquid`, `root` default to `""`. @@ -48,11 +61,13 @@ var html = engine.renderFile("hello.liquid", {name: 'alice'}); ## Use with Express.js ```javascript -app.engine('liquid', engine.express()); -app.set('views', './views'); // specify the views directory -app.set('view engine', 'liquid'); // register the template engine +app.engine('liquid', engine.express()); // register liquid engine +app.set('views', './views'); // specify the views directory +app.set('view engine', 'liquid'); // set to default ``` +There's an Express demo in [the demo folder](demo/). + ## Includes ``` @@ -132,26 +147,26 @@ Documentation: Tag | Document | Source | Test --- | --- | --- | --- -`case/when` | [Document](https://shopify.github.io/liquid/tags/control-flow/) | [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/case.js) | [Test][tt] -`if` | [Document](https://shopify.github.io/liquid/tags/control-flow/) | [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/if.js) | [Test][tt] -`unless` | [Document](https://shopify.github.io/liquid/tags/control-flow/) | [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/unless.js) | [Test][tt] -`elsif/else` | [Document](https://shopify.github.io/liquid/tags/control-flow/) | [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/if.js) | [Test][tt] -`for` | [Document](https://shopify.github.io/liquid/tags/iteration/) | [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/for.js) | [Test][tt] -`break` | [Document](https://shopify.github.io/liquid/tags/iteration/) | [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/for.js) | [Test][tt] -`continue` | [Document](https://shopify.github.io/liquid/tags/iteration/) | [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/for.js) | [Test][tt] -`for: limit,offset,range,reversed` | [Document](https://shopify.github.io/liquid/tags/iteration/) | [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/for.js) | [Test][tt] -`cycle` | [Document](https://shopify.github.io/liquid/tags/iteration/) | [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/cycle.js) | [Test][tt] -`cycle: group` | [Document](https://shopify.github.io/liquid/tags/iteration/) | [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/cycle.js) | [Test][tt] -`tablerow` | [Document](https://shopify.github.io/liquid/tags/iteration/) | [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/tablerow.js) | [Test][tt] -`tablerow: cols,limit,offset,range` | [Document](https://shopify.github.io/liquid/tags/iteration/) | [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/tablerow.js) | [Test][tt] -`assign` | [Document](https://shopify.github.io/liquid/tags/variable/) | [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/assign.js) | [Test][tt] -`capture` | [Document](https://shopify.github.io/liquid/tags/variable/) | [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/capture.js) | [Test][tt] -`increment` | [Document](https://shopify.github.io/liquid/tags/variable/) | [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/increment.js) | [Test][tt] -`decrement` | [Document](https://shopify.github.io/liquid/tags/variable/) | [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/decrement.js) | [Test][tt] -`raw` | [Document](https://help.shopify.com/themes/liquid/tags/theme-tags#raw) | [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/raw.js) | [Test][tt] -`comment` | [Document](https://help.shopify.com/themes/liquid/tags/theme-tags#comment) | [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/comment.js) | [Test][tt] -`include` | [Document](https://help.shopify.com/themes/liquid/tags/theme-tags#include) | [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/include.js) | [Test][tt] -`layout, block` | [Document](http://docs.mixture.io/templates/) | [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/layout.js) | [Test][tt] +`case/when` | [Document](https://shopify.github.io/liquid/tags/control-flow/) | [Source](tags/case.js) | [Test](test/tags/case.js) +`if` | [Document](https://shopify.github.io/liquid/tags/control-flow/) | [Source](tags/if.js) | [Test](test/tags/if.js) +`unless` | [Document](https://shopify.github.io/liquid/tags/control-flow/) | [Source](tags/unless.js) | [Test](test/tags/unless.js) +`elsif/else` | [Document](https://shopify.github.io/liquid/tags/control-flow/) | [Source](tags/if.js) | [Test](test/tags/if.js) +`for` | [Document](https://shopify.github.io/liquid/tags/iteration/) | [Source](tags/for.js) | [Test](test/tags/for.js) +`break` | [Document](https://shopify.github.io/liquid/tags/iteration/) | [Source](tags/for.js) | [Test](test/tags/for.js) +`continue` | [Document](https://shopify.github.io/liquid/tags/iteration/) | [Source](tags/for.js) | [Test](test/tags/for.js) +`for: limit,offset,range,reversed` | [Document](https://shopify.github.io/liquid/tags/iteration/) | [Source](tags/for.js) | [Test](test/tags/for.js) +`cycle` | [Document](https://shopify.github.io/liquid/tags/iteration/) | [Source](tags/cycle.js) | [Test](test/tags/cycle.js) +`cycle: group` | [Document](https://shopify.github.io/liquid/tags/iteration/) | [Source](tags/cycle.js) | [Test](test/tags/cycle.js) +`tablerow` | [Document](https://shopify.github.io/liquid/tags/iteration/) | [Source](tags/tablerow.js) | [Test](test/tags/tablerow.js) +`tablerow: cols,limit,offset,range` | [Document](https://shopify.github.io/liquid/tags/iteration/) | [Source](tags/tablerow.js) | [Test](test/tags/tablerow.js) +`assign` | [Document](https://shopify.github.io/liquid/tags/variable/) | [Source](tags/assign.js) | [Test](test/tags/assign.js) +`capture` | [Document](https://shopify.github.io/liquid/tags/variable/) | [Source](tags/capture.js) | [Test](test/tags/capture.js) +`increment` | [Document](https://shopify.github.io/liquid/tags/variable/) | [Source](tags/increment.js) | [Test](test/tags/increment.js) +`decrement` | [Document](https://shopify.github.io/liquid/tags/variable/) | [Source](tags/decrement.js) | [Test](test/tags/decrement.js) +`raw` | [Document](https://help.shopify.com/themes/liquid/tags/theme-tags#raw) | [Source](tags/raw.js) | [Test](test/tags/raw.js) +`comment` | [Document](https://help.shopify.com/themes/liquid/tags/theme-tags#comment) | [Source](tags/comment.js) | [Test](test/tags/comment.js) +`include` | [Document](https://help.shopify.com/themes/liquid/tags/theme-tags#include) | [Source](tags/include.js) | [Test](test/tags/include.js) +`layout, block` | [Document](http://docs.mixture.io/templates/) | [Source](tags/layout.js) | [Test](test/tags/layout.js) ## All Filters @@ -160,47 +175,47 @@ Documentation: Filter | Document | Source | Test --- | --- | --- | --- -`abs` | [Document](https://shopify.github.io/liquid/filters/abs/) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`append` | [Document](https://shopify.github.io/liquid/filters/append) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`capitalize` | [Document](https://shopify.github.io/liquid/filters/capitalize) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`ceil` | [Document](https://shopify.github.io/liquid/filters/ceil) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`date` | [Document](https://shopify.github.io/liquid/filters/date) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`default` | [Document](https://shopify.github.io/liquid/filters/default) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`divided_by` | [Document](https://shopify.github.io/liquid/filters/divided_by) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`downcase` | [Document](https://shopify.github.io/liquid/filters/downcase) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`escape` | [Document](https://shopify.github.io/liquid/filters/escape) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`escape_once` | [Document](https://shopify.github.io/liquid/filters/escape_once) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`first` | [Document](https://shopify.github.io/liquid/filters/first) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`floor` | [Document](https://shopify.github.io/liquid/filters/floor) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`join` | [Document](https://shopify.github.io/liquid/filters/join) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`last` | [Document](https://shopify.github.io/liquid/filters/last) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`lstrip` | [Document](https://shopify.github.io/liquid/filters/lstrip) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`map` | [Document](https://shopify.github.io/liquid/filters/map) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`minus` | [Document](https://shopify.github.io/liquid/filters/minus) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`modulo` | [Document](https://shopify.github.io/liquid/filters/modulo) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`newline_to_br` | [Document](https://shopify.github.io/liquid/filters/newline_to_br) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`plus` | [Document](https://shopify.github.io/liquid/filters/plus) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`prepend` | [Document](https://shopify.github.io/liquid/filters/prepend) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`remove` | [Document](https://shopify.github.io/liquid/filters/remove) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`remove_first` | [Document](https://shopify.github.io/liquid/filters/remove_first) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`replace` | [Document](https://shopify.github.io/liquid/filters/replace) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`replace_first` | [Document](https://shopify.github.io/liquid/filters/replace_first) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`reverse` | [Document](https://shopify.github.io/liquid/filters/reverse) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`round` | [Document](https://shopify.github.io/liquid/filters/round) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`rstrip` | [Document](https://shopify.github.io/liquid/filters/rstrip) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`size` | [Document](https://shopify.github.io/liquid/filters/size) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`slice` | [Document](https://shopify.github.io/liquid/filters/slice) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`sort` | [Document](https://shopify.github.io/liquid/filters/sort) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`split` | [Document](https://shopify.github.io/liquid/filters/split) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`strip` | [Document](https://shopify.github.io/liquid/filters/strip) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`strip_html` | [Document](https://shopify.github.io/liquid/filters/strip_html) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`strip_newlines` | [Document](https://shopify.github.io/liquid/filters/strip_newlines) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`times` | [Document](https://shopify.github.io/liquid/filters/times) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`truncate` | [Document](https://shopify.github.io/liquid/filters/truncate) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`truncatewords` | [Document](https://shopify.github.io/liquid/filters/truncatewords) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`uniq` | [Document](https://shopify.github.io/liquid/filters/uniq) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`upcase` | [Document](https://shopify.github.io/liquid/filters/upcase) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] -`url_encode` | [Document](https://shopify.github.io/liquid/filters/url_encode) | [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) | [Test][ft] +`abs` | [Document](https://shopify.github.io/liquid/filters/abs/) | [Source](filters.js) | [Test](test/filters.js) +`append` | [Document](https://shopify.github.io/liquid/filters/append) | [Source](filters.js) | [Test](test/filters.js) +`capitalize` | [Document](https://shopify.github.io/liquid/filters/capitalize) | [Source](filters.js) | [Test](test/filters.js) +`ceil` | [Document](https://shopify.github.io/liquid/filters/ceil) | [Source](filters.js) | [Test](test/filters.js) +`date` | [Document](https://shopify.github.io/liquid/filters/date) | [Source](filters.js) | [Test](test/filters.js) +`default` | [Document](https://shopify.github.io/liquid/filters/default) | [Source](filters.js) | [Test](test/filters.js) +`divided_by` | [Document](https://shopify.github.io/liquid/filters/divided_by) | [Source](filters.js) | [Test](test/filters.js) +`downcase` | [Document](https://shopify.github.io/liquid/filters/downcase) | [Source](filters.js) | [Test](test/filters.js) +`escape` | [Document](https://shopify.github.io/liquid/filters/escape) | [Source](filters.js) | [Test](test/filters.js) +`escape_once` | [Document](https://shopify.github.io/liquid/filters/escape_once) | [Source](filters.js) | [Test](test/filters.js) +`first` | [Document](https://shopify.github.io/liquid/filters/first) | [Source](filters.js) | [Test](test/filters.js) +`floor` | [Document](https://shopify.github.io/liquid/filters/floor) | [Source](filters.js) | [Test](test/filters.js) +`join` | [Document](https://shopify.github.io/liquid/filters/join) | [Source](filters.js) | [Test](test/filters.js) +`last` | [Document](https://shopify.github.io/liquid/filters/last) | [Source](filters.js) | [Test](test/filters.js) +`lstrip` | [Document](https://shopify.github.io/liquid/filters/lstrip) | [Source](filters.js) | [Test](test/filters.js) +`map` | [Document](https://shopify.github.io/liquid/filters/map) | [Source](filters.js) | [Test](test/filters.js) +`minus` | [Document](https://shopify.github.io/liquid/filters/minus) | [Source](filters.js) | [Test](test/filters.js) +`modulo` | [Document](https://shopify.github.io/liquid/filters/modulo) | [Source](filters.js) | [Test](test/filters.js) +`newline_to_br` | [Document](https://shopify.github.io/liquid/filters/newline_to_br) | [Source](filters.js) | [Test](test/filters.js) +`plus` | [Document](https://shopify.github.io/liquid/filters/plus) | [Source](filters.js) | [Test](test/filters.js) +`prepend` | [Document](https://shopify.github.io/liquid/filters/prepend) | [Source](filters.js) | [Test](test/filters.js) +`remove` | [Document](https://shopify.github.io/liquid/filters/remove) | [Source](filters.js) | [Test](test/filters.js) +`remove_first` | [Document](https://shopify.github.io/liquid/filters/remove_first) | [Source](filters.js) | [Test](test/filters.js) +`replace` | [Document](https://shopify.github.io/liquid/filters/replace) | [Source](filters.js) | [Test](test/filters.js) +`replace_first` | [Document](https://shopify.github.io/liquid/filters/replace_first) | [Source](filters.js) | [Test](test/filters.js) +`reverse` | [Document](https://shopify.github.io/liquid/filters/reverse) | [Source](filters.js) | [Test](test/filters.js) +`round` | [Document](https://shopify.github.io/liquid/filters/round) | [Source](filters.js) | [Test](test/filters.js) +`rstrip` | [Document](https://shopify.github.io/liquid/filters/rstrip) | [Source](filters.js) | [Test](test/filters.js) +`size` | [Document](https://shopify.github.io/liquid/filters/size) | [Source](filters.js) | [Test](test/filters.js) +`slice` | [Document](https://shopify.github.io/liquid/filters/slice) | [Source](filters.js) | [Test](test/filters.js) +`sort` | [Document](https://shopify.github.io/liquid/filters/sort) | [Source](filters.js) | [Test](test/filters.js) +`split` | [Document](https://shopify.github.io/liquid/filters/split) | [Source](filters.js) | [Test](test/filters.js) +`strip` | [Document](https://shopify.github.io/liquid/filters/strip) | [Source](filters.js) | [Test](test/filters.js) +`strip_html` | [Document](https://shopify.github.io/liquid/filters/strip_html) | [Source](filters.js) | [Test](test/filters.js) +`strip_newlines` | [Document](https://shopify.github.io/liquid/filters/strip_newlines) | [Source](filters.js) | [Test](test/filters.js) +`times` | [Document](https://shopify.github.io/liquid/filters/times) | [Source](filters.js) | [Test](test/filters.js) +`truncate` | [Document](https://shopify.github.io/liquid/filters/truncate) | [Source](filters.js) | [Test](test/filters.js) +`truncatewords` | [Document](https://shopify.github.io/liquid/filters/truncatewords) | [Source](filters.js) | [Test](test/filters.js) +`uniq` | [Document](https://shopify.github.io/liquid/filters/uniq) | [Source](filters.js) | [Test](test/filters.js) +`upcase` | [Document](https://shopify.github.io/liquid/filters/upcase) | [Source](filters.js) | [Test](test/filters.js) +`url_encode` | [Document](https://shopify.github.io/liquid/filters/url_encode) | [Source](filters.js) | [Test](test/filters.js) ## Operators @@ -225,5 +240,4 @@ For template-driven projects, checkout these Liquid-like engines: [shopify-liquid]: https://shopify.github.io/liquid/ [jekyll]: http://jekyllrb.com/ [gh]: https://pages.github.com/ -[tt]: https://github.com/harttle/shopify-liquid/blob/master/test/tags.js -[ft]: https://github.com/harttle/shopify-liquid/blob/master/test/filters.js +(test/filters.js): https://github.com/harttle/shopify-liquid/blob/master/test/filters.js diff --git a/index.js b/index.js index ad0fceebf..e505ba240 100644 --- a/index.js +++ b/index.js @@ -88,12 +88,9 @@ var _engine = { }, express: function() { return (filePath, options, callback) => { - try { - var html = this.renderFile(filePath, options); - return callback(null, html); - } catch (e) { - return callback(e); - } + this.renderFile(filePath, options) + .then(html => callback(null, html)) + .catch(e => callback(e)); }; } }; diff --git a/package.json b/package.json index 39a264d61..e86ce05a7 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "Liquid template engine in Node.js (Shopify compliant)", "main": "index.js", "scripts": { - "test": "mocha" + "test": "mocha --recursive" }, "repository": { "type": "git", diff --git a/src/error.js b/src/error.js index c67fbf98a..76a62597a 100644 --- a/src/error.js +++ b/src/error.js @@ -1,20 +1,24 @@ -function TokenizationError(message, input, line, stack) { - this.name = "TokenizationError"; - this.message = (message || ""); - this.input = input; - this.line = line; - if(stack) this.stack = stack; -} -TokenizationError.prototype = Error.prototype; +const util = require('util'); -function ParseError(message, input, line, stack) { - this.name = "ParseError"; - this.message = (message || ""); +function TokenizationError(message, input, line) { + Error.captureStackTrace(this, this.constructor); + this.name = this.constructor.name; + + this.message = message || ""; this.input = input; this.line = line; - if(stack) this.stack = stack; } -ParseError.prototype = Error.prototype; +util.inherits(TokenizationError, Error); + +function ParseError(message, input, line) { + Error.captureStackTrace(this, this.constructor); + this.name = "ParseError"; + + this.message = message || ""; + this.input = input; + this.line = line; +} +util.inherits(ParseError, Error); module.exports = { TokenizationError, ParseError diff --git a/src/parser.js b/src/parser.js index 86bcad5d9..6d33876c0 100644 --- a/src/parser.js +++ b/src/parser.js @@ -1,5 +1,4 @@ const lexical = require('./lexical.js'); -const error = require('./error.js'); const ParseError = require('./error.js').ParseError; module.exports = function(Tag, Filter) { @@ -60,7 +59,7 @@ module.exports = function(Tag, Filter) { return token; } } catch (e) { - throw new ParseError(e.message, token.input, token.line, e.stack); + throw new ParseError(e.message, token.input, token.line); } } diff --git a/src/scope.js b/src/scope.js index 954e004c3..836b675b3 100644 --- a/src/scope.js +++ b/src/scope.js @@ -1,6 +1,5 @@ const _ = require('lodash'); const lexical = require('./lexical.js'); -const error = require('./error.js'); var scope = { get: function(str) { @@ -21,7 +20,7 @@ var scope = { return this; }, push: function(ctx) { - if (!ctx) error(`trying to push ${ctx} into scopes`); + if (!ctx) throw new Error(`trying to push ${ctx} into scopes`); return this.scopes.push(ctx); }, pop: function() { @@ -31,6 +30,6 @@ var scope = { exports.factory = function(_ctx) { var ctx = Object.create(scope); - ctx.scopes = _ctx ? [_ctx] : []; + ctx.scopes = [_ctx || {}]; return ctx; }; diff --git a/tags/assign.js b/tags/assign.js index d63f72343..2126c8b95 100644 --- a/tags/assign.js +++ b/tags/assign.js @@ -8,7 +8,7 @@ module.exports = function(liquid) { liquid.registerTag('assign', { parse: function(token){ var match = token.args.match(re); - if(!match) error(`illegal token ${token.raw}`, token); + if(!match) throw new Error(`illegal token ${token.raw}`); this.key = match[1]; this.value = match[2]; }, diff --git a/tags/decrement.js b/tags/decrement.js index 69b64bf43..c726267b1 100644 --- a/tags/decrement.js +++ b/tags/decrement.js @@ -7,7 +7,7 @@ module.exports = function(liquid) { liquid.registerTag('decrement', { parse: function(token) { var match = token.args.match(lexical.identifier); - if (!match) error(`illegal identifier ${token.args}`, token); + if (!match) throw new Error(`illegal identifier ${token.args}`); this.variable = match[0]; }, render: function(scope, hash) { diff --git a/tags/include.js b/tags/include.js index 6f8eb94f5..edf621516 100644 --- a/tags/include.js +++ b/tags/include.js @@ -8,7 +8,7 @@ module.exports = function(liquid) { liquid.registerTag('include', { parse: function(token){ var match = lexical.value.exec(token.args); - if(!match) error(`illegal token ${token.raw}`, token); + if(!match) throw(new Error(`illegal token ${token.raw}`)); this.value = match[0]; match = withRE.exec(token.args); diff --git a/tags/increment.js b/tags/increment.js index 3f1eb816a..0e253fa87 100644 --- a/tags/increment.js +++ b/tags/increment.js @@ -1,13 +1,12 @@ const Liquid = require('..'); const lexical = Liquid.lexical; -const error = Liquid.error; module.exports = function(liquid) { liquid.registerTag('increment', { parse: function(token) { var match = token.args.match(lexical.identifier); - if (!match) error(`illegal identifier ${token.args}`, token); + if (!match) throw (new Error(`illegal identifier ${token.args}`)); this.variable = match[0]; }, render: function(scope, hash) { diff --git a/tags/layout.js b/tags/layout.js index bf2365908..2a2b3a5c2 100644 --- a/tags/layout.js +++ b/tags/layout.js @@ -8,7 +8,7 @@ module.exports = function(liquid) { liquid.registerTag('layout', { parse: function(token, remainTokens){ var match = lexical.value.exec(token.args); - if(!match) error(`illegal token ${token.raw}`, token); + if(!match) throw new Error(`illegal token ${token.raw}`); this.layout = match[0]; this.tpls = liquid.parser.parse(remainTokens); @@ -22,7 +22,7 @@ module.exports = function(liquid) { return liquid.renderer.renderTemplates(this.tpls, scope) .then((partial) => { html += partial; - return liquid.handleCache(layout) + return liquid.handleCache(layout); }) .then((templates) => { return liquid.renderer.renderTemplates(templates, scope); diff --git a/test/liquid.js b/test/liquid.js index 4d4fb213f..2339f1a8a 100644 --- a/test/liquid.js +++ b/test/liquid.js @@ -55,8 +55,6 @@ describe('liquid', function() { .then((result) => { return expect(result).to.equal('{"foo":"bar"}'); }); -// engine.render(template, ctx).should.equal('{"foo":"bar"}'); -// engine.render(template, ctx).should.equal('{"foo":"bar"}'); }); it('should render filters', function() { var template = engine.parse('

{{arr | join: "_"}}

'); diff --git a/test/tags.js b/test/tags.js deleted file mode 100644 index 7df2f1a85..000000000 --- a/test/tags.js +++ /dev/null @@ -1,304 +0,0 @@ -// temporary -const Promise = require('any-promise'); -const chai = require("chai"); -const chaiAsPromised = require("chai-as-promised"); -const should = chai.should(); -const expect = chai.expect; -const Liquid = require('..'); -const mock = require('mock-fs'); - -chai.use(chaiAsPromised); - -var liquid = Liquid({ - root: '/', - extname: '.html' - }), - ctx, src, dst; - -function test(src, dst) { - return liquid.parseAndRender(src, ctx) - .then((result) => { - return expect(result).to.equal(dst); - }); -} - -function testThrow(src, pattern) { - return liquid.parseAndRender(src, ctx).should.eventually.be.rejectedWith(pattern); -} - -describe('tags', function() { - beforeEach(function() { - ctx = { - one: 1, - two: 2, - leq: '<=', - empty: '', - foo: 'bar', - arr: [-2, 'a'], - alpha: ['a', 'b', 'c'], - emptyArray: [], - person: { - firstName: 'Joe', - lastName: 'Shmoe', - address: { - city: 'Dallas' - } - } - }; - mock({ - '/default-layout.html': 'foo{% block %}Default{% endblock %}foo', - '/multi-blocks-layout.html': 'foo{% block "a"%}{% endblock %}{% block b%}{%endblock%}foo', - '/multi-blocks.html': '{% layout "multi-blocks-layout" %}{%block a%}aaa{%endblock%},{%block b%};{%block c%}ccc{%endblock%};{%endblock%}', - '/files/foo.html': 'foo', - '/current.html': 'bar{% include "foo.html" %}bar', - '/relative.html': 'bar{% include "../files/foo.html" %}bar', - '/foo.html': 'FOO', - '/user.html': '{{name}} : {{role}} : {{alias}}', - '/color.html': 'color:{{color}}, shape:{{shape}}', - '/with.html': '{% include "color" with "red", shape: "rect" %}', - '/scope.html': '{% assign shape="triangle" %}{% assign color="yellow" %}{% include "color.html" %}', - '/hash.html': '{% assign name="harttle" %}{% include "user.html", role: "admin", alias: name %}', - '/personInfo.html': 'This is a person {% include "card.html" %}', - '/card.html': '

{{person.firstName}} {{person.lastName}}
{% include "address" %}

', - '/address.html': 'City: {{person.address.city}}' - }); - }); - afterEach(function() { - mock.restore(); - }); - - it('should support assign 1', function() { return test('{% assign foo="bar" %}{{foo}}', 'bar'); }); - it('should support assign 2', function() { return test('{% assign foo=(1..3) %}{{foo}}', '[1,2,3]'); }); - it('should support assign 3', function() { return test('{% assign foo="a b" | capitalize | split: " " | first %}{{foo}}', 'A'); }); - - it('should support raw 1', function() { return testThrow('{% raw%}', /{% raw%} not closed/); }); - it('should support raw 2', function() { return test('{% raw %}{{ 5 | plus: 6 }}{% endraw %} is equal to 11.', '{{ 5 | plus: 6 }} is equal to 11.'); }); - it('should support raw 3', function() { return test('{% raw %}\n{{ foo}} \n{% endraw %}', '\n{{ foo}} \n'); }); - - - it('should support comment 1', function() { return testThrow('{% comment %}{% raw%}', /{% comment %} not closed/); }); - it('should support comment 2', function() { return test('My name is {% comment %}super{% endcomment %} Shopify.', 'My name is Shopify.'); }); - it('should support comment 3', function() { return test('{% comment %}\n{{ foo}} \n{% endcomment %}', ''); }); - - it('should support case 1', function() { return testThrow('{% case "foo"%}', /{% case "foo"%} not closed/); }); - it('should support case 2', function() { return test('{% case "foo"%}' + - '{% when "foo" %}foo{% when "bar"%}bar' + - '{%endcase%}', 'foo'); }); - it('should support case 3', function() { return test('{% case empty %}' + - '{% when "foo" %}foo{% when ""%}bar' + - '{%endcase%}', 'bar'); }); - it('should support case 4', function() { return test('{% case false %}' + - '{% when "foo" %}foo{% when ""%}bar' + - '{%endcase%}', ''); }); - it('should support case 5', function() { return test('{% case "a" %}' + - '{% when "b" %}b{% when "c"%}c{%else %}d' + - '{%endcase%}', 'd'); }); - - it('should support if 1', function() { return testThrow('{% if false%}yes', /tag {% if false%} not closed/); }); - it('should support if 2', function() { return test('{%if emptyArray%}a{%endif%}', ''); }); - it('should support if 3', function() { return test('{% if 2==3 %}yes{%else%}no{%endif%}', 'no'); }); - it('should support if 4', function() { return test('{% if 1>=2 and one2 %}yes', /tag {% unless 1>2 %} not closed/); }); - it('should support unless 3', function() { return test('{% unless 1>2 %}yes{%endunless%}', 'yes'); }); - it('should support unless 4', function() { return test('{% unless true %}{%endunless%}', ''); }); - - it('should support capture 1', function() { return test('{% capture f %}{{"a" | capitalize}}{%endcapture%}{{f}}', 'A'); }); - it('should support capture 2', function() { return testThrow('{% capture = %}{%endcapture%}', /= not valid identifier/); }); - - it('should throw when for capture closed', function() { - return testThrow('{%capture c%}{{c}}', /tag .* not closed/); - }); - - it('should support for', function() { - return test('{%for c in alpha%}{{c}}{%endfor%}', 'abc'); - }); - - it('should throw when for not closed', function() { - return testThrow('{%for c in alpha%}{{c}}', /tag .* not closed/); - }); - - it('should support for else', function() { - return test('{%for c in ""%}a{%else%}b{%endfor%}', 'b'); - }); - - it('should support for with forloop', function() { - src = '{%for c in alpha%}' + - '{{forloop.first}}.{{forloop.index}}.{{forloop.index0}}.' + - '{{forloop.last}}.{{forloop.length}}.' + - '{{forloop.rindex}}.{{forloop.rindex0}}' + - '{{c}}\n' + - '{%endfor%}'; - dst = 'true.1.0.false.3.3.2a\n' + - 'false.2.1.false.3.2.1b\n' + - 'false.3.2.true.3.1.0c\n'; - return test(src, dst); - }); - - it('should support for with continue', function() { - src = '{% for i in (1..5) %}' + - '{% if i == 4 %}{% continue %}' + - '{% else %}{{ i }}' + - '{% endif %}' + - '{% endfor %}'; - return test(src, '1235'); - }); - it('should support for with break', function() { - src = '{% for i in (one..5) %}' + - '{% if i == 4 %}{% break %}{% endif %}' + - '{{ i }}' + - '{% endfor %}'; - return test(src, '123'); - }); - - it('should support for with limit', function() { - src = '{% for i in (1..5) limit:2 %}{{ i }}{% endfor %}'; - return test(src, '12'); - }); - it('should support for with limit and offset', function() { - src = '{% for i in (1..10) limit:2 offset:5%}{{ i }}{% endfor %}'; - return test(src, '67'); - }); - - it('should support for reversed', function() { - src = '{% for i in (1..5) limit:2 reversed %}{{ i }}{% endfor %}'; - return test(src, '21'); - }); - - it('should support cycle', function() { - src = "{% cycle '1', '2', '3' %}"; - return test(src + src + src + src, '1231'); - }); - - it('should throw when cycle candidates empty', function() { - return testThrow('{%cycle%}', /empty candidates/); - }); - - it('should support cycle in for block', function() { - src = '{% for i in (1..5) %}{% cycle one, "e"%}{% endfor %}'; - return test(src, '1e1e1'); - }); - - it('should support cycle group', function() { - src = "{% cycle one: '1', '2', '3'%}" + - "{% cycle 1: '1', '2', '3'%}" + - "{% cycle 2: '1', '2', '3'%}"; - return test(src, '121'); - }); - - it('should support increment 1', function() { return test('{% increment foo %}{%increment foo%}{{foo}}', '2'); }); - it('should support increment 2', function() { return test('{% increment one %}{{one}}', '2'); }); - - it('should support decrement 1', function() { return test('{% decrement foo %}{%decrement foo%}{{foo}}', '-2'); }); - it('should support decrement 2', function() { return test('{% decrement one %}{{one}}', '0'); }); - - it('should support tablerow', function() { - src = '{% tablerow i in alpha cols:2 %}{{ i }}{% endtablerow %}'; - dst = '' + - '' + - '' + - '
ab
c
'; - return test(src, dst); - }); - - it('should support empty tablerow', function() { - src = '{% tablerow i in (1..0) cols:2 %}{{ i }}{% endtablerow %}'; - dst = '
'; - return test(src, dst); - }); - - it('should throw when tablerow not closed', function() { - src = '{% tablerow i in (1..0) cols:2 %}{{ i }}'; - return testThrow(src, /tag .* not closed/); - }); - - it('should support tablerow with range', function() { - src = '{% tablerow i in (1..5) cols:2 %}{{ i }}{% endtablerow %}'; - dst = '' + - '' + - '' + - '' + - '
12
34
5
'; - return test(src, dst); - }); - - it('tablerow should throw on illegal cols 1', function() { - return testThrow('{% tablerow i in (1..5) cols:0 %}{{ i }}{% endtablerow %}', - /illegal cols: 0/); - }); - it('tablerow should throw on illegal cols 2', function() { - return testThrow('{% tablerow i in (1..5) %}{{ i }}{% endtablerow %}', - /illegal cols: undefined/); - }); - - it('should support tablerow with limit', function() { - src = '{% tablerow i in (1..5) cols:2 limit:3 %}{{ i }}{% endtablerow %}'; - dst = '' + - '' + - '' + - '
12
3
'; - return test(src, dst); - }); - - it('should support tablerow with offset', function() { - src = '{% tablerow i in (1..5) cols:2 offset:3 %}{{ i }}{% endtablerow %}'; - dst = '' + - '' + - '
45
'; - return test(src, dst); - }); - - it('should support include', function() { - return liquid.renderFile('/current.html', ctx).should.eventually.equal('barFOObar'); - }); - - it('should support include with relative path', function() { - return liquid.renderFile('relative.html', ctx).should.eventually.equal('barfoobar'); - }); - - it('should support include: hash list', function() { - return liquid.renderFile('hash.html', ctx).should.eventually.equal('harttle : admin : harttle'); - }); - - it('should support include: parent scope', function() { - return liquid.renderFile('scope.html', ctx).should.eventually.equal('color:yellow, shape:triangle'); - }); - - it('should support include: with', function() { - var filepath = 'with.html'; - var dst = 'color:red, shape:rect'; - return liquid.renderFile(filepath, ctx).should.eventually.equal(dst); - }); - - it('should support nested includes', function() { - //expect(liquid.renderFile('personInfo.html', ctx)).to.equal('This is a person

Joe Shmoe
City: Dallas

'); - return liquid.renderFile('personInfo.html', ctx).should.eventually.equal('This is a person

Joe Shmoe
City: Dallas

') - }); - - it('should throw when block not closed', function() { - src = '{% layout "default-layout" %}{%block%}bar'; - return testThrow(src, /tag {%block%} not closed/); - }); - it('should support layout', function() { - src = '{% layout "default-layout" %}{%block%}bar{%endblock%}'; - return test(src, 'foobarfoo'); - }); - it('should support layout: multiple blocks', function() { - src = '{% layout "multi-blocks-layout" %}' + - '{%block a%}bara{%endblock%}' + - '{%block b%}barb{%endblock%}'; - return test(src, 'foobarabarbfoo'); - }); - it('should support layout: nested 1', function() { - src = '{% layout "multi-blocks" %}{% block a%}A{%endblock%}{%block c%}C{%endblock%}'; - return test(src, 'fooA;C;foo'); - }); - it('should support layout: nested 2', function() { - src = '{% layout "multi-blocks" %}{%block c%}C{%endblock%}'; - return test(src, 'fooaaa;C;foo'); - }); -}); diff --git a/test/tags/assign.js b/test/tags/assign.js new file mode 100644 index 000000000..d38b1a3e0 --- /dev/null +++ b/test/tags/assign.js @@ -0,0 +1,23 @@ +const Liquid = require('../..'); +const chai = require("chai"); +const expect = chai.expect; +chai.use(require("chai-as-promised")); + +describe('tags/assign', function() { + var liquid = Liquid(); + it('should support assign 1', function() { + var src = '{% assign foo="bar" %}{{foo}}'; + return expect(liquid.parseAndRender(src)) + .to.eventually.equal('bar'); + }); + it('should support assign 2', function() { + var src = '{% assign foo=(1..3) %}{{foo}}'; + return expect(liquid.parseAndRender(src)) + .to.eventually.equal('[1,2,3]'); + }); + it('should support assign 3', function() { + var src = '{% assign foo="a b" | capitalize | split: " " | first %}{{foo}}'; + return expect(liquid.parseAndRender(src)) + .to.eventually.equal('A'); + }); +}); diff --git a/test/tags/capture.js b/test/tags/capture.js new file mode 100644 index 000000000..2951813fd --- /dev/null +++ b/test/tags/capture.js @@ -0,0 +1,25 @@ +const Liquid = require('../..'); +const chai = require("chai"); +const expect = chai.expect; +chai.use(require("chai-as-promised")); + +describe('tags/capture', function() { + var liquid = Liquid(); + + it('should support capture 1', function() { + var src = '{% capture f %}{{"a" | capitalize}}{%endcapture%}{{f}}'; + return expect(liquid.parseAndRender(src)) + .to.eventually.equal('A'); + }); + it('should support capture 2', function() { + var src = '{% capture = %}{%endcapture%}'; + return expect(liquid.parseAndRender(src)) + .to.be.rejectedWith(/= not valid identifier/); + }); + + it('should throw when for capture closed', function() { + var src = '{%capture c%}{{c}}'; + return expect(liquid.parseAndRender(src)) + .to.be.rejectedWith(/tag .* not closed/); + }); +}); diff --git a/test/tags/case.js b/test/tags/case.js new file mode 100644 index 000000000..17090c0a2 --- /dev/null +++ b/test/tags/case.js @@ -0,0 +1,45 @@ +const Liquid = require('../..'); +const chai = require("chai"); +const expect = chai.expect; +chai.use(require("chai-as-promised")); + +describe('tags/case', function() { + var liquid = Liquid(); + + it('should support case 1', function() { + var src = '{% case "foo"%}'; + return expect(liquid.parseAndRender(src)) + .to.be.rejectedWith(/{% case "foo"%} not closed/); + }); + it('should support case 2', function() { + var src = '{% case "foo"%}' + + '{% when "foo" %}foo{% when "bar"%}bar' + + '{%endcase%}'; + return expect(liquid.parseAndRender(src)) + .to.eventually.equal('foo'); + }); + it('should support case 3', function() { + var src = '{% case empty %}' + + '{% when "foo" %}foo{% when ""%}bar' + + '{%endcase%}'; + var ctx = { + empty: '' + }; + return expect(liquid.parseAndRender(src, ctx)) + .to.eventually.equal('bar'); + }); + it('should support case 4', function() { + var src = '{% case false %}' + + '{% when "foo" %}foo{% when ""%}bar' + + '{%endcase%}'; + return expect(liquid.parseAndRender(src)) + .to.eventually.equal(''); + }); + it('should support case 5', function() { + var src = '{% case "a" %}' + + '{% when "b" %}b{% when "c"%}c{%else %}d' + + '{%endcase%}'; + return expect(liquid.parseAndRender(src)) + .to.eventually.equal('d'); + }); +}); diff --git a/test/tags/comment.js b/test/tags/comment.js new file mode 100644 index 000000000..353c99d45 --- /dev/null +++ b/test/tags/comment.js @@ -0,0 +1,23 @@ +const Liquid = require('../..'); +const chai = require("chai"); +const expect = chai.expect; +chai.use(require("chai-as-promised")); + +describe('tags/comment', function() { + var liquid = Liquid(); + it('should support comment 1', function() { + var src = '{% comment %}{% raw%}'; + return expect(liquid.parseAndRender(src)) + .to.be.rejectedWith(/{% comment %} not closed/); + }); + it('should support comment 2', function() { + var src = 'My name is {% comment %}super{% endcomment %} Shopify.'; + return expect(liquid.parseAndRender(src)) + .to.eventually.equal('My name is Shopify.'); + }); + it('should support comment 3', function() { + var src = '{% comment %}\n{{ foo}} \n{% endcomment %}'; + return expect(liquid.parseAndRender(src)) + .to.eventually.equal(''); + }); +}); diff --git a/test/tags/cycle.js b/test/tags/cycle.js new file mode 100644 index 000000000..c062b0959 --- /dev/null +++ b/test/tags/cycle.js @@ -0,0 +1,39 @@ +const Liquid = require('../..'); +const chai = require("chai"); +const expect = chai.expect; +chai.use(require("chai-as-promised")); + +describe('tags/cycle', function() { + var liquid = Liquid(); + + it('should support cycle', function() { + var src = "{% cycle '1', '2', '3' %}"; + return expect(liquid.parseAndRender(src + src + src + src)) + .to.eventually.equal('1231'); + }); + + it('should throw when cycle candidates empty', function() { + return expect(liquid.parseAndRender('{%cycle%}')) + .to.be.rejectedWith(/empty candidates/); + }); + + it('should support cycle in for block', function() { + var src = '{% for i in (1..5) %}{% cycle one, "e"%}{% endfor %}'; + var ctx = { + one: 1 + }; + return expect(liquid.parseAndRender(src, ctx)) + .to.eventually.equal('1e1e1'); + }); + + it('should support cycle group', function() { + var src = "{% cycle one: '1', '2', '3'%}" + + "{% cycle 1: '1', '2', '3'%}" + + "{% cycle 2: '1', '2', '3'%}"; + var ctx = { + one: 1 + }; + return expect(liquid.parseAndRender(src, ctx)) + .to.eventually.equal('121'); + }); +}); diff --git a/test/tags/decrement.js b/test/tags/decrement.js new file mode 100644 index 000000000..5a95aaf4c --- /dev/null +++ b/test/tags/decrement.js @@ -0,0 +1,32 @@ +const Liquid = require('../..'); +const chai = require("chai"); +const expect = chai.expect; +chai.use(require("chai-as-promised")); + +describe('tags/decrement', function() { + var liquid = Liquid(); + + it('should support decrement', function() { + var src = '{% decrement one %}{{one}}'; + var ctx = { + one: 1 + }; + return expect(liquid.parseAndRender(src, ctx)) + .to.eventually.equal('0'); + }); + + it('should decrement undefined', function() { + var src = '{% decrement empty %}{{empty}}'; + return expect(liquid.parseAndRender(src)) + .to.eventually.equal('-1'); + }); + + it('should support decrement multiple times', function() { + var src = '{% decrement foo %}{%decrement foo%}{{foo}}'; + var ctx = { + foo: 1 + }; + return expect(liquid.parseAndRender(src, ctx)) + .to.eventually.equal('-1'); + }); +}); diff --git a/test/tags/for.js b/test/tags/for.js new file mode 100644 index 000000000..af80ad888 --- /dev/null +++ b/test/tags/for.js @@ -0,0 +1,81 @@ +const Liquid = require('../..'); +const chai = require("chai"); +const expect = chai.expect; +chai.use(require("chai-as-promised")); + +describe('tags/for', function() { + var liquid, ctx; + before(function() { + liquid = Liquid(); + ctx = { + one: 1, + alpha: ['a', 'b', 'c'], + }; + }); + it('should support for', function() { + var src = '{%for c in alpha%}{{c}}{%endfor%}'; + return expect(liquid.parseAndRender(src, ctx)) + .to.eventually.equal('abc'); + }); + + it('should throw when for not closed', function() { + var src = '{%for c in alpha%}{{c}}'; + return expect(liquid.parseAndRender(src, ctx)) + .to.be.rejectedWith(/tag .* not closed/); + }); + + it('should support for else', function() { + var src = '{%for c in ""%}a{%else%}b{%endfor%}'; + return expect(liquid.parseAndRender(src, ctx)) + .to.eventually.equal('b'); + }); + + it('should support for with forloop', function() { + var src = '{%for c in alpha%}' + + '{{forloop.first}}.{{forloop.index}}.{{forloop.index0}}.' + + '{{forloop.last}}.{{forloop.length}}.' + + '{{forloop.rindex}}.{{forloop.rindex0}}' + + '{{c}}\n' + + '{%endfor%}'; + var dst = 'true.1.0.false.3.3.2a\n' + + 'false.2.1.false.3.2.1b\n' + + 'false.3.2.true.3.1.0c\n'; + return expect(liquid.parseAndRender(src, ctx)) + .to.eventually.equal(dst); + }); + + it('should support for with continue', function() { + var src = '{% for i in (1..5) %}' + + '{% if i == 4 %}{% continue %}' + + '{% else %}{{ i }}' + + '{% endif %}' + + '{% endfor %}'; + return expect(liquid.parseAndRender(src, ctx)) + .to.eventually.equal('1235'); + }); + it('should support for with break', function() { + src = '{% for i in (one..5) %}' + + '{% if i == 4 %}{% break %}{% endif %}' + + '{{ i }}' + + '{% endfor %}'; + return expect(liquid.parseAndRender(src, ctx)) + .to.eventually.equal('123'); + }); + + it('should support for with limit', function() { + src = '{% for i in (1..5) limit:2 %}{{ i }}{% endfor %}'; + return expect(liquid.parseAndRender(src, ctx)) + .to.eventually.equal('12'); + }); + it('should support for with limit and offset', function() { + src = '{% for i in (1..10) limit:2 offset:5%}{{ i }}{% endfor %}'; + return expect(liquid.parseAndRender(src, ctx)) + .to.eventually.equal('67'); + }); + + it('should support for reversed', function() { + src = '{% for i in (1..5) limit:2 reversed %}{{ i }}{% endfor %}'; + return expect(liquid.parseAndRender(src, ctx)) + .to.eventually.equal('21'); + }); +}); diff --git a/test/tags/if.js b/test/tags/if.js new file mode 100644 index 000000000..4992af9ee --- /dev/null +++ b/test/tags/if.js @@ -0,0 +1,49 @@ +const Liquid = require('../..'); +const chai = require("chai"); +const expect = chai.expect; +chai.use(require("chai-as-promised")); + +describe('tags/if', function() { + var liquid = Liquid(); + var ctx = { + one: 1, + two: 2, + emptyArray: [] + }; + + it('should support if 1', function() { + var src = '{% if false%}yes'; + return expect(liquid.parseAndRender(src, ctx)) + .to.be.rejectedWith(/tag {% if false%} not closed/); + }); + it('should support if 2', function() { + var src = '{%if emptyArray%}a{%endif%}'; + return expect(liquid.parseAndRender(src, ctx)) + .to.eventually.equal(''); + }); + it('should support if 3', function() { + var src = '{% if 2==3 %}yes{%else%}no{%endif%}'; + return expect(liquid.parseAndRender(src, ctx)) + .to.eventually.equal('no'); + }); + it('should support if 4', function() { + var src = '{% if 1>=2 and one{{person.firstName}} {{person.lastName}}
{% include "address" %}

', + '/user.html': '{{name}} : {{role}} : {{alias}}', + '/address.html': 'City: {{person.address.city}}' + }); + }); + afterEach(function() { + mock.restore(); + }); + it('should support include', function() { + return expect(liquid.renderFile('/current.html', ctx)).to. + eventually.equal('barfoobar'); + }); + + it('should throw when illegal', function() { + return expect(liquid.renderFile('/illegal.html')).to. + be.rejectedWith(error.ParseError, /illegal token {%include%}/); + }); + + it('should support include with relative path', function() { + return expect(liquid.renderFile('foo/relative.html', ctx)).to. + eventually.equal('barfoobar'); + }); + + it('should support include: hash list', function() { + return expect(liquid.renderFile('hash.html', ctx)).to. + eventually.equal('harttle : admin : harttle'); + }); + + it('should support include: parent scope', function() { + return expect(liquid.renderFile('scope.html', ctx)).to. + eventually.equal('color:yellow, shape:triangle'); + }); + + it('should support include: with', function() { + return expect(liquid.renderFile('with.html', ctx)).to. + eventually.equal('color:red, shape:rect'); + }); + + it('should support nested includes', function() { + return expect(liquid.renderFile('personInfo.html', ctx)).to. + eventually.equal('This is a person

Joe Shmoe
City: Dallas

'); + }); +}); diff --git a/test/tags/increment.js b/test/tags/increment.js new file mode 100644 index 000000000..51cd8c290 --- /dev/null +++ b/test/tags/increment.js @@ -0,0 +1,32 @@ +const Liquid = require('../..'); +const chai = require("chai"); +const expect = chai.expect; +chai.use(require("chai-as-promised")); + +describe('tags/increment', function() { + var liquid = Liquid(); + + it('should support increment', function() { + var src = '{% increment one %}{{one}}'; + var ctx = { + one: 1 + }; + return expect(liquid.parseAndRender(src, ctx)) + .to.eventually.equal('2'); + }); + + it('should increment undefined', function() { + var src = '{% increment empty %}{{empty}}'; + return expect(liquid.parseAndRender(src)) + .to.eventually.equal('1'); + }); + + it('should support increment multiple times', function() { + var src = '{% increment foo %}{%increment foo%}{{foo}}'; + var ctx = { + foo: 1 + }; + return expect(liquid.parseAndRender(src, ctx)) + .to.eventually.equal('3'); + }); +}); diff --git a/test/tags/layout.js b/test/tags/layout.js new file mode 100644 index 000000000..31b066ff4 --- /dev/null +++ b/test/tags/layout.js @@ -0,0 +1,55 @@ +const Liquid = require('../..'); +const mock = require('mock-fs'); +const chai = require("chai"); +const expect = chai.expect; +const error = require('../../src/error.js'); +chai.use(require("chai-as-promised")); + +describe('tags/layout', function() { + var liquid; + before(function() { + liquid = Liquid({ + root: '/', + extname: '.html' + }); + }); + beforeEach(function() { + mock({ + '/default-layout.html': 'foo{% block %}Default{% endblock %}foo', + '/multi-blocks-layout.html': 'foo{% block "a"%}{% endblock %}{% block b%}{%endblock%}foo', + '/multi-blocks.html': '{% layout "multi-blocks-layout" %}{%block a%}aaa{%endblock%},{%block b%};{%block c%}ccc{%endblock%};{%endblock%}', + }); + }); + afterEach(function() { + mock.restore(); + }); + + it('should throw when block not closed', function() { + src = '{% layout "default-layout" %}{%block%}bar'; + return expect(liquid.parseAndRender(src)).to + .be.rejectedWith(/tag {%block%} not closed/); + }); + it('should support layout', function() { + src = '{% layout "default-layout" %}{%block%}bar{%endblock%}'; + return expect(liquid.parseAndRender(src)).to + .eventually.equal('foobarfoo'); + }); + it('should support layout: multiple blocks', function() { + src = '{% layout "multi-blocks-layout" %}' + + '{%block a%}bara{%endblock%}' + + '{%block b%}barb{%endblock%}'; + return expect(liquid.parseAndRender(src)).to + .eventually.equal('foobarabarbfoo'); + }); + it('should support layout: nested 1', function() { + src = '{% layout "multi-blocks" %}{% block a%}A{%endblock%}{%block c%}C{%endblock%}'; + return expect(liquid.parseAndRender(src)).to + .eventually.equal('fooA;C;foo'); + }); + it('should support layout: nested 2', function() { + src = '{% layout "multi-blocks" %}{%block c%}C{%endblock%}'; + return expect(liquid.parseAndRender(src)).to + .eventually.equal('fooaaa;C;foo'); + }); + +}); diff --git a/test/tags/raw.js b/test/tags/raw.js new file mode 100644 index 000000000..141745d54 --- /dev/null +++ b/test/tags/raw.js @@ -0,0 +1,24 @@ +const Liquid = require('../..'); +const chai = require("chai"); +const expect = chai.expect; +chai.use(require("chai-as-promised")); + +describe('tags/raw', function() { + var liquid = Liquid(); + it('should support raw 1', function() { + return expect(liquid.parseAndRender('{% raw%}')) + .to.be.rejectedWith(/{% raw%} not closed/); + }); + it('should support raw 2', function() { + var src = '{% raw %}{{ 5 | plus: 6 }}{% endraw %} is equal to 11.'; + var dst = '{{ 5 | plus: 6 }} is equal to 11.'; + return expect(liquid.parseAndRender(src)) + .to.eventually.equal(dst); + }); + it('should support raw 3', function() { + var src = '{% raw %}\n{{ foo}} \n{% endraw %}'; + var dst = '\n{{ foo}} \n'; + return expect(liquid.parseAndRender(src)) + .to.eventually.equal(dst); + }); +}); diff --git a/test/tags/tablerow.js b/test/tags/tablerow.js new file mode 100644 index 000000000..acac2033d --- /dev/null +++ b/test/tags/tablerow.js @@ -0,0 +1,71 @@ +const Liquid = require('../..'); +const chai = require("chai"); +const expect = chai.expect; +const error = require('../../src/error.js'); +chai.use(require("chai-as-promised")); + +describe('tags/tablerow', function() { + var liquid = Liquid(); + + it('should support tablerow', function() { + var src = '{% tablerow i in alpha cols:2 %}{{ i }}{% endtablerow %}'; + var ctx = { + alpha: ['a', 'b', 'c'] + }; + var dst = '' + + '' + + '' + + '
ab
c
'; + return expect(liquid.parseAndRender(src, ctx)).to.eventually.equal(dst); + }); + + it('should support empty tablerow', function() { + var src = '{% tablerow i in (1..0) cols:2 %}{{ i }}{% endtablerow %}'; + var dst = '
'; + return expect(liquid.parseAndRender(src)).to.eventually.equal(dst); + }); + + it('should throw when tablerow not closed', function() { + var src = '{% tablerow i in (1..0) cols:2 %}{{ i }}'; + return expect(liquid.parseAndRender(src)) + .to.be.rejectedWith(/tag .* not closed/); + }); + + it('should support tablerow with range', function() { + var src = '{% tablerow i in (1..5) cols:2 %}{{ i }}{% endtablerow %}'; + var dst = '' + + '' + + '' + + '' + + '
12
34
5
'; + return expect(liquid.parseAndRender(src)).to.eventually.equal(dst); + }); + + it('tablerow should throw on illegal cols 1', function() { + var src = '{% tablerow i in (1..5) cols:0 %}{{ i }}{% endtablerow %}'; + return expect(liquid.parseAndRender(src)) + .to.be.rejectedWith(/illegal cols: 0/); + }); + it('tablerow should throw on illegal cols 2', function() { + var src = '{% tablerow i in (1..5) %}{{ i }}{% endtablerow %}'; + return expect(liquid.parseAndRender(src)) + .to.be.rejectedWith(/illegal cols: undefined/); + }); + + it('should support tablerow with limit', function() { + var src = '{% tablerow i in (1..5) cols:2 limit:3 %}{{ i }}{% endtablerow %}'; + var dst = '' + + '' + + '' + + '
12
3
'; + return expect(liquid.parseAndRender(src)).to.eventually.equal(dst); + }); + + it('should support tablerow with offset', function() { + var src = '{% tablerow i in (1..5) cols:2 offset:3 %}{{ i }}{% endtablerow %}'; + var dst = '' + + '' + + '
45
'; + return expect(liquid.parseAndRender(src)).to.eventually.equal(dst); + }); +}); diff --git a/test/tags/unless.js b/test/tags/unless.js new file mode 100644 index 000000000..43921d6e2 --- /dev/null +++ b/test/tags/unless.js @@ -0,0 +1,29 @@ +const Liquid = require('../..'); +const chai = require("chai"); +const expect = chai.expect; +chai.use(require("chai-as-promised")); + +describe('tags/unless', function() { + var liquid = Liquid(); + + it('should support unless 1', function() { + var src = '{% unless 1 %}yes{%else%}no{%endunless%}'; + return expect(liquid.parseAndRender(src)) + .to.eventually.equal('no'); + }); + it('should support unless 2', function() { + var src = '{% unless 1>2 %}yes'; + return expect(liquid.parseAndRender(src)) + .to.be.rejectedWith(/tag {% unless 1>2 %} not closed/); + }); + it('should support unless 3', function() { + var src = '{% unless 1>2 %}yes{%endunless%}'; + return expect(liquid.parseAndRender(src)) + .to.eventually.equal('yes'); + }); + it('should support unless 4', function() { + var src = '{% unless true %}{%endunless%}'; + return expect(liquid.parseAndRender(src)) + .to.eventually.equal(''); + }); +});