mirror of
https://github.com/harttle/liquidjs.git
synced 2026-10-03 00:55:13 -07:00
feature: root option allows array of strings
This commit is contained in:
@@ -45,7 +45,7 @@ engine.render(tpl, {name: 'alice'})
|
|||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var engine = Liquid({
|
var engine = Liquid({
|
||||||
root: path.resolve(__dirname, 'views/'), // for layouts and partials
|
root: path.resolve(__dirname, 'views/'), // for layouts and includes
|
||||||
extname: '.liquid',
|
extname: '.liquid',
|
||||||
cache: false
|
cache: false
|
||||||
});
|
});
|
||||||
@@ -60,7 +60,13 @@ engine.renderFile("hello", {name: 'alice'})
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
`cache` default to `false`, `extname` default to `.liquid`, `root` default to `""`.
|
* `root` is a directory or an array of directories to resolve layouts and includes, as well as the filename passed in when calling `.renderFile()`.
|
||||||
|
If an array, the files are looked up in the order they occur in the array.
|
||||||
|
Defaults to `["."]`
|
||||||
|
|
||||||
|
* `extname` is used to lookup the template file when filepath doesn't include an extension name. Defaults to `.liquid`
|
||||||
|
|
||||||
|
* `cache` indicates whether or not to cache resolved templates. Defaults to `false`.
|
||||||
|
|
||||||
## Strict Rendering
|
## Strict Rendering
|
||||||
|
|
||||||
@@ -95,7 +101,9 @@ app.set('views', './views'); // specify the views directory
|
|||||||
app.set('view engine', 'liquid'); // set to default
|
app.set('view engine', 'liquid'); // set to default
|
||||||
```
|
```
|
||||||
|
|
||||||
There's an Express demo [here](demo/express/).
|
> There's an Express demo [here](demo/express/).
|
||||||
|
|
||||||
|
Note: includes and layouts lookup path should always be specified by `Liquid({root: []})`.
|
||||||
|
|
||||||
## Use in Browser
|
## Use in Browser
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
var express = require('express');
|
||||||
|
var app = express();
|
||||||
|
var Liquid = require('../..');
|
||||||
|
|
||||||
|
var engine = Liquid({
|
||||||
|
root: __dirname, // for layouts and partials
|
||||||
|
extname: '.liquid'
|
||||||
|
});
|
||||||
|
|
||||||
|
app.engine('liquid', engine.express()); // register liquid engine
|
||||||
|
app.set('views', __dirname); // specify the views directory
|
||||||
|
app.set('view engine', 'liquid'); // set to default
|
||||||
|
|
||||||
|
app.get('/', function (req, res) {
|
||||||
|
var todos = ['fork and clone', 'make it better', 'make a pull request'];
|
||||||
|
res.render('todolist', {
|
||||||
|
todos: todos,
|
||||||
|
title: 'Welcome to shopify-liquid!'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = app;
|
||||||
@@ -1 +0,0 @@
|
|||||||
<footer>Copyright @ 2016, Harttle</footer>
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title></title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>Welcome to shopify-liquid!</h1>
|
|
||||||
{% include 'bar' %}
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
+2
-16
@@ -1,20 +1,6 @@
|
|||||||
var express = require('express');
|
const app = require('./app.js');
|
||||||
var app = express();
|
|
||||||
var Liquid = require('..');
|
|
||||||
|
|
||||||
var engine = Liquid({
|
|
||||||
root: __dirname, // for layouts and partials
|
|
||||||
extname: '.liquid'
|
|
||||||
});
|
|
||||||
|
|
||||||
app.engine('liquid', engine.express()); // register liquid engine
|
|
||||||
app.set('views', __dirname); // specify the views directory
|
|
||||||
app.set('view engine', 'liquid'); // set to default
|
|
||||||
|
|
||||||
app.get('/', function (req, res) {
|
|
||||||
res.render('foo');
|
|
||||||
});
|
|
||||||
|
|
||||||
app.listen(3000, function () {
|
app.listen(3000, function () {
|
||||||
console.log('Example app listening on port 3000!');
|
console.log('Example app listening on port 3000!');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>{{title}}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>{{title}}</h1>
|
||||||
|
|
||||||
|
{% block %}
|
||||||
|
|
||||||
|
<footer> {% block footer %} </footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{{id}} - {{todo}}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{% layout 'layout' %}
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
{% for todo in todolist %}
|
||||||
|
<li>{% include 'todo' id=forloop.index %}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{% block 'footer' %}
|
||||||
|
Copyright @ 2016, Harttle
|
||||||
|
{% endblock %}
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
const Scope = require('./src/scope');
|
const Scope = require('./src/scope');
|
||||||
|
const _ = require('./src/util/underscore.js');
|
||||||
const tokenizer = require('./src/tokenizer.js');
|
const tokenizer = require('./src/tokenizer.js');
|
||||||
const fs = require('fs');
|
const statFileAsync = require('./src/util/fs.js').statFileAsync;
|
||||||
|
const readFileAsync = require('./src/util/fs.js').readFileAsync;
|
||||||
|
const pathResolve = require('./src/util/fs.js').pathResolve;
|
||||||
const Render = require('./src/render.js');
|
const Render = require('./src/render.js');
|
||||||
const lexical = require('./src/lexical.js');
|
const lexical = require('./src/lexical.js');
|
||||||
const Tag = require('./src/tag.js');
|
const Tag = require('./src/tag.js');
|
||||||
@@ -10,6 +13,7 @@ const Syntax = require('./src/syntax.js');
|
|||||||
const tags = require('./tags');
|
const tags = require('./tags');
|
||||||
const filters = require('./filters');
|
const filters = require('./filters');
|
||||||
const Promise = require('any-promise');
|
const Promise = require('any-promise');
|
||||||
|
const someSeries = require('./src/util/promise.js').someSeries;
|
||||||
|
|
||||||
var _engine = {
|
var _engine = {
|
||||||
init: function(tag, filter, options) {
|
init: function(tag, filter, options) {
|
||||||
@@ -53,7 +57,7 @@ var _engine = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
renderFile: function(filepath, ctx, opts) {
|
renderFile: function(filepath, ctx, opts) {
|
||||||
return this.handleCache(filepath)
|
return this.getTemplate(filepath)
|
||||||
.then((templates) => {
|
.then((templates) => {
|
||||||
return this.render(templates, ctx, opts);
|
return this.render(templates, ctx, opts);
|
||||||
})
|
})
|
||||||
@@ -72,30 +76,34 @@ var _engine = {
|
|||||||
registerTag: function(name, tag) {
|
registerTag: function(name, tag) {
|
||||||
return this.tag.register(name, tag);
|
return this.tag.register(name, tag);
|
||||||
},
|
},
|
||||||
handleCache: function(filepath) {
|
lookup: function(filepath) {
|
||||||
if (!filepath) throw new Error('filepath cannot be null');
|
var paths = this.options.root.map(root => pathResolve(root, filepath));
|
||||||
|
return someSeries(paths, path => statFileAsync(path).then(() => path));
|
||||||
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) {
|
getTemplate: function(filepath) {
|
||||||
filepath = resolvePath(this.options.root, filepath);
|
|
||||||
|
|
||||||
if (!filepath.match(/\.\w+$/)) {
|
if (!filepath.match(/\.\w+$/)) {
|
||||||
filepath += this.options.extname;
|
filepath += this.options.extname;
|
||||||
}
|
}
|
||||||
return new Promise(function(resolve, reject) {
|
return this
|
||||||
fs.readFile(filepath, 'utf8', function(err, html) {
|
.lookup(filepath)
|
||||||
err ? reject(err) : resolve(html);
|
.then(filepath => {
|
||||||
|
if (this.options.cache) {
|
||||||
|
var tpl = this.cache[filepath];
|
||||||
|
if (tpl) {
|
||||||
|
return Promise.resolve(tpl);
|
||||||
|
}
|
||||||
|
return readFileAsync(filepath)
|
||||||
|
.then(str => this.parse(str))
|
||||||
|
.then(tpl => this.cache[filepath] = tpl);
|
||||||
|
} else {
|
||||||
|
return readFileAsync(filepath).then(str => this.parse(str));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
},
|
},
|
||||||
express: function(renderingOptions) {
|
express: function(renderOption) {
|
||||||
|
renderOption = renderOption || {};
|
||||||
return (filePath, options, callback) => {
|
return (filePath, options, callback) => {
|
||||||
this.renderFile(filePath, options, renderingOptions)
|
this.renderFile(filePath, options, renderOption)
|
||||||
.then(html => callback(null, html))
|
.then(html => callback(null, html))
|
||||||
.catch(e => callback(e));
|
.catch(e => callback(e));
|
||||||
};
|
};
|
||||||
@@ -104,7 +112,9 @@ var _engine = {
|
|||||||
|
|
||||||
function factory(options) {
|
function factory(options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
options.root = options.root || '';
|
options.root = normalizeStringArray(options.root);
|
||||||
|
if (!options.root.length) options.root = ['.'];
|
||||||
|
|
||||||
options.extname = options.extname || '.liquid';
|
options.extname = options.extname || '.liquid';
|
||||||
|
|
||||||
var engine = Object.create(_engine);
|
var engine = Object.create(_engine);
|
||||||
@@ -113,17 +123,10 @@ function factory(options) {
|
|||||||
return engine;
|
return engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolvePath(root, path) {
|
function normalizeStringArray(value) {
|
||||||
if (path[0] == '/') return path;
|
if (_.isArray(value)) return value;
|
||||||
|
if (_.isString(value)) return [value];
|
||||||
var arr = root.split('/').concat(path.split('/'));
|
return [];
|
||||||
var result = [];
|
|
||||||
arr.forEach(function(slug) {
|
|
||||||
if (slug == '..') result.pop();
|
|
||||||
else if (!slug || slug == '.');
|
|
||||||
else result.push(slug);
|
|
||||||
});
|
|
||||||
return '/' + result.join('/');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
factory.lexical = lexical;
|
factory.lexical = lexical;
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
function readFileAsync(filepath) {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
fs.readFile(filepath, 'utf8', function(err, content) {
|
||||||
|
err ? reject(err) : resolve(content);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function statFileAsync(path) {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
fs.stat(path, (err, stat) => err ? reject(err) : resolve(stat))
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function pathResolve(root, path) {
|
||||||
|
if (path[0] == '/') return path;
|
||||||
|
|
||||||
|
var arr = root.split('/').concat(path.split('/'));
|
||||||
|
var result = [];
|
||||||
|
arr.forEach(function(slug) {
|
||||||
|
if (slug == '..') result.pop();
|
||||||
|
else if (!slug || slug == '.');
|
||||||
|
else result.push(slug);
|
||||||
|
});
|
||||||
|
return '/' + result.join('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
readFileAsync,
|
||||||
|
pathResolve,
|
||||||
|
statFileAsync
|
||||||
|
};
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
const Promise = require('any-promise');
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call functions in serial until someone resolved.
|
||||||
|
* @param {Array} iterable the array to iterate with.
|
||||||
|
* @param {Array} iteratee returns a new promise.
|
||||||
|
* The iteratee is invoked with three arguments: (value, index, iterable).
|
||||||
|
*/
|
||||||
|
function someSeries(iterable, iteratee) {
|
||||||
|
var ret = Promise.reject(new Error('init'));
|
||||||
|
iterable.forEach(function(item, idx) {
|
||||||
|
ret = ret
|
||||||
|
.then(x => x)
|
||||||
|
.catch(e => iteratee(item, idx, iterable));
|
||||||
|
});
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.someSeries = someSeries;
|
||||||
@@ -13,7 +13,7 @@ function isString(value) {
|
|||||||
* Iteratee functions may exit iteration early by explicitly returning false.
|
* Iteratee functions may exit iteration early by explicitly returning false.
|
||||||
* @param {Object} object The object to iterate over.
|
* @param {Object} object The object to iterate over.
|
||||||
* @param {Function} iteratee The function invoked per iteration.
|
* @param {Function} iteratee The function invoked per iteration.
|
||||||
* @return {Object} Returs object.
|
* @return {Object} Returns object.
|
||||||
*/
|
*/
|
||||||
function forOwn(object, iteratee) {
|
function forOwn(object, iteratee) {
|
||||||
object = object || {};
|
object = object || {};
|
||||||
@@ -25,5 +25,10 @@ function forOwn(object, iteratee) {
|
|||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isArray(value) {
|
||||||
|
return value instanceof Array;
|
||||||
|
}
|
||||||
|
|
||||||
exports.isString = isString;
|
exports.isString = isString;
|
||||||
|
exports.isArray = isArray;
|
||||||
exports.forOwn = forOwn;
|
exports.forOwn = forOwn;
|
||||||
|
|||||||
+1
-2
@@ -20,7 +20,7 @@ module.exports = function(liquid) {
|
|||||||
if(this.with){
|
if(this.with){
|
||||||
hash[filepath] = Liquid.evalValue(this.with, scope);
|
hash[filepath] = Liquid.evalValue(this.with, scope);
|
||||||
}
|
}
|
||||||
return liquid.handleCache(filepath)
|
return liquid.getTemplate(filepath)
|
||||||
.then((templates) => {
|
.then((templates) => {
|
||||||
scope.push(hash);
|
scope.push(hash);
|
||||||
return liquid.renderer.renderTemplates(templates, scope);
|
return liquid.renderer.renderTemplates(templates, scope);
|
||||||
@@ -29,7 +29,6 @@ module.exports = function(liquid) {
|
|||||||
scope.pop();
|
scope.pop();
|
||||||
return html;
|
return html;
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+6
-6
@@ -12,7 +12,7 @@ module.exports = function(liquid) {
|
|||||||
this.layout = match[0];
|
this.layout = match[0];
|
||||||
this.tpls = liquid.parser.parse(remainTokens);
|
this.tpls = liquid.parser.parse(remainTokens);
|
||||||
},
|
},
|
||||||
render: function(scope, hash) {
|
render: function(scope) {
|
||||||
var layout = Liquid.evalValue(this.layout, scope);
|
var layout = Liquid.evalValue(this.layout, scope);
|
||||||
|
|
||||||
var html = '';
|
var html = '';
|
||||||
@@ -21,7 +21,7 @@ module.exports = function(liquid) {
|
|||||||
return liquid.renderer.renderTemplates(this.tpls, scope)
|
return liquid.renderer.renderTemplates(this.tpls, scope)
|
||||||
.then((partial) => {
|
.then((partial) => {
|
||||||
html += partial;
|
html += partial;
|
||||||
return liquid.handleCache(layout);
|
return liquid.getTemplate(layout);
|
||||||
})
|
})
|
||||||
.then((templates) => {
|
.then((templates) => {
|
||||||
return liquid.renderer.renderTemplates(templates, scope);
|
return liquid.renderer.renderTemplates(templates, scope);
|
||||||
@@ -43,15 +43,15 @@ module.exports = function(liquid) {
|
|||||||
this.block = match ? match[0] : 'anonymous';
|
this.block = match ? match[0] : 'anonymous';
|
||||||
|
|
||||||
this.tpls = [];
|
this.tpls = [];
|
||||||
var p, stream = liquid.parser.parseStream(remainTokens)
|
var stream = liquid.parser.parseStream(remainTokens)
|
||||||
.on('tag:endblock', token => stream.stop())
|
.on('tag:endblock', () => stream.stop())
|
||||||
.on('template', tpl => this.tpls.push(tpl))
|
.on('template', tpl => this.tpls.push(tpl))
|
||||||
.on('end', x => {
|
.on('end', () => {
|
||||||
throw new Error(`tag ${token.raw} not closed`);
|
throw new Error(`tag ${token.raw} not closed`);
|
||||||
});
|
});
|
||||||
stream.start();
|
stream.start();
|
||||||
},
|
},
|
||||||
render: function(scope, hash){
|
render: function(scope){
|
||||||
var html = scope.get(`_liquid.blocks.${this.block}`);
|
var html = scope.get(`_liquid.blocks.${this.block}`);
|
||||||
var promise = Promise.resolve('');
|
var promise = Promise.resolve('');
|
||||||
if (html === undefined) {
|
if (html === undefined) {
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
const chai = require("chai");
|
||||||
|
const expect = chai.expect;
|
||||||
|
const mock = require('mock-fs');
|
||||||
|
const request = require('supertest');
|
||||||
|
const express = require('express');
|
||||||
|
const Liquid = require('..');
|
||||||
|
|
||||||
|
describe('engine#express()', function() {
|
||||||
|
var app, engine;
|
||||||
|
|
||||||
|
before(function() {
|
||||||
|
mock({
|
||||||
|
'/root/foo.html': 'foo',
|
||||||
|
'/views/name.html': 'My name is {{name}}.',
|
||||||
|
'/views/include.html': '{% include file %}',
|
||||||
|
'/partials/bar.html': 'bar'
|
||||||
|
});
|
||||||
|
app = express();
|
||||||
|
engine = Liquid({
|
||||||
|
root: '/root',
|
||||||
|
extname: '.html'
|
||||||
|
});
|
||||||
|
|
||||||
|
app.set('views', ['/views', '/partials']);
|
||||||
|
app.set('view engine', 'html');
|
||||||
|
app.engine('html', engine.express());
|
||||||
|
|
||||||
|
app.get('/name', function(req, res) {
|
||||||
|
res.render('name', {
|
||||||
|
name: 'harttle'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
app.get('/include/:file', function(req, res) {
|
||||||
|
res.render('include', {
|
||||||
|
file: req.params.file
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('should render templates', function(done) {
|
||||||
|
request(app).get('/name')
|
||||||
|
.expect('My name is harttle.')
|
||||||
|
.expect(200, done);
|
||||||
|
});
|
||||||
|
it('should pass error when file not found', function(done) {
|
||||||
|
var view = {
|
||||||
|
root: []
|
||||||
|
};
|
||||||
|
var file = '/not-exist.html';
|
||||||
|
var ctx = {};
|
||||||
|
engine.express().call(view, file, ctx, function(err) {
|
||||||
|
expect(err.code).to.equal('ENOENT');
|
||||||
|
console.log(err.message);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('should respect root option when lookup', function(done) {
|
||||||
|
request(app).get('/include/foo')
|
||||||
|
.expect('foo')
|
||||||
|
.expect(200, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
+33
-36
@@ -1,10 +1,9 @@
|
|||||||
const chai = require("chai");
|
const chai = require("chai");
|
||||||
const chaiAsPromised = require("chai-as-promised");
|
|
||||||
const should = chai.should();
|
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(chaiAsPromised);
|
chai.use(require("chai-as-promised"));
|
||||||
|
|
||||||
describe('liquid', function() {
|
describe('liquid', function() {
|
||||||
var engine, ctx;
|
var engine, ctx;
|
||||||
@@ -28,24 +27,26 @@ describe('liquid', function() {
|
|||||||
afterEach(function() {
|
afterEach(function() {
|
||||||
mock.restore();
|
mock.restore();
|
||||||
});
|
});
|
||||||
it('should output object', function() {
|
describe('{{output}}', function() {
|
||||||
return engine.parseAndRender('{{obj}}', ctx).should.eventually.equal('{"foo":"bar"}');
|
it('should output object', function() {
|
||||||
});
|
return engine.parseAndRender('{{obj}}', ctx).should.eventually.equal('{"foo":"bar"}');
|
||||||
it('should output array', function() {
|
});
|
||||||
return engine.parseAndRender('{{arr}}', ctx).should.eventually.equal('[-2,"a"]');
|
it('should output array', function() {
|
||||||
});
|
return engine.parseAndRender('{{arr}}', ctx).should.eventually.equal('[-2,"a"]');
|
||||||
it('should output undefined to empty', function() {
|
});
|
||||||
return engine.parseAndRender('foo{{zzz}}bar', ctx).should.eventually.equal('foobar');
|
it('should output undefined to empty', function() {
|
||||||
});
|
return engine.parseAndRender('foo{{zzz}}bar', ctx).should.eventually.equal('foobar');
|
||||||
it('should render as null when filter undefined', function() {
|
});
|
||||||
return engine.parseAndRender('{{arr | filter1}}', ctx).should.eventually.equal('');
|
it('should render as null when filter undefined', function() {
|
||||||
});
|
return engine.parseAndRender('{{arr | filter1}}', ctx).should.eventually.equal('');
|
||||||
it('should throw upon undefined filter when strict_filters set', function() {
|
});
|
||||||
var opts = {
|
it('should throw upon undefined filter when strict_filters set', function() {
|
||||||
strict_filters: true
|
var opts = {
|
||||||
};
|
strict_filters: true
|
||||||
return expect(engine.parseAndRender('{{arr | filter1}}', ctx, opts)).to
|
};
|
||||||
.be.rejectedWith(/undefined filter: filter1/);
|
return expect(engine.parseAndRender('{{arr | filter1}}', ctx, opts)).to
|
||||||
|
.be.rejectedWith(/undefined filter: filter1/);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
it('should parse html', function() {
|
it('should parse html', function() {
|
||||||
(function() {
|
(function() {
|
||||||
@@ -77,10 +78,20 @@ describe('liquid', function() {
|
|||||||
});
|
});
|
||||||
describe('#renderFile()', function() {
|
describe('#renderFile()', function() {
|
||||||
it('should render file', function() {
|
it('should render file', function() {
|
||||||
return engine.renderFile('/root/files/foo.html', ctx).should.eventually.equal('foo');
|
return expect(engine.renderFile('/root/files/foo.html', ctx))
|
||||||
|
.to.eventually.equal('foo');
|
||||||
});
|
});
|
||||||
it('should accept relative path', function() {
|
it('should accept relative path', function() {
|
||||||
return expect(engine.renderFile('files/foo.html')).to.eventually.equal('foo');
|
return expect(engine.renderFile('files/foo.html'))
|
||||||
|
.to.eventually.equal('foo');
|
||||||
|
});
|
||||||
|
it('should resolve array as root', function(){
|
||||||
|
engine = Liquid({
|
||||||
|
root: ['/boo', '/root/'],
|
||||||
|
extname: '.html'
|
||||||
|
});
|
||||||
|
return expect(engine.renderFile('files/foo.html'))
|
||||||
|
.to.eventually.equal('foo');
|
||||||
});
|
});
|
||||||
it('should render file with context', function() {
|
it('should render file with context', function() {
|
||||||
return engine.renderFile('/root/files/name.html', ctx).should.eventually.equal('My name is harttle.');
|
return engine.renderFile('/root/files/name.html', ctx).should.eventually.equal('My name is harttle.');
|
||||||
@@ -102,19 +113,6 @@ describe('liquid', function() {
|
|||||||
return expect(engine.renderFile('files/foo/../foo.html')).to.eventually.equal('foo');
|
return expect(engine.renderFile('files/foo/../foo.html')).to.eventually.equal('foo');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
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('strict', function() {
|
describe('strict', function() {
|
||||||
it('should not throw when strict_variables false (default)', function() {
|
it('should not throw when strict_variables false (default)', function() {
|
||||||
return expect(engine.parseAndRender('before{{notdefined}}after', ctx)).to
|
return expect(engine.parseAndRender('before{{notdefined}}after', ctx)).to
|
||||||
@@ -163,7 +161,6 @@ describe('liquid', function() {
|
|||||||
.then((result) => {
|
.then((result) => {
|
||||||
return expect(result).to.equal('foo');
|
return expect(result).to.equal('foo');
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
const chai = require("chai");
|
||||||
|
const sinon = require('sinon');
|
||||||
|
const expect = chai.expect;
|
||||||
|
chai.use(require("chai-as-promised"));
|
||||||
|
chai.use(require("sinon-chai"));
|
||||||
|
|
||||||
|
var P = require('../../src/util/promise.js');
|
||||||
|
|
||||||
|
describe('util/promise', function() {
|
||||||
|
describe('.someSeries()', function() {
|
||||||
|
it('should resolve in series', function() {
|
||||||
|
var spy1 = sinon.spy(),
|
||||||
|
spy2 = sinon.spy();
|
||||||
|
return P
|
||||||
|
.someSeries(
|
||||||
|
['first', 'second'],
|
||||||
|
(item, idx) => new Promise(function(resolve, reject) {
|
||||||
|
if (idx === 0) {
|
||||||
|
setTimeout(function() {
|
||||||
|
spy1();
|
||||||
|
reject(new Error('first cb'));
|
||||||
|
}, 10);
|
||||||
|
} else {
|
||||||
|
spy2();
|
||||||
|
resolve('foo');
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.then(() => expect(spy2).to.have.been.calledAfter(spy1));
|
||||||
|
});
|
||||||
|
it('should reject when all rejected', function() {
|
||||||
|
var p = P.someSeries(['first', 'second', 'third'],
|
||||||
|
item => Promise.reject(new Error(item)));
|
||||||
|
return expect(p).to.be.rejectedWith("third");
|
||||||
|
});
|
||||||
|
it('should resolve the value that first callback resolved', () => {
|
||||||
|
var p = P.someSeries(['first', 'second'],
|
||||||
|
item => Promise.resolve(item));
|
||||||
|
return expect(p).to.eventually.equal('first');
|
||||||
|
});
|
||||||
|
it('should not call rest of callbacks once resolved', () => {
|
||||||
|
var spy = sinon.spy();
|
||||||
|
return P.someSeries(['first', 'second'], (item, idx) => {
|
||||||
|
if (idx > 0) {
|
||||||
|
spy();
|
||||||
|
}
|
||||||
|
return Promise.resolve(item);
|
||||||
|
})
|
||||||
|
.then(() => expect(spy).to.not.have.been.called);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -45,4 +45,12 @@ describe('util/underscore', function() {
|
|||||||
expect(spy).to.have.been.calledOnce;
|
expect(spy).to.have.been.calledOnce;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
describe('.isArray()', function() {
|
||||||
|
it('should return true for []', function() {
|
||||||
|
expect(_.isArray([])).to.be.true;
|
||||||
|
});
|
||||||
|
it('should return false for "foo"', function() {
|
||||||
|
expect(_.isArray("foo")).to.be.false;
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user