mirror of
https://github.com/harttle/liquidjs.git
synced 2026-09-29 07:05:13 -07:00
render, filter, tag
This commit is contained in:
@@ -0,0 +1,14 @@
|
|||||||
|
## Async Support
|
||||||
|
|
||||||
|
harttle/shopify-liquid do NOT support async rendering, this is by design.
|
||||||
|
|
||||||
|
The primary principle of harttle/shopify-liquid is EASY TO EXTEND.
|
||||||
|
Async rendering introduces extra complexity in both implementation and extension.
|
||||||
|
|
||||||
|
For template-driven projects, checkout these Liquid-like engines:
|
||||||
|
|
||||||
|
* [liquid-node][liquid-node]: <https://github.com/sirlantis/liquid-node>
|
||||||
|
* [nunjucks][nunjucks]: <http://mozilla.github.io/nunjucks/>
|
||||||
|
|
||||||
|
[nunjucks]: http://mozilla.github.io/nunjucks/
|
||||||
|
[liquid-node]: https://github.com/sirlantis/liquid-node
|
||||||
+19
-12
@@ -1,26 +1,33 @@
|
|||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const identifier = require('./identifier.js');
|
const lexical = require('./lexical.js');
|
||||||
|
|
||||||
var context = {
|
var context = {
|
||||||
get: function(str){
|
get: function(str) {
|
||||||
if(identifier.isLiteral(str)){
|
str = str && str.trim();
|
||||||
return identifier.parseLiteral(str);
|
if(!str) return '';
|
||||||
|
|
||||||
|
if (lexical.isLiteral(str)) {
|
||||||
|
var a = lexical.parseLiteral(str);
|
||||||
|
return lexical.parseLiteral(str);
|
||||||
}
|
}
|
||||||
if(identifier.isVariable(str)){
|
if (lexical.isVariable(str)) {
|
||||||
return _.get(this.context, str);
|
for (var i = this.context.length - 1; i >= 0; i--) {
|
||||||
|
var v = _.get(this.context[i], str);
|
||||||
|
if (v !== undefined) return v;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
},
|
},
|
||||||
init: function(ctx){
|
push: function(ctx) {
|
||||||
this.context = ctx;
|
return this.context.push(ctx);
|
||||||
},
|
},
|
||||||
merge: function(ctx){
|
pop: function() {
|
||||||
_.merge(this.context, ctx);
|
return this.context.pop();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.factory = function(_ctx){
|
exports.factory = function(_ctx) {
|
||||||
var ctx = Object.create(context);
|
var ctx = Object.create(context);
|
||||||
ctx.init(_ctx);
|
ctx.context = [_ctx];
|
||||||
return ctx;
|
return ctx;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
const lexical = require('./lexical.js');
|
||||||
|
const _ = require('lodash');
|
||||||
|
|
||||||
|
var filters = {};
|
||||||
|
|
||||||
|
var _filterInstance = {
|
||||||
|
render: function(output, ctx) {
|
||||||
|
var args = this.args.map(arg => ctx.get(arg));
|
||||||
|
args.unshift(output);
|
||||||
|
return this.filter.apply(null, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parse(str) {
|
||||||
|
var match = lexical.patterns.filterLine.exec(str.trim());
|
||||||
|
if (!match) {
|
||||||
|
throw new Error('illegal filter: ' + str);
|
||||||
|
}
|
||||||
|
var k = match[1],
|
||||||
|
v = match[2];
|
||||||
|
|
||||||
|
return factory(k, [v]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function factory(name, args) {
|
||||||
|
var filter = filters[name];
|
||||||
|
if (typeof filter !== 'function')
|
||||||
|
throw new Error(`filter ${name} not found`);
|
||||||
|
|
||||||
|
var instance = Object.create(_filterInstance);
|
||||||
|
instance.args = args;
|
||||||
|
instance.filter = filter;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
function register(name, filter) {
|
||||||
|
filters[name] = filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clear() {
|
||||||
|
filters = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.parse = parse;
|
||||||
|
exports.register = register;
|
||||||
|
exports.clear = clear;
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
const _ = require('lodash');
|
|
||||||
|
|
||||||
var singleQuoted = /^'[^']*'$/;
|
|
||||||
var doubleQuoted = /^"[^"]*"$/;
|
|
||||||
|
|
||||||
var number = /^(?:\d+\.?\d*|\.?\d+)$/;
|
|
||||||
var bool = /^(?:true|false)$/i;
|
|
||||||
var range = /^\((\d+)\.\.(\d+)\)$/;
|
|
||||||
|
|
||||||
var quoted = new RegExp(`${singleQuoted.source}|${doubleQuoted.source}`);
|
|
||||||
var literal = new RegExp(`${quoted.source}|${range.source}|${bool.source}|${number.source}`, 'i');
|
|
||||||
var variable = /^[a-zA-Z_]\w*(?:\.[a-zA-Z_]\w*|\[\d+\])*$/;
|
|
||||||
var identifier = new RegExp(`${literal.source}|${variable.source}`, 'i');
|
|
||||||
|
|
||||||
exports.patterns = {
|
|
||||||
quoted, number, bool, range, literal
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.isLiteral = function(str) {
|
|
||||||
return literal.test(str);
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.isVariable = function(str) {
|
|
||||||
return variable.test(str);
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.parseLiteral = function(str) {
|
|
||||||
var res;
|
|
||||||
if(res = str.match(number)){
|
|
||||||
return Number(str);
|
|
||||||
}
|
|
||||||
if(res = str.match(bool)){
|
|
||||||
return str.toLowerCase() === 'true';
|
|
||||||
}
|
|
||||||
if(res = str.match(quoted)){
|
|
||||||
return str.slice(1, -1);
|
|
||||||
}
|
|
||||||
if(res = str.match(range)){
|
|
||||||
return _.range(res[1], res[2]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
const context = require('./context');
|
||||||
|
const tokenizer = require('./tokenizer.js');
|
||||||
|
const render = require('./render.js');
|
||||||
|
const lexical = require('./lexical.js');
|
||||||
|
|
||||||
|
exports.render = function(html, ctx){
|
||||||
|
return render(tokenizer(html), context.factory(ctx));
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.lexical = lexical;
|
||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
const _ = require('lodash');
|
||||||
|
|
||||||
|
var singleQuoted = /'[^']*'/;
|
||||||
|
var doubleQuoted = /"[^"]*"/;
|
||||||
|
|
||||||
|
var number = /\d+\.?\d*|\.?\d+/;
|
||||||
|
var bool = /true|false/i;
|
||||||
|
var range = /\((\d+)\.\.(\d+)\)/;
|
||||||
|
var identifier = /[a-zA-Z_$][a-zA-Z_$0-9]*/;
|
||||||
|
var subscript = /\[\d+\]/;
|
||||||
|
|
||||||
|
var quoted = new RegExp(`${singleQuoted.source}|${doubleQuoted.source}`);
|
||||||
|
var literal = new RegExp(`${quoted.source}|${range.source}|${bool.source}|${number.source}`, 'i');
|
||||||
|
var variable = new RegExp(`${identifier.source}(?:\\.${identifier.source}|${subscript.source})*`);
|
||||||
|
var value = new RegExp(`${literal.source}|${variable.source}`, 'i');
|
||||||
|
var hash = new RegExp(`(${identifier.source})\\s*:\\s*(${value.source})`, 'g');
|
||||||
|
var filter = new RegExp(`(${identifier.source})(?:\\s*:\\s*(${value.source}))?`);
|
||||||
|
|
||||||
|
var literalLine = new RegExp(`^(?:${literal.source})$`, 'i');
|
||||||
|
var variableLine = new RegExp(`^(?:${variable.source})$`);
|
||||||
|
var numberLine = new RegExp(`^(?:${number.source})$`);
|
||||||
|
var boolLine = new RegExp(`^(?:${bool.source})$`, 'i');
|
||||||
|
var quotedLine = new RegExp(`^(?:${quoted.source})$`);
|
||||||
|
var rangeLine = new RegExp(`^(?:${range.source})$`);
|
||||||
|
var filterLine = new RegExp(`^(?:${filter.source})$`);
|
||||||
|
|
||||||
|
exports.patterns = {
|
||||||
|
quoted, number, bool, range, literal, hash, filter, identifier,
|
||||||
|
quotedLine, numberLine, boolLine, rangeLine, literalLine, filterLine
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.isLiteral = function(str) {
|
||||||
|
return literalLine.test(str);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.isVariable = function(str) {
|
||||||
|
return variableLine.test(str);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.parseLiteral = function(str) {
|
||||||
|
var res;
|
||||||
|
if (res = str.match(numberLine)) {
|
||||||
|
return Number(str);
|
||||||
|
}
|
||||||
|
if (res = str.match(boolLine)) {
|
||||||
|
return str.toLowerCase() === 'true';
|
||||||
|
}
|
||||||
|
if (res = str.match(quotedLine)) {
|
||||||
|
return str.slice(1, -1);
|
||||||
|
}
|
||||||
|
if (res = str.match(rangeLine)) {
|
||||||
|
return _.range(res[1], res[2]);
|
||||||
|
}
|
||||||
|
};
|
||||||
+2
-3
@@ -21,15 +21,14 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/harttle/shopify-liquid#readme",
|
"homepage": "https://github.com/harttle/shopify-liquid#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bluebird": "^3.4.0",
|
|
||||||
"lodash": "^4.13.1"
|
"lodash": "^4.13.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"chai": "^3.5.0",
|
"chai": "^3.5.0",
|
||||||
"chai-as-promised": "^5.3.0",
|
|
||||||
"coveralls": "^2.11.9",
|
"coveralls": "^2.11.9",
|
||||||
"istanbul": "^0.4.3",
|
"istanbul": "^0.4.3",
|
||||||
"mocha": "^2.5.3",
|
"mocha": "^2.5.3",
|
||||||
"sinon": "^1.17.4"
|
"sinon": "^1.17.4",
|
||||||
|
"sinon-chai": "^2.8.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
const Filter = require('./filter');
|
||||||
|
const Tag = require('./tag');
|
||||||
|
|
||||||
|
module.exports = function render(tokens, ctx) {
|
||||||
|
var html = '';
|
||||||
|
for (var i = 0; i < tokens.length; i++) {
|
||||||
|
var token = tokens.shift();
|
||||||
|
switch (token.type) {
|
||||||
|
case 'html':
|
||||||
|
html += token.value;
|
||||||
|
break;
|
||||||
|
case 'output':
|
||||||
|
html += renderOutput(token);
|
||||||
|
break;
|
||||||
|
case 'tag':
|
||||||
|
html += renderTag(token);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(`unexpected type: ${token.type}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return html;
|
||||||
|
|
||||||
|
function renderOutput(token) {
|
||||||
|
var filters = token.value.split('|');
|
||||||
|
var val = ctx.get(filters.shift());
|
||||||
|
return filters
|
||||||
|
.map(str => Filter.parse(str))
|
||||||
|
.reduce((v, filter) => filter.render(v, ctx), val);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderTag(token) {
|
||||||
|
var tag = Tag.parse(token.value), subTokens = [];
|
||||||
|
if(tag.needClose){
|
||||||
|
var curToken, endToken = 'end' + tag.name;
|
||||||
|
while((curToken = tokens.shift()).value !== endToken){
|
||||||
|
subTokens.push(curToken);
|
||||||
|
}
|
||||||
|
if(curToken.value !== endToken){
|
||||||
|
throw new Error(`${token.value} not closed`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tag.render(subTokens, ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
const lexical = require('./lexical.js');
|
||||||
|
const context = require('./context.js');
|
||||||
|
|
||||||
|
var tags = {};
|
||||||
|
|
||||||
|
var _tagInstance = {
|
||||||
|
render: function(tokens, ctx){
|
||||||
|
var obj = hash(this.markup, ctx);
|
||||||
|
return this.tag.render(tokens, ctx, this.markup, obj);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function register(name, tag){
|
||||||
|
if(typeof tag.render !== 'function'){
|
||||||
|
throw new Error(`expect ${name}.render to be a function`);
|
||||||
|
}
|
||||||
|
tags[name] = tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parse(str){
|
||||||
|
var match = lexical.patterns.identifier.exec(str.trim());
|
||||||
|
if(!match) throw new Error('illegal tag: '+ str);
|
||||||
|
|
||||||
|
var tagInstance = factory(match[0], str);
|
||||||
|
return tagInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hash(markup, ctx){
|
||||||
|
var obj = {};
|
||||||
|
lexical.patterns.hash.lastIndex = 0;
|
||||||
|
while(match = lexical.patterns.hash.exec(markup)){
|
||||||
|
var k = match[1], v = match[2];
|
||||||
|
if(!k) continue;
|
||||||
|
obj[k] = ctx.get(v);
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
function factory(name, markup){
|
||||||
|
var tag = tags[name];
|
||||||
|
if(!tag) throw new Error(`tag ${name} not found`);
|
||||||
|
|
||||||
|
var instance = Object.create(_tagInstance);
|
||||||
|
instance.name = name;
|
||||||
|
instance.markup = markup;
|
||||||
|
instance.tag = tag;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clear(){
|
||||||
|
tags = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.parse = parse;
|
||||||
|
exports.register = register;
|
||||||
|
exports.hash = hash;
|
||||||
|
exports.clear = clear;
|
||||||
+11
-3
@@ -1,6 +1,6 @@
|
|||||||
var chai = require("chai");
|
var chai = require("chai");
|
||||||
var should = chai.should();
|
var should = chai.should();
|
||||||
chai.use(require("chai-as-promised"));
|
var expect = chai.expect;
|
||||||
|
|
||||||
var context = require('../context.js');
|
var context = require('../context.js');
|
||||||
|
|
||||||
@@ -29,9 +29,17 @@ describe('context', function() {
|
|||||||
ctx.get('bar[1].b[1]').should.equal(2);
|
ctx.get('bar[1].b[1]').should.equal(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should merge context', function() {
|
it('should push context', function() {
|
||||||
ctx.merge({foo: 'foo', foo1: 'foo1'});
|
ctx.push({foo: 'foo', foo1: 'foo1'});
|
||||||
ctx.get('foo').should.equal('foo');
|
ctx.get('foo').should.equal('foo');
|
||||||
ctx.get('foo1').should.equal('foo1');
|
ctx.get('foo1').should.equal('foo1');
|
||||||
|
ctx.get('bar[1].b[1]').should.equal(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should pop context', function() {
|
||||||
|
ctx.pop();
|
||||||
|
expect(ctx.get('foo')).to.equal('bar');
|
||||||
|
expect(ctx.get('foo1')).to.equal('');
|
||||||
|
expect(ctx.get('bar[1].b[1]')).to.equal(2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
const chai = require("chai");
|
||||||
|
const sinon = require("sinon");
|
||||||
|
const sinonChai = require("sinon-chai");
|
||||||
|
const expect = chai.expect;
|
||||||
|
|
||||||
|
chai.use(sinonChai);
|
||||||
|
|
||||||
|
var filter = require('../filter.js');
|
||||||
|
var context = require('../context.js');
|
||||||
|
|
||||||
|
describe('filter', function() {
|
||||||
|
var ctx;
|
||||||
|
beforeEach(function(){
|
||||||
|
filter.clear();
|
||||||
|
ctx = context.factory();
|
||||||
|
});
|
||||||
|
it('should throw when not registered', function() {
|
||||||
|
expect(function() {
|
||||||
|
filter.parse('foo');
|
||||||
|
}).to.throw(/filter foo not found/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should register a simple filter', function(){
|
||||||
|
filter.register('foo', x => x.toUpperCase());
|
||||||
|
expect(filter.parse('foo').render('foo', ctx)).to.equal('FOO');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call filter with corrct arguments', function(){
|
||||||
|
var spy = sinon.spy();
|
||||||
|
filter.register('foo', spy);
|
||||||
|
filter.parse('foo: 33').render('foo', ctx);
|
||||||
|
expect(spy).to.have.been.calledWith('foo', 33);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -2,7 +2,7 @@ var chai = require("chai");
|
|||||||
var should = chai.should();
|
var should = chai.should();
|
||||||
chai.use(require("chai-as-promised"));
|
chai.use(require("chai-as-promised"));
|
||||||
|
|
||||||
var identifier = require('../identifier.js');
|
var identifier = require('../lexical.js');
|
||||||
|
|
||||||
describe('identifier', function() {
|
describe('identifier', function() {
|
||||||
it('should test boolean literal', function() {
|
it('should test boolean literal', function() {
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
const chai = require("chai");
|
||||||
|
const sinonChai = require("sinon-chai");
|
||||||
|
const sinon = require("sinon");
|
||||||
|
const expect = chai.expect;
|
||||||
|
|
||||||
|
chai.use(sinonChai);
|
||||||
|
|
||||||
|
var tag = require('../tag.js');
|
||||||
|
var context = require('../context.js');
|
||||||
|
var filter = require('../filter');
|
||||||
|
var render = require('../render.js');
|
||||||
|
|
||||||
|
describe('render', function() {
|
||||||
|
var ctx, htmlToken, tagToken, filterToken;
|
||||||
|
|
||||||
|
before(function() {
|
||||||
|
ctx = context.factory({
|
||||||
|
x: 'XXX',
|
||||||
|
foo: {
|
||||||
|
bar: ['a', 2]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tagToken = {
|
||||||
|
type: 'tag',
|
||||||
|
value: 'foo bar:x foo:"FOO" num:2.3'
|
||||||
|
};
|
||||||
|
htmlToken = {
|
||||||
|
type: 'html',
|
||||||
|
value: '<p>'
|
||||||
|
};
|
||||||
|
filterToken = {
|
||||||
|
type: 'output',
|
||||||
|
value: 'foo.bar[0] | date: "b" | time:2'
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(function(){
|
||||||
|
filter.clear();
|
||||||
|
tag.clear();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render html', function() {
|
||||||
|
expect(render([htmlToken], ctx)).to.equal('<p>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render with tag function', function() {
|
||||||
|
tag.register('foo', {
|
||||||
|
render: x => 'X'
|
||||||
|
});
|
||||||
|
expect(render([tagToken], ctx)).to.equal('X');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call tag with correct arguments', function() {
|
||||||
|
var spy = sinon.spy();
|
||||||
|
tag.register('foo', { render: spy });
|
||||||
|
render([tagToken], ctx);
|
||||||
|
expect(spy).to.have.been.calledWithMatch([], ctx, tagToken.value, {
|
||||||
|
bar: 'XXX',
|
||||||
|
foo: 'FOO',
|
||||||
|
num: 2.3
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render with filter function', function() {
|
||||||
|
filter.register('date', (l, r) => l + r);
|
||||||
|
filter.register('time', (l, r) => l + 3*r);
|
||||||
|
expect(render([filterToken], ctx)).to.equal('ab6');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call filter with correct arguments', function() {
|
||||||
|
var date = sinon.stub().returns('y');
|
||||||
|
var time = sinon.spy();
|
||||||
|
filter.register('date', date);
|
||||||
|
filter.register('time', time);
|
||||||
|
render([filterToken], ctx);
|
||||||
|
expect(date).to.have.been.calledWith('a', 'b');
|
||||||
|
expect(time).to.have.been.calledWith('y', 2);
|
||||||
|
});
|
||||||
|
});
|
||||||
+65
@@ -0,0 +1,65 @@
|
|||||||
|
var chai = require("chai");
|
||||||
|
var sinonChai = require("sinon-chai");
|
||||||
|
var sinon = require("sinon");
|
||||||
|
var expect = chai.expect;
|
||||||
|
chai.use(sinonChai);
|
||||||
|
|
||||||
|
var tag = require('../tag.js');
|
||||||
|
var context = require('../context.js');
|
||||||
|
|
||||||
|
describe('tag', function() {
|
||||||
|
var ctx;
|
||||||
|
before(function(){
|
||||||
|
ctx = context.factory({
|
||||||
|
foo: 'bar',
|
||||||
|
arr: [2, 1]
|
||||||
|
});
|
||||||
|
tag.clear();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw when not registered', function() {
|
||||||
|
expect(function() {
|
||||||
|
tag.parse('foo');
|
||||||
|
}).to.throw(/tag foo not found/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw when render method not defined', function() {
|
||||||
|
expect(function() {
|
||||||
|
tag.register('foo', {});
|
||||||
|
}).to.throw(/expect foo.render to be a function/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should register simple tag', function() {
|
||||||
|
expect(
|
||||||
|
function() {
|
||||||
|
tag.register('foo', {
|
||||||
|
render: x => 'bar'
|
||||||
|
});
|
||||||
|
}).not.throw();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call tag.render', function() {
|
||||||
|
var spy = sinon.spy(),
|
||||||
|
tokens = [];
|
||||||
|
tag.register('foo', {
|
||||||
|
render: spy
|
||||||
|
});
|
||||||
|
tag.parse('foo').render(tokens, ctx);
|
||||||
|
expect(spy).to.have.been.called;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call tag.render with resolved hash', function() {
|
||||||
|
var spy = sinon.spy(),
|
||||||
|
tokens = [];
|
||||||
|
tag.register('foo', {
|
||||||
|
render: spy
|
||||||
|
});
|
||||||
|
var t = tag.parse('foo aa:foo bb: arr[0] cc: 2.3');
|
||||||
|
t.render(tokens, ctx);
|
||||||
|
expect(spy).to.have.been.calledWithMatch(tokens, ctx, 'foo', {
|
||||||
|
aa: 'bar',
|
||||||
|
bb: 2,
|
||||||
|
cc: 2.3
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
var chai = require("chai");
|
var chai = require("chai");
|
||||||
var should = chai.should();
|
var should = chai.should();
|
||||||
chai.use(require("chai-as-promised"));
|
|
||||||
|
|
||||||
var tokenizer = require('../tokenizer.js');
|
var tokenizer = require('../tokenizer.js');
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user