Compare commits

...
8 Commits
Author SHA1 Message Date
harttle 79815784c1 1.7.8 2017-04-17 22:56:16 +08:00
harttle 2d793a63fe fix #29 2017-04-17 22:49:53 +08:00
harttle cc2b2ea5d1 1.7.7 2017-04-10 19:07:51 +08:00
Jun YangandGitHub 8ff9eeb51d Merge pull request #28 from wojtask9/master
support multiline tags
2017-04-10 19:06:16 +08:00
wojtask9 3bc7caa387 support multiline tags 2017-04-10 11:58:45 +02:00
harttle 20044c4256 1.7.6 2017-03-21 18:00:27 +08:00
chenosandJun Yang e72f295bd0 Comparison on NULL is always false (#27)
* All values in Liquid are truthy except nil and false.

* The falsy values are null, undefined and false.

* comparison on null
2017-03-21 14:54:26 +08:00
chenosandJun Yang 66774865f4 All values in Liquid are truthy except nil and false. (#26)
* All values in Liquid are truthy except nil and false.

* The falsy values are null, undefined and false.
2017-03-21 12:25:11 +08:00
15 changed files with 118 additions and 34 deletions
+11 -11
View File
@@ -591,7 +591,7 @@ var hash = new RegExp('(?:' + identifier.source + ')\\s*:\\s*(?:' + value.source
var hashCapture = new RegExp('(' + identifier.source + ')\\s*:\\s*(' + value.source + ')', 'g');
// full match
var tagLine = new RegExp('^\\s*(' + identifier.source + ')\\s*(.*)\\s*$');
var tagLine = new RegExp('^\\s*(' + identifier.source + ')\\s*([\\s\\S]*)\\s*$');
var literalLine = new RegExp('^' + literal.source + '$', 'i');
var variableLine = new RegExp('^' + variable.source + '$');
var numberLine = new RegExp('^' + number.source + '$');
@@ -662,16 +662,16 @@ var operators = {
return l != r;
},
'>': function _(l, r) {
return l > r;
return l !== null && r !== null && l > r;
},
'<': function _(l, r) {
return l < r;
return l !== null && r !== null && l < r;
},
'>=': function _(l, r) {
return l >= r;
return l !== null && r !== null && l >= r;
},
'<=': function _(l, r) {
return l <= r;
return l !== null && r !== null && l <= r;
},
'contains': function contains(l, r) {
if (!l) return false;
@@ -1016,7 +1016,7 @@ var Scope = {
name = str.slice(i + 2, j);
seq.push(name);
name = '';
i = j + 1;
i = j + 2;
}
}
// foo.bar
@@ -1116,12 +1116,11 @@ function evalValue(str, scope) {
}
function isTruthy(val) {
if (val instanceof Array) return !!val.length;
return !!val;
return !isFalsy(val);
}
function isFalsy(val) {
return !isTruthy(val);
return false === val || undefined === val || null === val;;
}
module.exports = {
@@ -1218,7 +1217,7 @@ function parse(html, filepath, options) {
html = whiteSpaceCtrl(html, options);
var tokens = [];
var syntax = /({%-?(.*?)-?%})|({{(.*?)}})/g;
var syntax = /({%-?([\s\S]*?)-?%})|({{([\s\S]*?)}})/g;
var result, htmlFragment, token;
var lastMatchEnd = 0,
lastMatchBegin = -1,
@@ -2086,7 +2085,8 @@ module.exports = function (liquid) {
var _this2 = this;
var collection = Liquid.evalExp(this.collection, scope);
if (Liquid.isFalsy(collection)) {
if (!Array.isArray(collection) || Array.isArray(collection) && collection.length === 0) {
return liquid.renderer.renderTemplates(this.elseTemplates, scope);
}
+2 -3
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "shopify-liquid",
"version": "1.7.5",
"version": "1.7.8",
"description": "A feature-rich Liquid template engine for Node.js and browsers, with compliance with the Ruby version.",
"main": "index.js",
"scripts": {
+1 -1
View File
@@ -27,7 +27,7 @@ var hash = new RegExp(`(?:${identifier.source})\\s*:\\s*(?:${value.source})`);
var hashCapture = new RegExp(`(${identifier.source})\\s*:\\s*(${value.source})`, 'g');
// full match
var tagLine = new RegExp(`^\\s*(${identifier.source})\\s*(.*)\\s*$`);
var tagLine = new RegExp(`^\\s*(${identifier.source})\\s*([\\s\\S]*)\\s*$`);
var literalLine = new RegExp(`^${literal.source}$`, 'i');
var variableLine = new RegExp(`^${variable.source}$`);
var numberLine = new RegExp(`^${number.source}$`);
+4 -4
View File
@@ -1,10 +1,10 @@
var operators = {
'==': (l, r) => l == r,
'!=': (l, r) => l != r,
'>': (l, r) => l > r,
'<': (l, r) => l < r,
'>=': (l, r) => l >= r,
'<=': (l, r) => l <= r,
'>': (l, r) => l !== null && r !== null && l > r,
'<': (l, r) => l !== null && r !== null && l < r,
'>=': (l, r) => l !== null && r !== null && l >= r,
'<=': (l, r) => l !== null && r !== null && l <= r,
'contains': (l, r) => {
if (!l) return false;
if (typeof l.indexOf !== 'function') return false;
+1 -1
View File
@@ -129,7 +129,7 @@ var Scope = {
name = str.slice(i + 2, j);
seq.push(name);
name = '';
i = j + 1;
i = j + 2;
}
}
// foo.bar
+2 -3
View File
@@ -43,12 +43,11 @@ function evalValue(str, scope) {
}
function isTruthy(val) {
if (val instanceof Array) return !!val.length;
return !!val;
return !isFalsy(val);
}
function isFalsy(val) {
return !isTruthy(val);
return false === val || undefined === val || null === val;;
}
module.exports = {
+1 -1
View File
@@ -9,7 +9,7 @@ function parse(html, filepath, options) {
html = whiteSpaceCtrl(html, options);
var tokens = [];
var syntax = /({%-?(.*?)-?%})|({{(.*?)}})/g;
var syntax = /({%-?([\s\S]*?)-?%})|({{([\s\S]*?)}})/g;
var result, htmlFragment, token;
var lastMatchEnd = 0, lastMatchBegin = -1, parsedLinesCount = 0;
+3 -1
View File
@@ -36,7 +36,9 @@ module.exports = function(liquid) {
render: function(scope, hash) {
var collection = Liquid.evalExp(this.collection, scope);
if (Liquid.isFalsy(collection)) {
if (!Array.isArray(collection) ||
(Array.isArray(collection) && collection.length === 0)) {
return liquid.renderer.renderTemplates(this.elseTemplates, scope);
}
+7 -1
View File
@@ -30,12 +30,18 @@ describe('scope', function() {
expect(scope.propertyAccessSeq('foo[foo]'))
.to.deep.equal(['foo', 'zoo']);
});
it('should handle nested access', function() {
it('should handle nested access 1', function() {
expect(scope.propertyAccessSeq('foo[bar.zoo]'))
.to.deep.equal(['foo', 'coo']);
});
it('should handle nested access 2', function() {
expect(scope.propertyAccessSeq('foo[bar["zoo"]]'))
.to.deep.equal(['foo', 'coo']);
});
it('should handle nested access 3', function() {
expect(scope.propertyAccessSeq('bar["foo"].zoo'))
.to.deep.equal(['bar', 'foo', 'zoo']);
});
});
describe('#get()', function() {
+2 -2
View File
@@ -62,9 +62,9 @@ describe('tag', function() {
});
token = {
type: 'tag',
value: 'foo aa:foo bb: arr[0] cc: 2.3 dd:bar.coo',
value: 'foo aa:foo bb: arr[0] cc: 2.3\ndd:bar.coo',
name: 'foo',
args: 'aa:foo bb: arr[0] cc: 2.3 dd:bar.coo'
args: 'aa:foo bb: arr[0] cc: 2.3\ndd:bar.coo'
};
});
it('should call tag.render with scope', function() {
+9 -2
View File
@@ -10,6 +10,7 @@ describe('tags/for', function() {
ctx = {
one: 1,
alpha: ['a', 'b', 'c'],
emptyArray: []
};
});
it('should support for', function() {
@@ -24,6 +25,12 @@ describe('tags/for', function() {
.to.be.rejectedWith(/tag .* not closed/);
});
it('should return else when for in empty array', function() {
var src = '{%for c in emptyArray%}a{%else%}b{%endfor%}';
return expect(liquid.parseAndRender(src, ctx))
.to.eventually.equal('b');
});
it('should support for else', function() {
var src = '{%for c in ""%}a{%else%}b{%endfor%}';
return expect(liquid.parseAndRender(src, ctx))
@@ -80,13 +87,13 @@ describe('tags/for', function() {
.to.eventually.equal('21');
});
it('should support for reversed in the middle position', function() {
it('should support for reversed in the first position', function() {
var src = '{% for i in (1..5) reversed limit:2 %}{{ i }}{% endfor %}';
return expect(liquid.parseAndRender(src, ctx))
.to.eventually.equal('21');
});
it('should support for reversed in the first position', function() {
it('should support for reversed in the middle position', function() {
var src = '{% for i in (1..5) offset:2 reversed limit:4 %}{{ i }}{% endfor %}';
return expect(liquid.parseAndRender(src, ctx))
.to.eventually.equal('543');
+56 -1
View File
@@ -8,6 +8,7 @@ describe('tags/if', function() {
var ctx = {
one: 1,
two: 2,
emptyString: '',
emptyArray: []
};
@@ -19,7 +20,7 @@ describe('tags/if', function() {
it('should support if 2', function() {
var src = '{%if emptyArray%}a{%endif%}';
return expect(liquid.parseAndRender(src, ctx))
.to.eventually.equal('');
.to.eventually.equal('a');
});
it('should support if 3', function() {
var src = '{% if 2==3 %}yes{%else%}no{%endif%}';
@@ -46,4 +47,58 @@ describe('tags/if', function() {
return expect(liquid.parseAndRender(src, ctx))
.to.eventually.equal('');
});
it('should return true if empty string', function() {
var src = "{%if emptyString%}a{%endif%}";
return expect(liquid.parseAndRender(src, ctx))
.to.eventually.equal('a');
});
it('should return else when comparison on null 1', function() {
var src = "{% if null < 10 %}yes{% else %}no{% endif %}";
return expect(liquid.parseAndRender(src, ctx))
.to.eventually.equal('no');
});
it('should return else when comparison on null 2', function() {
var src = "{% if null <= 10 %}yes{% else %}no{% endif %}";
return expect(liquid.parseAndRender(src, ctx))
.to.eventually.equal('no');
});
it('should return else when comparison on null 3', function() {
var src = "{% if null >= 10 %}yes{% else %}no{% endif %}";
return expect(liquid.parseAndRender(src, ctx))
.to.eventually.equal('no');
});
it('should return else when comparison on null 4', function() {
var src = "{% if null > 10 %}yes{% else %}no{% endif %}";
return expect(liquid.parseAndRender(src, ctx))
.to.eventually.equal('no');
});
it('should return else when comparison on null 5', function() {
var src = "{% if 10 < null %}yes{% else %}no{% endif %}";
return expect(liquid.parseAndRender(src, ctx))
.to.eventually.equal('no');
});
it('should return else when comparison on null 6', function() {
var src = "{% if 10 <= null %}yes{% else %}no{% endif %}";
return expect(liquid.parseAndRender(src, ctx))
.to.eventually.equal('no');
});
it('should return else when comparison on null 7', function() {
var src = "{% if 10 >= null %}yes{% else %}no{% endif %}";
return expect(liquid.parseAndRender(src, ctx))
.to.eventually.equal('no');
});
it('should return else when comparison on null 8', function() {
var src = "{% if 10 > null %}yes{% else %}no{% endif %}";
return expect(liquid.parseAndRender(src, ctx))
.to.eventually.equal('no');
});
});
+3 -2
View File
@@ -7,12 +7,13 @@ describe('tags/unless', function() {
var liquid = Liquid();
it('should render else when predicate yields true', function() {
var src = '{% unless 1 %}yes{%else%}no{%endunless%}';
// 0 is truthy
var src = '{% unless 0 %}yes{%else%}no{%endunless%}';
return expect(liquid.parseAndRender(src))
.to.eventually.equal('no');
});
it('should render unless when predicate yields false', function() {
var src = '{% unless 0 %}yes{%else%}no{%endunless%}';
var src = '{% unless false %}yes{%else%}no{%endunless%}';
return expect(liquid.parseAndRender(src))
.to.eventually.equal('yes');
});
+15
View File
@@ -56,6 +56,21 @@ describe('tokenizer', function() {
expect(tokens[3].type).to.equal('html');
expect(tokens[3].raw).to.equal(' \n ');
});
it('should handle multiple lines tag', function() {
var html = '{%foo\na:a\nb:1.23\n%}';
var tokens = parse(html);
expect(tokens.length).to.equal(1);
expect(tokens[0].type).to.equal('tag');
expect(tokens[0].args).to.equal('a:a\nb:1.23');
expect(tokens[0].raw).to.equal('{%foo\na:a\nb:1.23\n%}');
});
it('should handle multiple lines output', function() {
var html = '{{foo\n|\date:\n"%Y-%m-%d"\n}}';
var tokens = parse(html);
expect(tokens.length).to.equal(1);
expect(tokens[0].type).to.equal('output');
expect(tokens[0].raw).to.equal('{{foo\n|\date:\n"%Y-%m-%d"\n}}');
});
});
describe('whitespace control', function() {
it('should not strip by default', function() {