Got first test working in async - nested includes

This commit is contained in:
Tim Hardy
2016-08-28 23:28:06 -05:00
parent 698bbd75cf
commit 4626f8f6bf
5 changed files with 69 additions and 21 deletions
+19 -5
View File
@@ -12,6 +12,7 @@ const Template = require('./src/parser');
const Expression = require('./src/expression.js'); const Expression = require('./src/expression.js');
const tags = require('./tags'); const tags = require('./tags');
const filters = require('./filters'); const filters = require('./filters');
const Promise = require("bluebird");
var _engine = { var _engine = {
init: function(tag, filter, options) { init: function(tag, filter, options) {
@@ -43,8 +44,14 @@ var _engine = {
}, },
renderFile: function(filepath, ctx) { renderFile: function(filepath, ctx) {
try{ try{
var tpl = this.handleCache(filepath); return this.handleCache(filepath)
return this.render(tpl, ctx); .then((templates) => {
return this.render(templates, ctx);
})
.catch((e) => {
e.file = filepath;
throw e;
});
} }
catch(e){ catch(e){
e.file = filepath; e.file = filepath;
@@ -67,9 +74,16 @@ var _engine = {
if (path.extname(filepath) === '') { if (path.extname(filepath) === '') {
filepath += this.options.extname; filepath += this.options.extname;
} }
var tpl = this.options.cache && this.cache[filepath] ||
this.parse(fs.readFileSync(filepath, 'utf8')); return this.getTemplate(filepath)
return this.options.cache ? (this.cache[filepath] = tpl) : tpl; .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() { express: function() {
return (filePath, options, callback) => { return (filePath, options, callback) => {
+2
View File
@@ -23,11 +23,13 @@
}, },
"homepage": "https://github.com/harttle/shopify-liquid#readme", "homepage": "https://github.com/harttle/shopify-liquid#readme",
"dependencies": { "dependencies": {
"bluebird": "^3.4.3",
"lodash": "^4.13.1", "lodash": "^4.13.1",
"strftime": "^0.9.2" "strftime": "^0.9.2"
}, },
"devDependencies": { "devDependencies": {
"chai": "^3.5.0", "chai": "^3.5.0",
"chai-as-promised": "^5.3.0",
"coveralls": "^2.11.9", "coveralls": "^2.11.9",
"express": "^4.14.0", "express": "^4.14.0",
"istanbul": "^0.4.3", "istanbul": "^0.4.3",
+17 -9
View File
@@ -1,30 +1,38 @@
const error = require('./error.js'); const error = require('./error.js');
const Exp = require('./expression.js'); const Exp = require('./expression.js');
const assert = require('assert'); const assert = require('assert');
const Promise = require("bluebird");
var render = { var render = {
renderTemplates: function(templates, scope) { renderTemplates: function(templates, scope) {
assert(scope, 'unable to evalTemplates: scope undefined'); assert(scope, 'unable to evalTemplates: scope undefined');
var html = '', var htmlBlocks = [],
partial; partial,
templates.some(template => { promises = [];
templates.some((template, index) => {
if (scope.get('forloop.skip')) return true; if (scope.get('forloop.skip')) return true;
switch (template.type) { switch (template.type) {
case 'tag': case 'tag':
partial = this.renderTag(template, scope, this.register); promises.push(this.renderTag(template, scope, this.register)
if (partial === undefined) return true; .then((partial) => {
html += partial; if (partial === undefined) return true;
return htmlBlocks[index] = partial;
}));
break; break;
case 'html': case 'html':
html += template.value; promises.push(Promise.resolve(htmlBlocks[index] = template.value));
break; break;
case 'output': case 'output':
var val = this.evalOutput(template, scope); var val = this.evalOutput(template, scope);
html += val === undefined ? '' : stringify(val); htmlBlocks[index] = val === undefined ? '' : stringify(val);
promises.push(Promise.resolve(htmlBlocks[index]));
} }
}); });
return html; return Promise.all(promises)
.then((results) => {
return htmlBlocks.join('');
});
}, },
renderTag: function(template, scope, register) { renderTag: function(template, scope, register) {
+11 -5
View File
@@ -1,4 +1,5 @@
var Liquid = require('..'); var Liquid = require('..');
var Promise = require("bluebird");
var lexical = Liquid.lexical; var lexical = Liquid.lexical;
var withRE = new RegExp(`with\\s+(${lexical.value.source})`); var withRE = new RegExp(`with\\s+(${lexical.value.source})`);
@@ -20,11 +21,16 @@ module.exports = function(liquid) {
if(this.with){ if(this.with){
hash[filepath] = Liquid.evalValue(this.with, scope); hash[filepath] = Liquid.evalValue(this.with, scope);
} }
var tpl = liquid.handleCache(filepath); return liquid.handleCache(filepath)
scope.push(hash); .then((templates) => {
var html = liquid.renderer.renderTemplates(tpl, scope); scope.push(hash);
scope.pop(); return liquid.renderer.renderTemplates(templates, scope);
return html; })
.then((html) => {
scope.pop();
return html;
});
} }
}); });
+20 -2
View File
@@ -1,7 +1,9 @@
const chai = require("chai"); const chai = require("chai");
const should = chai.should();
const expect = chai.expect; const expect = chai.expect;
const Liquid = require('..'); const Liquid = require('..');
const mock = require('mock-fs'); const mock = require('mock-fs');
chai.use(require("chai-as-promised"));
var liquid = Liquid({ var liquid = Liquid({
root: '/', root: '/',
extname: '.html' extname: '.html'
@@ -28,7 +30,14 @@ describe('tags', function() {
foo: 'bar', foo: 'bar',
arr: [-2, 'a'], arr: [-2, 'a'],
alpha: ['a', 'b', 'c'], alpha: ['a', 'b', 'c'],
emptyArray: [] emptyArray: [],
person: {
firstName: 'Joe',
lastName: 'Shmoe',
address: {
city: 'Dallas'
}
}
}; };
mock({ mock({
'/default-layout.html': 'foo{% block %}Default{% endblock %}foo', '/default-layout.html': 'foo{% block %}Default{% endblock %}foo',
@@ -42,7 +51,10 @@ describe('tags', function() {
'/color.html': 'color:{{color}}, shape:{{shape}}', '/color.html': 'color:{{color}}, shape:{{shape}}',
'/with.html': '{% include "color" with "red", shape: "rect" %}', '/with.html': '{% include "color" with "red", shape: "rect" %}',
'/scope.html': '{% assign shape="triangle" %}{% assign color="yellow" %}{% include "color.html" %}', '/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() { afterEach(function() {
@@ -266,6 +278,12 @@ describe('tags', function() {
var dst = 'color:red, shape:rect'; var dst = 'color:red, shape:rect';
expect(liquid.renderFile(filepath, ctx)).to.equal(dst); expect(liquid.renderFile(filepath, ctx)).to.equal(dst);
}); });
it.only('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() { it('should throw when block not closed', function() {
src = '{% layout "default-layout" %}{%block%}bar'; src = '{% layout "default-layout" %}{%block%}bar';
testThrow(src, /tag {%block%} not closed/); testThrow(src, /tag {%block%} not closed/);