mirror of
https://github.com/harttle/liquidjs.git
synced 2026-09-16 21:00:40 -07:00
@@ -12,6 +12,7 @@ const Template = require('./src/parser');
|
||||
const Expression = require('./src/expression.js');
|
||||
const tags = require('./tags');
|
||||
const filters = require('./filters');
|
||||
const Promise = require('any-promise');
|
||||
|
||||
var _engine = {
|
||||
init: function(tag, filter, options) {
|
||||
@@ -38,19 +39,26 @@ var _engine = {
|
||||
return this.renderer.renderTemplates(tpl, scope.factory(ctx));
|
||||
},
|
||||
parseAndRender: function(html, ctx) {
|
||||
var tpl = this.parse(html);
|
||||
return this.render(tpl, ctx);
|
||||
},
|
||||
renderFile: function(filepath, ctx) {
|
||||
try{
|
||||
var tpl = this.handleCache(filepath);
|
||||
try {
|
||||
var tpl = this.parse(html);
|
||||
return this.render(tpl, ctx);
|
||||
}
|
||||
catch(e){
|
||||
e.file = filepath;
|
||||
throw e;
|
||||
catch (error) {
|
||||
// A throw inside of a then or catch of a Promise automatically rejects, but since we mix a sync call
|
||||
// with an async call, we need to do this in case the sync call throws.
|
||||
return Promise.reject(error);
|
||||
}
|
||||
},
|
||||
renderFile: function(filepath, ctx) {
|
||||
return this.handleCache(filepath)
|
||||
.then((templates) => {
|
||||
return this.render(templates, ctx);
|
||||
})
|
||||
.catch((e) => {
|
||||
e.file = filepath;
|
||||
throw e;
|
||||
});
|
||||
},
|
||||
evalOutput: function(str, scope) {
|
||||
var tpl = this.parser.parseOutput(str.trim());
|
||||
return this.renderer.evalOutput(tpl, scope);
|
||||
@@ -67,9 +75,16 @@ var _engine = {
|
||||
if (path.extname(filepath) === '') {
|
||||
filepath += this.options.extname;
|
||||
}
|
||||
var tpl = this.options.cache && this.cache[filepath] ||
|
||||
this.parse(fs.readFileSync(filepath, 'utf8'));
|
||||
return this.options.cache ? (this.cache[filepath] = tpl) : tpl;
|
||||
|
||||
return this.getTemplate(filepath)
|
||||
.then((html) => {
|
||||
var tpl = this.options.cache && this.cache[filepath] || this.parse(html);
|
||||
return this.options.cache ? (this.cache[filepath] = tpl) : tpl;
|
||||
});
|
||||
},
|
||||
getTemplate: function(filepath) {
|
||||
var html = fs.readFileSync(filepath, 'utf8');
|
||||
return Promise.resolve(html);
|
||||
},
|
||||
express: function() {
|
||||
return (filePath, options, callback) => {
|
||||
|
||||
@@ -23,11 +23,13 @@
|
||||
},
|
||||
"homepage": "https://github.com/harttle/shopify-liquid#readme",
|
||||
"dependencies": {
|
||||
"any-promise": "^1.3.0",
|
||||
"lodash": "^4.13.1",
|
||||
"strftime": "^0.9.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chai": "^3.5.0",
|
||||
"chai-as-promised": "^5.3.0",
|
||||
"coveralls": "^2.11.9",
|
||||
"express": "^4.14.0",
|
||||
"istanbul": "^0.4.3",
|
||||
|
||||
+68
-21
@@ -1,41 +1,88 @@
|
||||
const error = require('./error.js');
|
||||
const Exp = require('./expression.js');
|
||||
const assert = require('assert');
|
||||
const Promise = require('any-promise');
|
||||
|
||||
var render = {
|
||||
|
||||
renderTemplates: function(templates, scope) {
|
||||
assert(scope, 'unable to evalTemplates: scope undefined');
|
||||
var html = '',
|
||||
partial;
|
||||
templates.some(template => {
|
||||
if (scope.get('forloop.skip')) return true;
|
||||
switch (template.type) {
|
||||
case 'tag':
|
||||
partial = this.renderTag(template, scope, this.register);
|
||||
if (partial === undefined) return true;
|
||||
html += partial;
|
||||
break;
|
||||
case 'html':
|
||||
html += template.value;
|
||||
break;
|
||||
case 'output':
|
||||
var val = this.evalOutput(template, scope);
|
||||
html += val === undefined ? '' : stringify(val);
|
||||
}
|
||||
});
|
||||
return html;
|
||||
|
||||
var html = '';
|
||||
|
||||
// This executes an array of promises sequentially for every template in the templates array - http://webcache.googleusercontent.com/search?q=cache:rNbMUn9TPtkJ:joost.vunderink.net/blog/2014/12/15/processing-an-array-of-promises-sequentially-in-node-js/+&cd=5&hl=en&ct=clnk&gl=us
|
||||
// It's fundamentally equivalent to the following...
|
||||
// emptyPromise.then(renderTag(template0).then(renderTag(template1).then(renderTag(template2)...
|
||||
var lastPromise = templates.reduce((promise, template) => {
|
||||
return promise.then((partial) => {
|
||||
if (scope.get('forloop.skip')) {
|
||||
return Promise.resolve('');
|
||||
}
|
||||
if (scope.get('forloop.stop')) {
|
||||
throw new Error('forloop.stop'); // this will stop/break the sequential promise chain and go to the catch
|
||||
}
|
||||
|
||||
var promiseLink = Promise.resolve('');
|
||||
switch (template.type) {
|
||||
case 'tag':
|
||||
// Add Promises to the chain
|
||||
promiseLink = this.renderTag(template, scope, this.register)
|
||||
.then((partial) => {
|
||||
if (partial === undefined) {
|
||||
return true; // basically a noop (do nothing)
|
||||
}
|
||||
return html += partial;
|
||||
});
|
||||
break;
|
||||
case 'html':
|
||||
promiseLink = Promise.resolve(template.value)
|
||||
.then((partial) => {
|
||||
return html += partial;
|
||||
});
|
||||
break;
|
||||
case 'output':
|
||||
var val = this.evalOutput(template, scope);
|
||||
promiseLink = Promise.resolve(val === undefined ? '' : stringify(val))
|
||||
.then((partial) => {
|
||||
return html += partial;
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
return promiseLink;
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.message === 'forloop.skip') {
|
||||
// the error is a controlled, purposeful stop. so just return the html that we have up to this point
|
||||
return html;
|
||||
} else {
|
||||
// rethrow actual error
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
}, Promise.resolve('')); // start the reduce chain with a resolved Promise. After first run, the "promise" argument
|
||||
// in our reduce callback will be the returned promise from our "then" above. In this
|
||||
// case, that's the promise returned from this.renderTag or a resolved promise with raw html.
|
||||
|
||||
return lastPromise
|
||||
.then((renderedHtml) => {
|
||||
return renderedHtml;
|
||||
})
|
||||
.catch((error) => {
|
||||
throw error;
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
renderTag: function(template, scope, register) {
|
||||
if (template.name === 'continue') {
|
||||
scope.set('forloop.skip', true);
|
||||
return;
|
||||
return Promise.resolve('');
|
||||
}
|
||||
if (template.name === 'break') {
|
||||
scope.set('forloop.stop', true);
|
||||
scope.set('forloop.skip', true);
|
||||
return;
|
||||
return Promise.reject(new Error('forloop.stop')); // this will stop the sequential promise chain
|
||||
}
|
||||
return template.render(scope, register);
|
||||
},
|
||||
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
const lexical = require('./lexical.js');
|
||||
const Promise = require('any-promise');
|
||||
const Exp = require('./expression.js');
|
||||
const TokenizationError = require('./error.js').TokenizationError;
|
||||
|
||||
@@ -21,7 +22,7 @@ module.exports = function() {
|
||||
var reg = register[this.name];
|
||||
if(!reg) reg = register[this.name] = {};
|
||||
var obj = hash(this.token.args, scope);
|
||||
return this.tagImpl.render && this.tagImpl.render(scope, obj, reg) || '';
|
||||
return this.tagImpl.render && this.tagImpl.render(scope, obj, reg) || Promise.resolve('');
|
||||
},
|
||||
parse: function(token, tokens){
|
||||
this.type = 'tag';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
var Liquid = require('..');
|
||||
var Promise = require('any-promise');
|
||||
var lexical = Liquid.lexical;
|
||||
var re = new RegExp(`(${lexical.identifier.source})\\s*=(.*)`);
|
||||
|
||||
@@ -13,6 +14,7 @@ module.exports = function(liquid) {
|
||||
},
|
||||
render: function(scope, hash) {
|
||||
scope.set(this.key, liquid.evalOutput(this.value, scope));
|
||||
return Promise.resolve('');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
+4
-2
@@ -21,8 +21,10 @@ module.exports = function(liquid) {
|
||||
stream.start();
|
||||
},
|
||||
render: function(scope, hash) {
|
||||
var html = liquid.renderer.renderTemplates(this.templates, scope);
|
||||
scope.set(this.variable, html);
|
||||
return liquid.renderer.renderTemplates(this.templates, scope)
|
||||
.then((html) => {
|
||||
scope.set(this.variable, html);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
var Liquid = require('..');
|
||||
var Promise = require('any-promise');
|
||||
var lexical = Liquid.lexical;
|
||||
var groupRE = new RegExp(`^(?:(${lexical.value.source})\\s*:\\s*)?(.*)$`);
|
||||
var candidatesRE = new RegExp(lexical.value.source, 'g');
|
||||
@@ -37,7 +38,7 @@ module.exports = function(liquid) {
|
||||
idx = (idx + 1) % this.candidates.length;
|
||||
register[fingerprint] = idx;
|
||||
|
||||
return Liquid.evalValue(candidate, scope);
|
||||
return Promise.resolve(Liquid.evalValue(candidate, scope));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
+54
-10
@@ -1,4 +1,6 @@
|
||||
var Liquid = require('..');
|
||||
var Promise = require('any-promise');
|
||||
var _ = require('lodash');
|
||||
var lexical = Liquid.lexical;
|
||||
var re = new RegExp(`^(${lexical.identifier.source})\\s+in\\s+` +
|
||||
`(${lexical.value.source})` +
|
||||
@@ -36,15 +38,20 @@ module.exports = function(liquid) {
|
||||
return liquid.renderer.renderTemplates(this.elseTemplates, scope);
|
||||
}
|
||||
|
||||
var html = '',
|
||||
ctx = {},
|
||||
length = collection.length;
|
||||
var html = '';
|
||||
var length = collection.length;
|
||||
var offset = hash.offset || 0;
|
||||
var limit = (hash.limit === undefined) ? collection.length : hash.limit;
|
||||
|
||||
collection = collection.slice(offset, offset + limit);
|
||||
if(this.reversed) collection.reverse();
|
||||
|
||||
// for needs to execute the promises sequentially, not just resolve them sequentially, due to break and continue.
|
||||
// We can't just loop through executing everything then resolve them all sequentially like we do for render.renderTemplates
|
||||
// First, we build the array of parameters we are going to use for each call to renderTemplates
|
||||
var contexts = [];
|
||||
collection.some((item, i) => {
|
||||
var ctx = {};
|
||||
ctx[this.variable] = item;
|
||||
ctx.forloop = {
|
||||
first: i === 0,
|
||||
@@ -57,14 +64,51 @@ module.exports = function(liquid) {
|
||||
stop: false,
|
||||
skip: false
|
||||
};
|
||||
scope.push(ctx);
|
||||
html += liquid.renderer.renderTemplates(this.templates, scope);
|
||||
var breakloop = scope.get('forloop.stop');
|
||||
scope.pop(ctx);
|
||||
|
||||
if (breakloop) return true;
|
||||
// We are just putting together an array of the arguments we will be passing to our sequential promises
|
||||
contexts.push(ctx);
|
||||
});
|
||||
return html;
|
||||
|
||||
// This is some pretty tricksy javascript, at least to me.
|
||||
// This executes an array of promises sequentially for every argument in the contexts array - http://webcache.googleusercontent.com/search?q=cache:rNbMUn9TPtkJ:joost.vunderink.net/blog/2014/12/15/processing-an-array-of-promises-sequentially-in-node-js/+&cd=5&hl=en&ct=clnk&gl=us
|
||||
// It's fundamentally equivalent to the following...
|
||||
// emptyPromise.then(renderTemplates(args0).then(renderTemplates(args1).then(renderTemplates(args2)...
|
||||
var lastPromise = contexts.reduce((promise, context) => {
|
||||
return promise.then((partial) => {
|
||||
if (scope.get('forloop.stop')) {
|
||||
throw new Error('forloop.stop'); // this will stop the sequential promise chain
|
||||
}
|
||||
|
||||
return html += partial;
|
||||
})
|
||||
.then((partial) => {
|
||||
// todo: Make sure our scope management is sound here. Create some tests that revolve around loops
|
||||
// with sections that take differing amounts of time to complete. Make sure the order is maintained
|
||||
// and scope doesn't bleed over into other renderTemplate calls.
|
||||
scope.push(context);
|
||||
return liquid.renderer.renderTemplates(this.templates, scope);
|
||||
})
|
||||
.then((partial) => {
|
||||
scope.pop(context);
|
||||
return partial;
|
||||
});
|
||||
}, Promise.resolve('')); // start the reduce chain with a resolved Promise. After first run, the "promise" argument
|
||||
// in our reduce callback will be the returned promise from our "then" above. In this
|
||||
// case, the promise returned from liquid.renderer.renderTemplates.
|
||||
|
||||
return lastPromise
|
||||
.then((partial) => {
|
||||
return html += partial;
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.message === 'forloop.stop') {
|
||||
// the error is a controlled, purposeful stop. so just return the html that we have up to this point
|
||||
return html;
|
||||
} else {
|
||||
// rethrow actual error
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
+11
-5
@@ -1,4 +1,5 @@
|
||||
var Liquid = require('..');
|
||||
var Promise = require('any-promise');
|
||||
var lexical = Liquid.lexical;
|
||||
var withRE = new RegExp(`with\\s+(${lexical.value.source})`);
|
||||
|
||||
@@ -20,11 +21,16 @@ module.exports = function(liquid) {
|
||||
if(this.with){
|
||||
hash[filepath] = Liquid.evalValue(this.with, scope);
|
||||
}
|
||||
var tpl = liquid.handleCache(filepath);
|
||||
scope.push(hash);
|
||||
var html = liquid.renderer.renderTemplates(tpl, scope);
|
||||
scope.pop();
|
||||
return html;
|
||||
return liquid.handleCache(filepath)
|
||||
.then((templates) => {
|
||||
scope.push(hash);
|
||||
return liquid.renderer.renderTemplates(templates, scope);
|
||||
})
|
||||
.then((html) => {
|
||||
scope.pop();
|
||||
return html;
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
+45
-9
@@ -1,4 +1,5 @@
|
||||
var Liquid = require('..');
|
||||
var Promise = require('any-promise');
|
||||
var lexical = Liquid.lexical;
|
||||
var withRE = new RegExp(`with\\s+(${lexical.value.source})`);
|
||||
|
||||
@@ -14,13 +15,34 @@ module.exports = function(liquid) {
|
||||
},
|
||||
render: function(scope, hash) {
|
||||
var layout = Liquid.evalValue(this.layout, scope);
|
||||
var tpl = liquid.handleCache(layout);
|
||||
|
||||
var html = '';
|
||||
scope.push({});
|
||||
liquid.renderer.renderTemplates(this.tpls, scope);
|
||||
var html = liquid.renderer.renderTemplates(tpl, scope);
|
||||
scope.pop();
|
||||
return html;
|
||||
// not sure if this first one is needed, since the results are ignored
|
||||
return liquid.renderer.renderTemplates(this.tpls, scope)
|
||||
.then((partial) => {
|
||||
html += partial;
|
||||
return liquid.handleCache(layout)
|
||||
})
|
||||
.then((templates) => {
|
||||
return liquid.renderer.renderTemplates(templates, scope);
|
||||
})
|
||||
.then((partial) => {
|
||||
scope.pop();
|
||||
return partial;
|
||||
})
|
||||
.catch((e) => {
|
||||
e.file = layout;
|
||||
throw e;
|
||||
});
|
||||
|
||||
// var tpl = liquid.handleCache(layout);
|
||||
//
|
||||
// scope.push({});
|
||||
// liquid.renderer.renderTemplates(this.tpls, scope); // what's the point of this line?
|
||||
// var html = liquid.renderer.renderTemplates(tpl, scope);
|
||||
// scope.pop();
|
||||
// return html;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -40,11 +62,25 @@ module.exports = function(liquid) {
|
||||
},
|
||||
render: function(scope, hash){
|
||||
var html = scope.get(`_liquid.blocks.${this.block}`);
|
||||
if(html === undefined){
|
||||
html = liquid.renderer.renderTemplates(this.tpls, scope);
|
||||
var promise = Promise.resolve('');
|
||||
if (html === undefined) {
|
||||
promise = liquid.renderer.renderTemplates(this.tpls, scope)
|
||||
.then((partial) => {
|
||||
scope.set(`_liquid.blocks.${this.block}`, partial);
|
||||
return partial;
|
||||
});
|
||||
}
|
||||
scope.set(`_liquid.blocks.${this.block}`, html);
|
||||
return html;
|
||||
else {
|
||||
scope.set(`_liquid.blocks.${this.block}`, html);
|
||||
promise = Promise.resolve(html);
|
||||
}
|
||||
return promise;
|
||||
|
||||
// if(html === undefined){
|
||||
// html = liquid.renderer.renderTemplates(this.tpls, scope);
|
||||
// }
|
||||
// scope.set(`_liquid.blocks.${this.block}`, html);
|
||||
// return html;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
+3
-1
@@ -1,4 +1,5 @@
|
||||
var Liquid = require('..');
|
||||
var Promise = require('any-promise');
|
||||
var lexical = Liquid.lexical;
|
||||
var re = new RegExp(`(${lexical.identifier.source})`);
|
||||
|
||||
@@ -20,7 +21,8 @@ module.exports = function(liquid) {
|
||||
stream.start();
|
||||
},
|
||||
render: function(scope, hash) {
|
||||
return this.tokens.map(token => token.raw).join('');
|
||||
var tokens = this.tokens.map(token => token.raw).join('');
|
||||
return Promise.resolve(tokens);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
+52
-19
@@ -1,4 +1,5 @@
|
||||
var Liquid = require('..');
|
||||
var Promise = require('any-promise');
|
||||
var lexical = Liquid.lexical;
|
||||
var re = new RegExp(`^(${lexical.identifier.source})\\s+in\\s+` +
|
||||
`(${lexical.value.source})` +
|
||||
@@ -30,7 +31,7 @@ module.exports = function(liquid) {
|
||||
var collection = Liquid.evalExp(this.collection, scope) || [];
|
||||
|
||||
var html = '<table>',
|
||||
ctx = {},
|
||||
promiseChain = Promise.resolve(''); // create an empty promise to begin the chain
|
||||
length = collection.length;
|
||||
var offset = hash.offset || 0;
|
||||
var limit = (hash.limit === undefined) ? collection.length : hash.limit;
|
||||
@@ -38,26 +39,58 @@ module.exports = function(liquid) {
|
||||
var cols = hash.cols, row, col;
|
||||
if (!cols) throw new Error(`illegal cols: ${cols}`);
|
||||
|
||||
collection.slice(offset, offset + limit).some((item, i) => {
|
||||
row = Math.floor(i / cols) + 1;
|
||||
col = (i % cols) + 1;
|
||||
if(col === 1){
|
||||
if(row !== 1){
|
||||
// build array of arguments to pass to sequential promises...
|
||||
collection = collection.slice(offset, offset + limit);
|
||||
var contexts = [];
|
||||
collection.some((item, i) => {
|
||||
var ctx = {};
|
||||
ctx[this.variable] = item;
|
||||
// We are just putting together an array of the arguments we will be passing to our sequential promises
|
||||
contexts.push(ctx);
|
||||
});
|
||||
|
||||
// This executes an array of promises sequentially for every argument in the contexts array - http://webcache.googleusercontent.com/search?q=cache:rNbMUn9TPtkJ:joost.vunderink.net/blog/2014/12/15/processing-an-array-of-promises-sequentially-in-node-js/+&cd=5&hl=en&ct=clnk&gl=us
|
||||
// It's fundamentally equivalent to the following...
|
||||
// emptyPromise.then(renderTemplates(args0).then(renderTemplates(args1).then(renderTemplates(args2)...
|
||||
var lastPromise = contexts.reduce((promise, context, currentIndex) => {
|
||||
return promise.then((partial) => {
|
||||
row = Math.floor(currentIndex / cols) + 1;
|
||||
col = (currentIndex % cols) + 1;
|
||||
if(col === 1) {
|
||||
if(row !== 1){
|
||||
html += '</tr>';
|
||||
}
|
||||
html += `<tr class="row${row}">`;
|
||||
}
|
||||
|
||||
//ctx[this.variable] = context;
|
||||
|
||||
return html += `<td class="col${col}">`;
|
||||
})
|
||||
.then((partial) => {
|
||||
scope.push(context);
|
||||
return liquid.renderer.renderTemplates(this.templates, scope)
|
||||
})
|
||||
.then((partial) => {
|
||||
scope.pop(context);
|
||||
html += partial;
|
||||
return html += '</td>';
|
||||
});
|
||||
}, Promise.resolve('')); // start the reduce chain with a resolved Promise. After first run, the "promise" argument
|
||||
// in our reduce callback will be the returned promise from our "then" above. In this
|
||||
// case, the promise returned from liquid.renderer.renderTemplates.
|
||||
|
||||
return lastPromise
|
||||
.then(() => {
|
||||
if(row > 0) {
|
||||
html += '</tr>';
|
||||
}
|
||||
html += `<tr class="row${row}">`;
|
||||
}
|
||||
|
||||
ctx[this.variable] = item;
|
||||
scope.push(ctx);
|
||||
html += `<td class="col${col}">`;
|
||||
html += liquid.renderer.renderTemplates(this.templates, scope);
|
||||
html += '</td>';
|
||||
scope.pop(ctx);
|
||||
});
|
||||
if(row > 0) html += '</tr>';
|
||||
html += '</table>';
|
||||
return html;
|
||||
html += '</table>';
|
||||
return html;
|
||||
})
|
||||
.catch((error) => {
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
+14
-26
@@ -3,22 +3,20 @@ var expect = chai.expect;
|
||||
var engine = require('..')(), ctx;
|
||||
const mock = require('mock-fs');
|
||||
|
||||
function test(func, cb){
|
||||
try{
|
||||
func();
|
||||
cb({});
|
||||
}
|
||||
catch(e){
|
||||
cb(e);
|
||||
}
|
||||
function test(promise, cb){
|
||||
return promise
|
||||
.then((result) => {
|
||||
return cb({});
|
||||
})
|
||||
.catch((error) => {
|
||||
return cb(error);
|
||||
});
|
||||
}
|
||||
|
||||
describe('error', function() {
|
||||
|
||||
it('should throw TokenizationError when tag illegal', function() {
|
||||
test(function(){
|
||||
engine.parseAndRender('{% -a %}', {});
|
||||
}, function(err){
|
||||
return test(engine.parseAndRender('{% -a %}', {}), function(err){
|
||||
expect(err.name).to.equal('TokenizationError');
|
||||
expect(err.message).to.equal('illegal tag: {% -a %}');
|
||||
expect(err.input).to.equal('{% -a %}');
|
||||
@@ -27,9 +25,7 @@ describe('error', function() {
|
||||
});
|
||||
|
||||
it('should throw correct error info', function() {
|
||||
test(function(){
|
||||
engine.parseAndRender('{%if true%}\naaa{%endif%}\n{% -a %}\n3', {});
|
||||
}, function(err){
|
||||
return test(engine.parseAndRender('{%if true%}\naaa{%endif%}\n{% -a %}\n3', {}), function(err){
|
||||
expect(err.input).to.equal('{% -a %}');
|
||||
expect(err.line).to.equal(3);
|
||||
});
|
||||
@@ -39,9 +35,7 @@ describe('error', function() {
|
||||
mock({
|
||||
"/foo.html": '<html>\n<head>\n\n{% raw %}\n\n'
|
||||
});
|
||||
test(function(){
|
||||
engine.renderFile('/foo.html', {});
|
||||
}, function(err){
|
||||
return test(engine.renderFile('/foo.html', {}), function(err){
|
||||
expect(err.input).to.equal('{% raw %}');
|
||||
expect(err.line).to.equal(4);
|
||||
expect(err.file).to.equal('/foo.html');
|
||||
@@ -49,9 +43,7 @@ describe('error', function() {
|
||||
});
|
||||
|
||||
it('should throw ParseError when filter not exist', function() {
|
||||
test(function(){
|
||||
engine.parseAndRender('{{ a | xz }}', {});
|
||||
}, function(err){
|
||||
return test(engine.parseAndRender('{{ a | xz }}', {}), function(err){
|
||||
expect(err.name).to.equal('ParseError');
|
||||
expect(err.message).to.equal('filter "xz" not found');
|
||||
expect(err.input).to.equal('{{ a | xz }}');
|
||||
@@ -59,9 +51,7 @@ describe('error', function() {
|
||||
});
|
||||
});
|
||||
it('should throw ParseError when tag not exist', function() {
|
||||
test(function(){
|
||||
engine.parseAndRender('{% a %}', {});
|
||||
}, function(err){
|
||||
return test(engine.parseAndRender('{% a %}', {}), function(err){
|
||||
expect(err.name).to.equal('ParseError');
|
||||
expect(err.message).to.equal('tag a not found');
|
||||
expect(err.input).to.equal('{% a %}');
|
||||
@@ -70,9 +60,7 @@ describe('error', function() {
|
||||
});
|
||||
|
||||
it('should throw ParseError when tag not closed', function() {
|
||||
test(function(){
|
||||
engine.parseAndRender('{% if %}', {});
|
||||
}, function(err){
|
||||
return test(engine.parseAndRender('{% if %}', {}), function(err){
|
||||
expect(err.name).to.equal('ParseError');
|
||||
expect(err.message).to.equal('tag {% if %} not closed');
|
||||
expect(err.input).to.equal('{% if %}');
|
||||
|
||||
+102
-115
@@ -1,8 +1,10 @@
|
||||
const chai = require("chai");
|
||||
const chaiAsPromised = require("chai-as-promised");
|
||||
const should = chai.should();
|
||||
const expect = chai.expect;
|
||||
|
||||
var liquid = require('..')(),
|
||||
ctx;
|
||||
chai.use(chaiAsPromised);
|
||||
|
||||
function test(src, dst) {
|
||||
ctx = {
|
||||
@@ -18,106 +20,87 @@ function test(src, dst) {
|
||||
category: 'bar'
|
||||
}]
|
||||
};
|
||||
expect(liquid.parseAndRender(src, ctx)).to.equal(dst);
|
||||
return liquid.parseAndRender(src, ctx).should.eventually.equal(dst);
|
||||
}
|
||||
|
||||
describe('filters', function() {
|
||||
it('should support abs', function() {
|
||||
test('{{ -3 | abs }}', '3');
|
||||
test('{{ arr[0] | abs }}', '2');
|
||||
});
|
||||
it('should support abs 1', function() { return test('{{ -3 | abs }}', '3'); });
|
||||
it('should support abs 2', function() { return test('{{ arr[0] | abs }}', '2'); });
|
||||
|
||||
it('should support append', function() {
|
||||
test('{{ -3 | append: "abc" }}', '-3abc');
|
||||
test('{{ "a" | append: foo }}', 'abar');
|
||||
});
|
||||
it('should support append 1', function() { return test('{{ -3 | append: "abc" }}', '-3abc'); });
|
||||
it('should support append 2', function() { return test('{{ "a" | append: foo }}', 'abar');; });
|
||||
|
||||
it('should support capitalize', function() {
|
||||
test('{{ "i am good" | capitalize }}', 'I am good');
|
||||
});
|
||||
it('should support capitalize', function() { return test('{{ "i am good" | capitalize }}', 'I am good'); });
|
||||
|
||||
it('should support ceil', function() {
|
||||
test('{{ 1.2 | ceil }}', '2');
|
||||
test('{{ 2.0 | ceil }}', '2');
|
||||
test('{{ "3.5" | ceil }}', '4');
|
||||
test('{{ 183.357 | ceil }}', '184');
|
||||
});
|
||||
it('should support ceil 1', function() { return test('{{ 1.2 | ceil }}', '2'); });
|
||||
it('should support ceil 2', function() { return test('{{ 2.0 | ceil }}', '2'); });
|
||||
it('should support ceil 3', function() { return test('{{ "3.5" | ceil }}', '4'); });
|
||||
it('should support ceil 4', function() { return test('{{ 183.357 | ceil }}', '184'); });
|
||||
|
||||
it('should support date', function() {
|
||||
str = ctx.date.toDateString();
|
||||
test('{{ date | date:"%a %b %d %Y"}}', str);
|
||||
return test('{{ date | date:"%a %b %d %Y"}}', str);
|
||||
});
|
||||
|
||||
it('should support default', function() {
|
||||
test('{{false |default: "a"}}', 'a');
|
||||
});
|
||||
it('should support default', function() { return test('{{false |default: "a"}}', 'a'); });
|
||||
|
||||
it('should support divided_by', function() {
|
||||
test('{{4 | divided_by: 2}}', '2');
|
||||
test('{{16 | divided_by: 4}}', '4');
|
||||
test('{{5 | divided_by: 3}}', '1');
|
||||
});
|
||||
it('should support divided_by 1', function() { return test('{{4 | divided_by: 2}}', '2'); });
|
||||
it('should support divided_by 2', function() { return test('{{16 | divided_by: 4}}', '4'); });
|
||||
it('should support divided_by 3', function() { return test('{{5 | divided_by: 3}}', '1'); });
|
||||
|
||||
it('should support downcase', function() {
|
||||
test('{{ "Parker Moore" | downcase }}', 'parker moore');
|
||||
test('{{ "apple" | downcase }}', 'apple');
|
||||
});
|
||||
it('should support escape', function() {
|
||||
test('{{ "Have you read \'James & the Giant Peach\'?" | escape }}',
|
||||
it('should support downcase 1', function() { return test('{{ "Parker Moore" | downcase }}', 'parker moore'); });
|
||||
it('should support downcase 2', function() { return test('{{ "apple" | downcase }}', 'apple'); });
|
||||
|
||||
it('should support escape 1', function() {
|
||||
return test('{{ "Have you read \'James & the Giant Peach\'?" | escape }}',
|
||||
'Have you read 'James & the Giant Peach'?');
|
||||
test('{{ "Tetsuro Takara" | escape }}', 'Tetsuro Takara');
|
||||
});
|
||||
it('should support escape 2', function() {
|
||||
return test('{{ "Tetsuro Takara" | escape }}', 'Tetsuro Takara');
|
||||
});
|
||||
|
||||
it('should support escape_once', function() {
|
||||
test('{{ "1 < 2 & 3" | escape_once }}', '1 < 2 & 3');
|
||||
test('{{ "1 < 2 & 3" | escape_once }}', '1 < 2 & 3');
|
||||
});
|
||||
it('should support escape_once 1', function() { return test('{{ "1 < 2 & 3" | escape_once }}', '1 < 2 & 3'); });
|
||||
it('should support escape_once 2', function() { return test('{{ "1 < 2 & 3" | escape_once }}', '1 < 2 & 3'); });
|
||||
|
||||
it('should support split/first', function() {
|
||||
src = '{% assign my_array = "apples, oranges, peaches, plums" | split: ", " %}' +
|
||||
'{{ my_array | first }}';
|
||||
test(src, 'apples');
|
||||
return test(src, 'apples');
|
||||
});
|
||||
|
||||
it('should support floor', function() {
|
||||
test('{{ 1.2 | floor }}', '1');
|
||||
test('{{ 2.0 | floor }}', '2');
|
||||
test('{{ 183.357 | floor }}', '183');
|
||||
test('{{ "3.5" | floor }}', '3');
|
||||
});
|
||||
it('should support floor 1', function() { return test('{{ 1.2 | floor }}', '1'); });
|
||||
it('should support floor 2', function() { return test('{{ 2.0 | floor }}', '2'); });
|
||||
it('should support floor 3', function() { return test('{{ 183.357 | floor }}', '183'); });
|
||||
it('should support floor 4', function() { return test('{{ "3.5" | floor }}', '3'); });
|
||||
|
||||
it('should support join', function() {
|
||||
src = '{% assign beatles = "John, Paul, George, Ringo" | split: ", " %}' +
|
||||
'{{ beatles | join: " and " }}';
|
||||
test(src, 'John and Paul and George and Ringo');
|
||||
return test(src, 'John and Paul and George and Ringo');
|
||||
});
|
||||
|
||||
it('should support split/last', function() {
|
||||
src = '{% assign my_array = "zebra, octopus, giraffe, tiger" | split: ", " %}' +
|
||||
'{{ my_array|last }}';
|
||||
test(src, 'tiger');
|
||||
return test(src, 'tiger');
|
||||
});
|
||||
|
||||
it('should support lstrip', function() {
|
||||
src = '{{ " So much room for activities! " | lstrip }}';
|
||||
test(src, 'So much room for activities! ');
|
||||
return test(src, 'So much room for activities! ');
|
||||
});
|
||||
|
||||
it('should support map', function() {
|
||||
test('{{posts | map: "category"}}', '["foo","bar"]');
|
||||
return test('{{posts | map: "category"}}', '["foo","bar"]');
|
||||
});
|
||||
|
||||
it('should support minus', function() {
|
||||
test('{{ 4 | minus: 2 }}', '2');
|
||||
test('{{ 16 | minus: 4 }}', '12');
|
||||
test('{{ 183.357 | minus: 12 }}', '171.357');
|
||||
});
|
||||
it('should support minus 1', function() { return test('{{ 4 | minus: 2 }}', '2'); });
|
||||
it('should support minus 2', function() { return test('{{ 16 | minus: 4 }}', '12'); });
|
||||
it('should support minus 3', function() { return test('{{ 183.357 | minus: 12 }}', '171.357'); });
|
||||
|
||||
it('should support modulo', function() {
|
||||
test('{{ 3 | modulo: 2 }}', '1');
|
||||
test('{{ 24 | modulo: 7 }}', '3');
|
||||
test('{{ 183.357 | modulo: 12 }}', '3.357');
|
||||
});
|
||||
it('should support modulo 1', function() { return test('{{ 3 | modulo: 2 }}', '1'); });
|
||||
it('should support modulo 2', function() { return test('{{ 24 | modulo: 7 }}', '3'); });
|
||||
it('should support modulo 3', function() { return test('{{ 183.357 | modulo: 12 }}', '3.357'); });
|
||||
|
||||
it('should support string_with_newlines', function() {
|
||||
src = '{% capture string_with_newlines %}\n' +
|
||||
@@ -128,81 +111,75 @@ describe('filters', function() {
|
||||
dst = '<br />' +
|
||||
'Hello<br />' +
|
||||
'there<br />';
|
||||
test(src, dst);
|
||||
return test(src, dst);
|
||||
});
|
||||
|
||||
it('should support plus', function() {
|
||||
test('{{ 4 | plus: 2 }}', '6');
|
||||
test('{{ 16 | plus: 4 }}', '20');
|
||||
test('{{ 183.357 | plus: 12 }}', '195.357');
|
||||
});
|
||||
it('should support plus 1', function() { return test('{{ 4 | plus: 2 }}', '6'); });
|
||||
it('should support plus 2', function() { return test('{{ 16 | plus: 4 }}', '20'); });
|
||||
it('should support plus 3', function() { return test('{{ 183.357 | plus: 12 }}', '195.357'); });
|
||||
|
||||
it('should support prepend', function() {
|
||||
test('{% assign url = "liquidmarkup.com" %}' +
|
||||
return test('{% assign url = "liquidmarkup.com" %}' +
|
||||
'{{ "/index.html" | prepend: url }}',
|
||||
'liquidmarkup.com/index.html');
|
||||
});
|
||||
|
||||
it('should support remove', function() {
|
||||
test('{{ "I strained to see the train through the rain" | remove: "rain" }}',
|
||||
return test('{{ "I strained to see the train through the rain" | remove: "rain" }}',
|
||||
'I sted to see the t through the ');
|
||||
});
|
||||
|
||||
it('should support remove_first', function() {
|
||||
test('{{ "I strained to see the train through the rain" | remove_first: "rain" }}',
|
||||
return test('{{ "I strained to see the train through the rain" | remove_first: "rain" }}',
|
||||
'I sted to see the train through the rain');
|
||||
});
|
||||
|
||||
it('should support replace', function() {
|
||||
test('{{ "Take my protein pills and put my helmet on" | replace: "my", "your" }}',
|
||||
return test('{{ "Take my protein pills and put my helmet on" | replace: "my", "your" }}',
|
||||
'Take your protein pills and put your helmet on');
|
||||
});
|
||||
|
||||
it('should support replace_first', function() {
|
||||
test('{% assign my_string = "Take my protein pills and put my helmet on" %}\n' +
|
||||
return test('{% assign my_string = "Take my protein pills and put my helmet on" %}\n' +
|
||||
'{{ my_string | replace_first: "my", "your" }}',
|
||||
'\nTake your protein pills and put my helmet on');
|
||||
});
|
||||
|
||||
it('should support reverse', function() {
|
||||
test('{{ "Ground control to Major Tom." | split: "" | reverse | join: "" }}',
|
||||
return test('{{ "Ground control to Major Tom." | split: "" | reverse | join: "" }}',
|
||||
'.moT rojaM ot lortnoc dnuorG');
|
||||
});
|
||||
|
||||
it('should support round', function() {
|
||||
test('{{1.2|round}}', '1');
|
||||
test('{{2.7|round}}', '3');
|
||||
test('{{183.357|round: 2}}', '183.36');
|
||||
});
|
||||
it('should support round 1', function() { return test('{{1.2|round}}', '1'); });
|
||||
it('should support round 2', function() { return test('{{2.7|round}}', '3'); });
|
||||
it('should support round 3', function() { return test('{{183.357|round: 2}}', '183.36'); });
|
||||
|
||||
it('should support rstrip', function() {
|
||||
test('{{ " So much room for activities! " | rstrip }}',
|
||||
return test('{{ " So much room for activities! " | rstrip }}',
|
||||
' So much room for activities!');
|
||||
});
|
||||
|
||||
it('should support size', function() {
|
||||
test('{{ "Ground control to Major Tom." | size }}', '28');
|
||||
test('{% assign my_array = "apples, oranges, peaches, plums"' +
|
||||
it('should support size 1', function() { return test('{{ "Ground control to Major Tom." | size }}', '28'); });
|
||||
it('should support size 2', function() {
|
||||
return test('{% assign my_array = "apples, oranges, peaches, plums"' +
|
||||
' | split: ", " %}{{ my_array | size }}',
|
||||
'4');
|
||||
});
|
||||
|
||||
it('should support slice', function() {
|
||||
test('{{ "Liquid" | slice: 0 }}', 'L');
|
||||
test('{{ "Liquid" | slice: 2 }}', 'q');
|
||||
test('{{ "Liquid" | slice: 2, 5 }}', 'quid');
|
||||
test('{{ "Liquid" | slice: -3, 2 }}', 'ui');
|
||||
});
|
||||
it('should support slice 1', function() { return test('{{ "Liquid" | slice: 0 }}', 'L'); });
|
||||
it('should support slice 2', function() { return test('{{ "Liquid" | slice: 2 }}', 'q'); });
|
||||
it('should support slice 3', function() { return test('{{ "Liquid" | slice: 2, 5 }}', 'quid'); });
|
||||
it('should support slice 4', function() { return test('{{ "Liquid" | slice: -3, 2 }}', 'ui'); });
|
||||
|
||||
it('should support sort', function() {
|
||||
test('{% assign my_array = "zebra, octopus, giraffe, Sally Snake"' +
|
||||
return test('{% assign my_array = "zebra, octopus, giraffe, Sally Snake"' +
|
||||
' | split: ", " %}' +
|
||||
'{{ my_array | sort | join: ", " }}',
|
||||
'Sally Snake, giraffe, octopus, zebra');
|
||||
});
|
||||
|
||||
it('should support split', function() {
|
||||
test('{% assign beatles = "John, Paul, George, Ringo" | split: ", " %}' +
|
||||
return test('{% assign beatles = "John, Paul, George, Ringo" | split: ", " %}' +
|
||||
'{% for member in beatles %}' +
|
||||
'{{ member }} ' +
|
||||
'{% endfor %}',
|
||||
@@ -210,63 +187,73 @@ describe('filters', function() {
|
||||
});
|
||||
|
||||
it('should support strip', function() {
|
||||
test('{{ " So much room for activities! " | strip }}',
|
||||
return test('{{ " So much room for activities! " | strip }}',
|
||||
'So much room for activities!');
|
||||
});
|
||||
|
||||
it('should support strip_tml', function() {
|
||||
test('{{ "Have <em>you</em> read <strong>Ulysses</strong>?" | strip_html }}',
|
||||
it('should support strip_tml 1', function() {
|
||||
return test('{{ "Have <em>you</em> read <strong>Ulysses</strong>?" | strip_html }}',
|
||||
'Have you read Ulysses?');
|
||||
test('{{"<br/><br />< p ></p></ p >" | strip_html }}', '');
|
||||
});
|
||||
it('should support strip_tml 2', function() {
|
||||
return test('{{"<br/><br />< p ></p></ p >" | strip_html }}', '');
|
||||
});
|
||||
|
||||
it('should support strip_newlines', function() {
|
||||
test('{% capture string_with_newlines %}\n' +
|
||||
return test('{% capture string_with_newlines %}\n' +
|
||||
'Hello\nthere\n{% endcapture %}' +
|
||||
'{{ string_with_newlines | strip_newlines }}',
|
||||
'Hellothere');
|
||||
});
|
||||
|
||||
it('should support times', function() {
|
||||
test('{{ 3 | times: 2 }}', '6');
|
||||
test('{{ 24 | times: 7 }}', '168');
|
||||
test('{{ 183.357 | times: 12 }}', '2200.284');
|
||||
});
|
||||
it('should support times 1', function() { return test('{{ 3 | times: 2 }}', '6'); });
|
||||
it('should support times 2', function() { return test('{{ 24 | times: 7 }}', '168'); });
|
||||
it('should support times 3', function() { return test('{{ 183.357 | times: 12 }}', '2200.284'); });
|
||||
|
||||
it('should support truncate', function() {
|
||||
test('{{ "Ground control to Major Tom." | truncate: 20 }}',
|
||||
it('should support truncate 1', function() {
|
||||
return test('{{ "Ground control to Major Tom." | truncate: 20 }}',
|
||||
'Ground control to...');
|
||||
test('{{ "Ground control to Major Tom." | truncate: 80 }}',
|
||||
});
|
||||
it('should support truncate 2', function() {
|
||||
return test('{{ "Ground control to Major Tom." | truncate: 80 }}',
|
||||
'Ground control to Major Tom.');
|
||||
test('{{ "Ground control to Major Tom." | truncate: 25,", and so on" }}',
|
||||
});
|
||||
it('should support truncate 3', function() {
|
||||
return test('{{ "Ground control to Major Tom." | truncate: 25,", and so on" }}',
|
||||
'Ground control, and so on');
|
||||
test('{{ "Ground control to Major Tom." | truncate: 20, "" }}',
|
||||
});
|
||||
it('should support truncate 4', function() {
|
||||
return test('{{ "Ground control to Major Tom." | truncate: 20, "" }}',
|
||||
'Ground control to Ma');
|
||||
});
|
||||
|
||||
it('should support truncatewords', function() {
|
||||
test('{{ "Ground control to Major Tom." | truncatewords: 3 }}',
|
||||
it('should support truncatewords 1', function() {
|
||||
return test('{{ "Ground control to Major Tom." | truncatewords: 3 }}',
|
||||
'Ground control to...');
|
||||
test('{{ "Ground control to Major Tom." | truncatewords: 8 }}',
|
||||
});
|
||||
it('should support truncatewords 2', function() {
|
||||
return test('{{ "Ground control to Major Tom." | truncatewords: 8 }}',
|
||||
'Ground control to Major Tom.');
|
||||
test('{{ "Ground control to Major Tom." | truncatewords: 3, "--" }}',
|
||||
});
|
||||
it('should support truncatewords 3', function() {
|
||||
return test('{{ "Ground control to Major Tom." | truncatewords: 3, "--" }}',
|
||||
'Ground control to--');
|
||||
test('{{ "Ground control to Major Tom." | truncatewords: 3, "" }}',
|
||||
});
|
||||
it('should support truncatewords 4', function() {
|
||||
return test('{{ "Ground control to Major Tom." | truncatewords: 3, "" }}',
|
||||
'Ground control to');
|
||||
});
|
||||
|
||||
it('should support uniq', function() {
|
||||
test('{% assign my_array = "ants, bugs, bees, bugs, ants" | split: ", " %}' +
|
||||
return test('{% assign my_array = "ants, bugs, bees, bugs, ants" | split: ", " %}' +
|
||||
'{{ my_array | uniq | join: ", " }}',
|
||||
'ants, bugs, bees');
|
||||
});
|
||||
|
||||
it('should support upcase', function() {
|
||||
test('{{ "Parker Moore" | upcase }}', 'PARKER MOORE');
|
||||
return test('{{ "Parker Moore" | upcase }}', 'PARKER MOORE');
|
||||
});
|
||||
|
||||
it('should support url_encode', function() {
|
||||
test('{{ "[email protected]" | url_encode }}', 'john%40liquid.com');
|
||||
test('{{ "Tetsuro Takara" | url_encode }}', 'Tetsuro%20Takara');
|
||||
});
|
||||
it('should support url_encode 1', function() { return test('{{ "[email protected]" | url_encode }}', 'john%40liquid.com'); });
|
||||
it('should support url_encode 2', function() { return test('{{ "Tetsuro Takara" | url_encode }}', 'Tetsuro%20Takara'); });
|
||||
});
|
||||
|
||||
+50
-30
@@ -1,8 +1,10 @@
|
||||
const chai = require("chai");
|
||||
const chaiAsPromised = require("chai-as-promised");
|
||||
const should = chai.should();
|
||||
const expect = chai.expect;
|
||||
const should = chai.should;
|
||||
const Liquid = require('..');
|
||||
const mock = require('mock-fs');
|
||||
chai.use(chaiAsPromised);
|
||||
|
||||
describe('liquid', function() {
|
||||
var engine, ctx;
|
||||
@@ -27,13 +29,13 @@ describe('liquid', function() {
|
||||
mock.restore();
|
||||
});
|
||||
it('should output object', function() {
|
||||
engine.parseAndRender('{{obj}}', ctx).should.equal('{"foo":"bar"}');
|
||||
return engine.parseAndRender('{{obj}}', ctx).should.eventually.equal('{"foo":"bar"}');
|
||||
});
|
||||
it('should output array', function() {
|
||||
engine.parseAndRender('{{arr}}', ctx).should.equal('[-2,"a"]');
|
||||
return engine.parseAndRender('{{arr}}', ctx).should.eventually.equal('[-2,"a"]');
|
||||
});
|
||||
it('should output undefined to empty', function() {
|
||||
engine.parseAndRender('foo{{zzz}}bar', ctx).should.equal('foobar');
|
||||
return engine.parseAndRender('foo{{zzz}}bar', ctx).should.eventually.equal('foobar');
|
||||
});
|
||||
it('should parse html', function() {
|
||||
(function() {
|
||||
@@ -45,46 +47,55 @@ describe('liquid', function() {
|
||||
});
|
||||
it('should render template multiple times', function() {
|
||||
var template = engine.parse('{{obj}}');
|
||||
engine.render(template, ctx).should.equal('{"foo":"bar"}');
|
||||
engine.render(template, ctx).should.equal('{"foo":"bar"}');
|
||||
return engine.render(template, ctx)
|
||||
.then((result) => {
|
||||
expect(result).to.equal('{"foo":"bar"}');
|
||||
return engine.render(template, ctx);
|
||||
})
|
||||
.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('<p>{{arr | join: "_"}}</p>');
|
||||
engine.render(template, ctx).should.equal('<p>-2_a</p>');
|
||||
return engine.render(template, ctx).should.eventually.equal('<p>-2_a</p>');
|
||||
});
|
||||
describe('#renderFile()', function(){
|
||||
it('should render file', function() {
|
||||
engine.renderFile('/root/files/foo.html', ctx).should.equal('foo');
|
||||
return engine.renderFile('/root/files/foo.html', ctx).should.eventually.equal('foo');
|
||||
});
|
||||
it('should render file relative to root', function() {
|
||||
engine.renderFile('files/foo.html', ctx).should.equal('foo');
|
||||
return engine.renderFile('files/foo.html', ctx).should.eventually.equal('foo');
|
||||
});
|
||||
it('should render file with context', function() {
|
||||
engine.renderFile('/root/files/name.html', ctx).should.equal('My name is harttle.');
|
||||
return engine.renderFile('/root/files/name.html', ctx).should.eventually.equal('My name is harttle.');
|
||||
});
|
||||
it('should render file with default extname', function() {
|
||||
engine.renderFile('files/name', ctx).should.equal('My name is harttle.');
|
||||
});
|
||||
});
|
||||
describe('#express()', function() {
|
||||
it('should render templates', function() {
|
||||
engine.express()('/root/files/name.html', ctx, function(err, html) {
|
||||
expect(err).to.equal(null);
|
||||
expect(html).to.equal('My name is harttle.');
|
||||
});
|
||||
});
|
||||
it('should pass error when file not found', function() {
|
||||
engine.express()('/root/files/name1.html', ctx, function(err, html) {
|
||||
expect(err.code).to.equal('ENOENT');
|
||||
});
|
||||
return engine.renderFile('files/name', ctx).should.eventually.equal('My name is harttle.');
|
||||
});
|
||||
});
|
||||
// todo: make these async
|
||||
// describe('#express()', function() {
|
||||
// it('should render templates', function() {
|
||||
// engine.express()('/root/files/name.html', ctx, function(err, html) {
|
||||
// expect(err).to.equal(null);
|
||||
// expect(html).to.equal('My name is harttle.');
|
||||
// });
|
||||
// });
|
||||
// it('should pass error when file not found', function() {
|
||||
// engine.express()('/root/files/name1.html', ctx, function(err, html) {
|
||||
// expect(err.code).to.equal('ENOENT');
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
describe('cache', function() {
|
||||
it('should be disabled by default', function() {
|
||||
mock({
|
||||
'/root/files/foo.html': 'bar'
|
||||
});
|
||||
engine.renderFile('files/foo', ctx).should.equal('bar');
|
||||
return engine.renderFile('files/foo', ctx).should.eventually.equal('bar');
|
||||
});
|
||||
it('should respect cache=true option', function() {
|
||||
engine = Liquid({
|
||||
@@ -92,11 +103,20 @@ describe('liquid', function() {
|
||||
extname: '.html',
|
||||
cache: true
|
||||
});
|
||||
engine.renderFile('files/foo', ctx).should.equal('foo');
|
||||
mock({
|
||||
'/root/files/foo.html': 'bar'
|
||||
});
|
||||
engine.renderFile('files/foo', ctx).should.equal('foo');
|
||||
return engine.renderFile('files/foo', ctx)
|
||||
.then((result) => {
|
||||
return expect(result).to.equal('foo');
|
||||
})
|
||||
.then((result) => {
|
||||
mock({
|
||||
'/root/files/foo.html': 'bar'
|
||||
});
|
||||
return engine.renderFile('files/foo', ctx);
|
||||
})
|
||||
.then((result) => {
|
||||
return expect(result).to.equal('foo');
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+5
-5
@@ -1,9 +1,12 @@
|
||||
const chai = require("chai");
|
||||
const chaiAsPromised = require("chai-as-promised");
|
||||
const should = chai.should();
|
||||
const expect = chai.expect;
|
||||
const sinonChai = require("sinon-chai");
|
||||
const sinon = require("sinon");
|
||||
const expect = chai.expect;
|
||||
|
||||
chai.use(sinonChai);
|
||||
chai.use(chaiAsPromised);
|
||||
|
||||
var tag = require('../src/tag.js')();
|
||||
var Scope = require('../src/scope.js');
|
||||
@@ -26,10 +29,7 @@ describe('render', function() {
|
||||
});
|
||||
|
||||
it('should render html', function() {
|
||||
expect(render.renderTemplates([{
|
||||
type: 'html',
|
||||
value: '<p>'
|
||||
}], scope)).to.equal('<p>');
|
||||
return render.renderTemplates([{type: 'html', value: '<p>'}], scope).should.eventually.equal('<p>');
|
||||
});
|
||||
|
||||
it('should eval filter with correct arguments', function() {
|
||||
|
||||
+114
-99
@@ -1,7 +1,14 @@
|
||||
// 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'
|
||||
@@ -9,13 +16,14 @@ var liquid = Liquid({
|
||||
ctx, src, dst;
|
||||
|
||||
function test(src, dst) {
|
||||
expect(liquid.parseAndRender(src, ctx)).to.equal(dst);
|
||||
return liquid.parseAndRender(src, ctx)
|
||||
.then((result) => {
|
||||
return expect(result).to.equal(dst);
|
||||
});
|
||||
}
|
||||
|
||||
function testThrow(src, pattern) {
|
||||
expect(function() {
|
||||
liquid.parseAndRender(src, ctx);
|
||||
}).to.throw(pattern);
|
||||
return liquid.parseAndRender(src, ctx).should.eventually.be.rejectedWith(pattern);
|
||||
}
|
||||
|
||||
describe('tags', function() {
|
||||
@@ -28,7 +36,14 @@ describe('tags', function() {
|
||||
foo: 'bar',
|
||||
arr: [-2, 'a'],
|
||||
alpha: ['a', 'b', 'c'],
|
||||
emptyArray: []
|
||||
emptyArray: [],
|
||||
person: {
|
||||
firstName: 'Joe',
|
||||
lastName: 'Shmoe',
|
||||
address: {
|
||||
city: 'Dallas'
|
||||
}
|
||||
}
|
||||
};
|
||||
mock({
|
||||
'/default-layout.html': 'foo{% block %}Default{% endblock %}foo',
|
||||
@@ -42,83 +57,73 @@ describe('tags', function() {
|
||||
'/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 %}'
|
||||
'/hash.html': '{% assign name="harttle" %}{% include "user.html", role: "admin", alias: name %}',
|
||||
'/personInfo.html': 'This is a person {% include "card.html" %}',
|
||||
'/card.html': '<p>{{person.firstName}} {{person.lastName}}<br/>{% include "address" %}</p>',
|
||||
'/address.html': 'City: {{person.address.city}}'
|
||||
});
|
||||
});
|
||||
afterEach(function() {
|
||||
mock.restore();
|
||||
});
|
||||
|
||||
it('should support assign', function() {
|
||||
test('{% assign foo="bar" %}{{foo}}', 'bar');
|
||||
test('{% assign foo=(1..3) %}{{foo}}', '[1,2,3]');
|
||||
test('{% assign foo="a b" | capitalize | split: " " | first %}{{foo}}', 'A');
|
||||
});
|
||||
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', function() {
|
||||
testThrow('{% raw%}', /{% raw%} not closed/);
|
||||
test('{% raw %}{{ 5 | plus: 6 }}{% endraw %} is equal to 11.', '{{ 5 | plus: 6 }} is equal to 11.');
|
||||
test('{% raw %}\n{{ foo}} \n{% endraw %}', '\n{{ foo}} \n');
|
||||
});
|
||||
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', function() {
|
||||
testThrow('{% comment %}{% raw%}', /{% comment %} not closed/);
|
||||
test('My name is {% comment %}super{% endcomment %} Shopify.', 'My name is Shopify.');
|
||||
test('{% comment %}\n{{ foo}} \n{% endcomment %}', '');
|
||||
});
|
||||
|
||||
it('should support case', function() {
|
||||
testThrow('{% case "foo"%}', /{% case "foo"%} not closed/);
|
||||
test('{% case "foo"%}' +
|
||||
'{% when "foo" %}foo{% when "bar"%}bar' +
|
||||
'{%endcase%}', 'foo');
|
||||
test('{% case empty %}' +
|
||||
'{% when "foo" %}foo{% when ""%}bar' +
|
||||
'{%endcase%}', 'bar');
|
||||
test('{% case false %}' +
|
||||
'{% when "foo" %}foo{% when ""%}bar' +
|
||||
'{%endcase%}', '');
|
||||
test('{% case "a" %}' +
|
||||
'{% when "b" %}b{% when "c"%}c{%else %}d' +
|
||||
'{%endcase%}', 'd');
|
||||
});
|
||||
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 if', function() {
|
||||
testThrow('{% if false%}yes', /tag {% if false%} not closed/);
|
||||
test('{%if emptyArray%}a{%endif%}', '');
|
||||
test('{% if 2==3 %}yes{%else%}no{%endif%}', 'no');
|
||||
test('{% if 1>=2 and one<two %}a{%endif%}', '');
|
||||
test('{% if one!=two %}yes{%else%}no{%endif%}', 'yes');
|
||||
test('{% if false %}1{%elsif true%}2{%else%}3{%endif%}', '2');
|
||||
test('{%if false%}{%if true%}{%else%}a{%endif%}{%endif%}', '');
|
||||
});
|
||||
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 unless', function() {
|
||||
test('{% unless 1 %}yes{%else%}no{%endunless%}', 'no');
|
||||
testThrow('{% unless 1>2 %}yes', /tag {% unless 1>2 %} not closed/);
|
||||
test('{% unless 1>2 %}yes{%endunless%}', 'yes');
|
||||
test('{% unless true %}{%endunless%}', '');
|
||||
});
|
||||
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 one<two %}a{%endif%}', ''); });
|
||||
it('should support if 5', function() { return test('{% if one!=two %}yes{%else%}no{%endif%}', 'yes'); });
|
||||
it('should support if 6', function() { return test('{% if false %}1{%elsif true%}2{%else%}3{%endif%}', '2'); });
|
||||
it('should support if 7', function() { return test('{%if false%}{%if true%}{%else%}a{%endif%}{%endif%}', ''); });
|
||||
|
||||
it('should support capture', function() {
|
||||
test('{% capture f %}{{"a" | capitalize}}{%endcapture%}{{f}}', 'A');
|
||||
testThrow('{% capture = %}{%endcapture%}', /= not valid identifier/);
|
||||
});
|
||||
it('should support unless 1', function() { return test('{% unless 1 %}yes{%else%}no{%endunless%}', 'no'); });
|
||||
it('should support unless 2', function() { return testThrow('{% unless 1>2 %}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() {
|
||||
testThrow('{%capture c%}{{c}}', /tag .* not closed/);
|
||||
return testThrow('{%capture c%}{{c}}', /tag .* not closed/);
|
||||
});
|
||||
|
||||
it('should support for', function() {
|
||||
test('{%for c in alpha%}{{c}}{%endfor%}', 'abc');
|
||||
return test('{%for c in alpha%}{{c}}{%endfor%}', 'abc');
|
||||
});
|
||||
|
||||
it('should throw when for not closed', function() {
|
||||
testThrow('{%for c in alpha%}{{c}}', /tag .* not closed/);
|
||||
return testThrow('{%for c in alpha%}{{c}}', /tag .* not closed/);
|
||||
});
|
||||
|
||||
it('should support for else', function() {
|
||||
test('{%for c in ""%}a{%else%}b{%endfor%}', 'b');
|
||||
return test('{%for c in ""%}a{%else%}b{%endfor%}', 'b');
|
||||
});
|
||||
|
||||
it('should support for with forloop', function() {
|
||||
@@ -131,65 +136,65 @@ describe('tags', function() {
|
||||
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';
|
||||
test(src, dst);
|
||||
return test(src, dst);
|
||||
});
|
||||
|
||||
it('should support for with continue and break', function() {
|
||||
it('should support for with continue', function() {
|
||||
src = '{% for i in (1..5) %}' +
|
||||
'{% if i == 4 %}{% continue %}' +
|
||||
'{% else %}{{ i }}' +
|
||||
'{% endif %}' +
|
||||
'{% endfor %}';
|
||||
test(src, '1235');
|
||||
return test(src, '1235');
|
||||
});
|
||||
it('should support for with break', function() {
|
||||
src = '{% for i in (one..5) %}' +
|
||||
'{% if i == 4 %}{% break %}{% endif %}' +
|
||||
'{{ i }}' +
|
||||
'{% endfor %}';
|
||||
test(src, '123');
|
||||
return test(src, '123');
|
||||
});
|
||||
|
||||
it('should support for with limit and offset', function() {
|
||||
it('should support for with limit', function() {
|
||||
src = '{% for i in (1..5) limit:2 %}{{ i }}{% endfor %}';
|
||||
test(src, '12');
|
||||
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 %}';
|
||||
test(src, '67');
|
||||
return test(src, '67');
|
||||
});
|
||||
|
||||
it('should support for reversed', function() {
|
||||
src = '{% for i in (1..5) limit:2 reversed %}{{ i }}{% endfor %}';
|
||||
test(src, '21');
|
||||
return test(src, '21');
|
||||
});
|
||||
|
||||
it('should support cycle', function() {
|
||||
src = "{% cycle '1', '2', '3' %}";
|
||||
test(src + src + src + src, '1231');
|
||||
return test(src + src + src + src, '1231');
|
||||
});
|
||||
|
||||
it('should throw when cycle candidates empty', function() {
|
||||
testThrow('{%cycle%}', /empty candidates/);
|
||||
return testThrow('{%cycle%}', /empty candidates/);
|
||||
});
|
||||
|
||||
it('should support cycle in for block', function() {
|
||||
src = '{% for i in (1..5) %}{% cycle one, "e"%}{% endfor %}';
|
||||
test(src, '1e1e1');
|
||||
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'%}";
|
||||
test(src, '121');
|
||||
return test(src, '121');
|
||||
});
|
||||
|
||||
it('should support increment', function() {
|
||||
test('{% increment foo %}{%increment foo%}{{foo}}', '2');
|
||||
test('{% increment one %}{{one}}', '2');
|
||||
});
|
||||
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', function() {
|
||||
test('{% decrement foo %}{%decrement foo%}{{foo}}', '-2');
|
||||
test('{% decrement one %}{{one}}', '0');
|
||||
});
|
||||
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 %}';
|
||||
@@ -197,18 +202,18 @@ describe('tags', function() {
|
||||
'<tr class="row1"><td class="col1">a</td><td class="col2">b</td></tr>' +
|
||||
'<tr class="row2"><td class="col1">c</td></tr>' +
|
||||
'</table>';
|
||||
test(src, dst);
|
||||
return test(src, dst);
|
||||
});
|
||||
|
||||
it('should support empty tablerow', function() {
|
||||
src = '{% tablerow i in (1..0) cols:2 %}{{ i }}{% endtablerow %}';
|
||||
dst = '<table></table>';
|
||||
test(src, dst);
|
||||
return test(src, dst);
|
||||
});
|
||||
|
||||
it('should throw when tablerow not closed', function() {
|
||||
src = '{% tablerow i in (1..0) cols:2 %}{{ i }}';
|
||||
testThrow(src, /tag .* not closed/);
|
||||
return testThrow(src, /tag .* not closed/);
|
||||
});
|
||||
|
||||
it('should support tablerow with range', function() {
|
||||
@@ -218,13 +223,15 @@ describe('tags', function() {
|
||||
'<tr class="row2"><td class="col1">3</td><td class="col2">4</td></tr>' +
|
||||
'<tr class="row3"><td class="col1">5</td></tr>' +
|
||||
'</table>';
|
||||
test(src, dst);
|
||||
return test(src, dst);
|
||||
});
|
||||
|
||||
it('tablerow should throw on illegal cols', function() {
|
||||
testThrow('{% tablerow i in (1..5) cols:0 %}{{ i }}{% endtablerow %}',
|
||||
it('tablerow should throw on illegal cols 1', function() {
|
||||
return testThrow('{% tablerow i in (1..5) cols:0 %}{{ i }}{% endtablerow %}',
|
||||
/illegal cols: 0/);
|
||||
testThrow('{% tablerow i in (1..5) %}{{ i }}{% endtablerow %}',
|
||||
});
|
||||
it('tablerow should throw on illegal cols 2', function() {
|
||||
return testThrow('{% tablerow i in (1..5) %}{{ i }}{% endtablerow %}',
|
||||
/illegal cols: undefined/);
|
||||
});
|
||||
|
||||
@@ -234,7 +241,7 @@ describe('tags', function() {
|
||||
'<tr class="row1"><td class="col1">1</td><td class="col2">2</td></tr>' +
|
||||
'<tr class="row2"><td class="col1">3</td></tr>' +
|
||||
'</table>';
|
||||
test(src, dst);
|
||||
return test(src, dst);
|
||||
});
|
||||
|
||||
it('should support tablerow with offset', function() {
|
||||
@@ -242,48 +249,56 @@ describe('tags', function() {
|
||||
dst = '<table>' +
|
||||
'<tr class="row1"><td class="col1">4</td><td class="col2">5</td></tr>' +
|
||||
'</table>';
|
||||
test(src, dst);
|
||||
return test(src, dst);
|
||||
});
|
||||
|
||||
it('should support include', function() {
|
||||
expect(liquid.renderFile('/current.html', ctx)).to.equal('barFOObar');
|
||||
return liquid.renderFile('/current.html', ctx).should.eventually.equal('barFOObar');
|
||||
});
|
||||
|
||||
it('should support include with relative path', function() {
|
||||
expect(liquid.renderFile('relative.html', ctx)).to.equal('barfoobar');
|
||||
return liquid.renderFile('relative.html', ctx).should.eventually.equal('barfoobar');
|
||||
});
|
||||
|
||||
it('should support include: hash list', function() {
|
||||
expect(liquid.renderFile('hash.html', ctx)).to.equal('harttle : admin : harttle');
|
||||
return liquid.renderFile('hash.html', ctx).should.eventually.equal('harttle : admin : harttle');
|
||||
});
|
||||
|
||||
it('should support include: parent scope', function() {
|
||||
expect(liquid.renderFile('scope.html', ctx)).to.equal('color:yellow, shape:triangle');
|
||||
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';
|
||||
expect(liquid.renderFile(filepath, ctx)).to.equal(dst);
|
||||
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 <p>Joe Shmoe<br/>City: Dallas</p>');
|
||||
return liquid.renderFile('personInfo.html', ctx).should.eventually.equal('This is a person <p>Joe Shmoe<br/>City: Dallas</p>')
|
||||
});
|
||||
|
||||
it('should throw when block not closed', function() {
|
||||
src = '{% layout "default-layout" %}{%block%}bar';
|
||||
testThrow(src, /tag {%block%} not closed/);
|
||||
return testThrow(src, /tag {%block%} not closed/);
|
||||
});
|
||||
it('should support layout', function() {
|
||||
src = '{% layout "default-layout" %}{%block%}bar{%endblock%}';
|
||||
test(src, 'foobarfoo');
|
||||
return test(src, 'foobarfoo');
|
||||
});
|
||||
it('should support layout: multiple blocks', function() {
|
||||
src = '{% layout "multi-blocks-layout" %}' +
|
||||
'{%block a%}bara{%endblock%}' +
|
||||
'{%block b%}barb{%endblock%}';
|
||||
test(src, 'foobarabarbfoo');
|
||||
return test(src, 'foobarabarbfoo');
|
||||
});
|
||||
it('should support layout: nested', function() {
|
||||
it('should support layout: nested 1', function() {
|
||||
src = '{% layout "multi-blocks" %}{% block a%}A{%endblock%}{%block c%}C{%endblock%}';
|
||||
test(src, 'fooA;C;foo');
|
||||
return test(src, 'fooA;C;foo');
|
||||
});
|
||||
it('should support layout: nested 2', function() {
|
||||
src = '{% layout "multi-blocks" %}{%block c%}C{%endblock%}';
|
||||
test(src, 'fooaaa;C;foo');
|
||||
return test(src, 'fooaaa;C;foo');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user