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 = '';
- 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 = '' +
- '| 1 | 2 |
' +
- '| 3 | 4 |
' +
- '| 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 = '';
- return test(src, dst);
- });
-
- it('should support tablerow with offset', function() {
- src = '{% tablerow i in (1..5) cols:2 offset:3 %}{{ i }}{% endtablerow %}';
- dst = '';
- 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 = '';
+ 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 = '' +
+ '| 1 | 2 |
' +
+ '| 3 | 4 |
' +
+ '| 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 = '';
+ 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 = '';
+ 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('');
+ });
+});