mirror of
https://github.com/harttle/liquidjs.git
synced 2026-10-03 09:05:14 -07:00
cover all
This commit is contained in:
+1
-1
@@ -4,4 +4,4 @@ node_js:
|
|||||||
before_script:
|
before_script:
|
||||||
- npm install -g mocha
|
- npm install -g mocha
|
||||||
after_script:
|
after_script:
|
||||||
- NODE_ENV=test ./node_modules/.bin/istanbul cover --report lcovonly ./node_modules/mocha/bin/_mocha -- -R spec --recursive && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage
|
- npm run lcov && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage
|
||||||
|
|||||||
@@ -43,15 +43,10 @@ var _engine = {
|
|||||||
return this.renderer.renderTemplates(tpl, scope)
|
return this.renderer.renderTemplates(tpl, scope)
|
||||||
},
|
},
|
||||||
parseAndRender: function (html, ctx, opts) {
|
parseAndRender: function (html, ctx, opts) {
|
||||||
|
console.log('parse and render')
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
.then(() => this.parse(html))
|
.then(() => this.parse(html))
|
||||||
.then(tpl => this.render(tpl, ctx, opts))
|
.then(tpl => this.render(tpl, ctx, opts))
|
||||||
.catch(e => {
|
|
||||||
if (e instanceof Errors.RenderBreakError) {
|
|
||||||
return e.html
|
|
||||||
}
|
|
||||||
throw e
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
renderFile: function (filepath, ctx, opts) {
|
renderFile: function (filepath, ctx, opts) {
|
||||||
opts = _.assign({}, opts)
|
opts = _.assign({}, opts)
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "eslint src/ test/",
|
"lint": "eslint src/ test/",
|
||||||
"test": "npm run lint && mocha --recursive",
|
"test": "npm run lint && mocha --recursive",
|
||||||
|
"coverage": "NODE_ENV=test istanbul cover --report html ./node_modules/mocha/bin/_mocha -- -R spec --recursive",
|
||||||
|
"lcov": "NODE_ENV=test istanbul cover --report lcovonly ./node_modules/mocha/bin/_mocha -- -R spec --recursive",
|
||||||
"dist": "make dist",
|
"dist": "make dist",
|
||||||
"preversion": "npm test",
|
"preversion": "npm test",
|
||||||
"version": "npm run dist && git add -A dist",
|
"version": "npm run dist && git add -A dist",
|
||||||
|
|||||||
+45
-49
@@ -1,7 +1,6 @@
|
|||||||
const _ = require('./util/underscore.js')
|
const _ = require('./util/underscore.js')
|
||||||
const lexical = require('./lexical.js')
|
const lexical = require('./lexical.js')
|
||||||
const assert = require('./util/assert.js')
|
const assert = require('./util/assert.js')
|
||||||
const toStr = Object.prototype.toString
|
|
||||||
|
|
||||||
var Scope = {
|
var Scope = {
|
||||||
getAll: function () {
|
getAll: function () {
|
||||||
@@ -12,32 +11,16 @@ var Scope = {
|
|||||||
return ctx
|
return ctx
|
||||||
},
|
},
|
||||||
get: function (str) {
|
get: function (str) {
|
||||||
for (var i = this.scopes.length - 1; i >= 0; i--) {
|
|
||||||
try {
|
try {
|
||||||
return this.getPropertyByPath(this.scopes[i], str)
|
return this.getPropertyByPath(this.scopes, str)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (/undefined variable/.test(e.message)) {
|
if (!/undefined variable/.test(e.message) || this.opts.strict_variables) {
|
||||||
continue
|
|
||||||
}
|
|
||||||
if (/Cannot read property/.test(e.message)) {
|
|
||||||
if (this.opts.strict_variables) {
|
|
||||||
e.message += ': ' + str
|
|
||||||
throw e
|
|
||||||
} else {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
e.message += ': ' + str
|
|
||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (this.opts.strict_variables) {
|
|
||||||
throw new TypeError('undefined variable: ' + str)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
set: function (k, v) {
|
set: function (k, v) {
|
||||||
this.setPropertyByPath(this.scopes[this.scopes.length - 1], k, v)
|
setPropertyByPath(this.scopes[this.scopes.length - 1], k, v)
|
||||||
return this
|
return this
|
||||||
},
|
},
|
||||||
push: function (ctx) {
|
push: function (ctx) {
|
||||||
@@ -54,39 +37,23 @@ var Scope = {
|
|||||||
shift: function () {
|
shift: function () {
|
||||||
return this.scopes.shift()
|
return this.scopes.shift()
|
||||||
},
|
},
|
||||||
setPropertyByPath: function (obj, path, val) {
|
|
||||||
if (_.isString(path)) {
|
|
||||||
var paths = path.replace(/\[/g, '.').replace(/\]/g, '').split('.')
|
|
||||||
for (var i = 0; i < paths.length; i++) {
|
|
||||||
var key = paths[i]
|
|
||||||
if (i === paths.length - 1) {
|
|
||||||
return (obj[key] = val)
|
|
||||||
}
|
|
||||||
if (undefined === obj[key]) obj[key] = {}
|
|
||||||
// case for readonly objects
|
|
||||||
obj = obj[key] || {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
getPropertyByPath: function (obj, path) {
|
getPropertyByPath: function (scopes, path) {
|
||||||
var paths = this.propertyAccessSeq(path + '')
|
var paths = this.propertyAccessSeq(path + '')
|
||||||
var varName = paths.shift()
|
if (!paths.length) {
|
||||||
if (!obj.hasOwnProperty(varName)) {
|
throw new TypeError('undefined variable: ' + path)
|
||||||
throw new TypeError('undefined variable')
|
|
||||||
}
|
}
|
||||||
var variable = obj[varName]
|
var key = paths.shift()
|
||||||
var lastName = paths.pop()
|
var value = getValueFromScopes(key, scopes)
|
||||||
paths.forEach(p => (variable = variable[p]))
|
return paths.reduce(
|
||||||
if (undefined !== lastName) {
|
(value, key) => {
|
||||||
if (lastName === 'size' &&
|
if (_.isNil(value)) {
|
||||||
(toStr.call(variable) === '[object Array]' ||
|
throw new TypeError('undefined variable: ' + key)
|
||||||
toStr.call(variable) === '[object String]')) {
|
|
||||||
return variable.length
|
|
||||||
}
|
}
|
||||||
variable = variable[lastName]
|
return getValueFromParent(key, value)
|
||||||
}
|
},
|
||||||
return variable
|
value
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -144,6 +111,35 @@ var Scope = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setPropertyByPath (obj, path, val) {
|
||||||
|
var paths = (path + '').replace(/\[/g, '.').replace(/\]/g, '').split('.')
|
||||||
|
for (var i = 0; i < paths.length; i++) {
|
||||||
|
var key = paths[i]
|
||||||
|
if (i === paths.length - 1) {
|
||||||
|
return (obj[key] = val)
|
||||||
|
}
|
||||||
|
if (undefined === obj[key]) obj[key] = {}
|
||||||
|
// case for readonly objects
|
||||||
|
obj = obj[key] || {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getValueFromParent (key, value) {
|
||||||
|
return (key === 'size' && (_.isArray(value) || _.isString(value)))
|
||||||
|
? value.length
|
||||||
|
: value[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
function getValueFromScopes (key, scopes) {
|
||||||
|
for (var i = scopes.length - 1; i > -1; i--) {
|
||||||
|
var scope = scopes[i]
|
||||||
|
if (scope.hasOwnProperty(key)) {
|
||||||
|
return scope[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new TypeError('undefined variable: ' + key)
|
||||||
|
}
|
||||||
|
|
||||||
function matchRightBracket (str, begin) {
|
function matchRightBracket (str, begin) {
|
||||||
var stack = 1 // count of '[' - count of ']'
|
var stack = 1 // count of '[' - count of ']'
|
||||||
for (var i = begin; i < str.length; i++) {
|
for (var i = begin; i < str.length; i++) {
|
||||||
|
|||||||
+3
-9
@@ -1,5 +1,4 @@
|
|||||||
const lexical = require('./lexical.js')
|
const lexical = require('./lexical.js')
|
||||||
const _ = require('./util/underscore.js')
|
|
||||||
const Promise = require('any-promise')
|
const Promise = require('any-promise')
|
||||||
const Syntax = require('./syntax.js')
|
const Syntax = require('./syntax.js')
|
||||||
const assert = require('./util/assert.js')
|
const assert = require('./util/assert.js')
|
||||||
@@ -28,14 +27,9 @@ module.exports = function () {
|
|||||||
}
|
}
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
.then(() => typeof impl.render === 'function'
|
.then(() => typeof impl.render === 'function'
|
||||||
? impl.render(scope, obj) : '')
|
? impl.render(scope, obj)
|
||||||
.catch(function (e) {
|
: ''
|
||||||
if (_.isError(e)) {
|
)
|
||||||
throw e
|
|
||||||
}
|
|
||||||
var msg = `Please reject with an Error in ${impl.render}, got ${e}`
|
|
||||||
throw new Error(msg)
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
parse: function (token, tokens) {
|
parse: function (token, tokens) {
|
||||||
this.type = 'tag'
|
this.type = 'tag'
|
||||||
|
|||||||
@@ -2,9 +2,6 @@ const AssertionError = require('./error.js').AssertionError
|
|||||||
|
|
||||||
function assert (predicate, message) {
|
function assert (predicate, message) {
|
||||||
if (!predicate) {
|
if (!predicate) {
|
||||||
if (message instanceof Error) {
|
|
||||||
throw message
|
|
||||||
}
|
|
||||||
message = message || `expect ${predicate} to be true`
|
message = message || `expect ${predicate} to be true`
|
||||||
throw new AssertionError(message)
|
throw new AssertionError(message)
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-1
@@ -1,3 +1,5 @@
|
|||||||
|
const toStr = Object.prototype.toString
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Checks if value is classified as a String primitive or object.
|
* Checks if value is classified as a String primitive or object.
|
||||||
* @param {any} value The value to check.
|
* @param {any} value The value to check.
|
||||||
@@ -7,6 +9,15 @@ function isString (value) {
|
|||||||
return value instanceof String || typeof value === 'string'
|
return value instanceof String || typeof value === 'string'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isNil (value) {
|
||||||
|
return value === null || value === undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
function isArray (value) {
|
||||||
|
// be compatible with IE 8
|
||||||
|
return toStr.call(value) === '[object Array]'
|
||||||
|
}
|
||||||
|
|
||||||
function isError (value) {
|
function isError (value) {
|
||||||
var signature = Object.prototype.toString.call(value)
|
var signature = Object.prototype.toString.call(value)
|
||||||
// [object XXXError]
|
// [object XXXError]
|
||||||
@@ -53,7 +64,6 @@ function assign (object) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _assignBinary (dst, src) {
|
function _assignBinary (dst, src) {
|
||||||
if (!dst) return dst
|
|
||||||
forOwn(src, function (v, k) {
|
forOwn(src, function (v, k) {
|
||||||
dst[k] = v
|
dst[k] = v
|
||||||
})
|
})
|
||||||
@@ -115,6 +125,8 @@ function range (start, stop, step) {
|
|||||||
|
|
||||||
exports.isString = isString
|
exports.isString = isString
|
||||||
exports.isObject = isObject
|
exports.isObject = isObject
|
||||||
|
exports.isArray = isArray
|
||||||
|
exports.isNil = isNil
|
||||||
exports.isError = isError
|
exports.isError = isError
|
||||||
|
|
||||||
exports.range = range
|
exports.range = range
|
||||||
|
|||||||
+50
-56
@@ -1,95 +1,89 @@
|
|||||||
const Liquid = require('..');
|
const Liquid = require('..')
|
||||||
const Promise = require('any-promise');
|
const Promise = require('any-promise')
|
||||||
const lexical = Liquid.lexical;
|
const lexical = Liquid.lexical
|
||||||
const assert = require('../src/util/assert.js');
|
const assert = require('../src/util/assert.js')
|
||||||
const re = new RegExp(`^(${lexical.identifier.source})\\s+in\\s+` +
|
const re = new RegExp(`^(${lexical.identifier.source})\\s+in\\s+` +
|
||||||
`(${lexical.value.source})` +
|
`(${lexical.value.source})` +
|
||||||
`(?:\\s+${lexical.hash.source})*$`);
|
`(?:\\s+${lexical.hash.source})*$`)
|
||||||
|
|
||||||
module.exports = function (liquid) {
|
module.exports = function (liquid) {
|
||||||
liquid.registerTag('tablerow', {
|
liquid.registerTag('tablerow', {
|
||||||
|
|
||||||
parse: function (tagToken, remainTokens) {
|
parse: function (tagToken, remainTokens) {
|
||||||
var match = re.exec(tagToken.args);
|
var match = re.exec(tagToken.args)
|
||||||
assert(match, `illegal tag: ${tagToken.raw}`);
|
assert(match, `illegal tag: ${tagToken.raw}`)
|
||||||
this.variable = match[1];
|
|
||||||
this.collection = match[2];
|
|
||||||
|
|
||||||
this.templates = [];
|
this.variable = match[1]
|
||||||
|
this.collection = match[2]
|
||||||
|
this.templates = []
|
||||||
|
|
||||||
var p, stream = liquid.parser.parseStream(remainTokens)
|
var p
|
||||||
.on('start', x => p = this.templates)
|
var stream = liquid.parser.parseStream(remainTokens)
|
||||||
|
.on('start', () => (p = this.templates))
|
||||||
.on('tag:endtablerow', token => stream.stop())
|
.on('tag:endtablerow', token => stream.stop())
|
||||||
.on('template', tpl => p.push(tpl))
|
.on('template', tpl => p.push(tpl))
|
||||||
.on('end', x => {
|
.on('end', () => {
|
||||||
throw new Error(`tag ${tagToken.raw} not closed`);
|
throw new Error(`tag ${tagToken.raw} not closed`)
|
||||||
});
|
})
|
||||||
|
|
||||||
stream.start();
|
stream.start()
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function (scope, hash) {
|
render: function (scope, hash) {
|
||||||
var collection = Liquid.evalExp(this.collection, scope) || [];
|
var collection = Liquid.evalExp(this.collection, scope) || []
|
||||||
|
|
||||||
var html = '<table>';
|
var html = '<table>'
|
||||||
var offset = hash.offset || 0;
|
var offset = hash.offset || 0
|
||||||
var limit = (hash.limit === undefined) ? collection.length : hash.limit;
|
var limit = (hash.limit === undefined) ? collection.length : hash.limit
|
||||||
|
|
||||||
var cols = hash.cols, row, col;
|
var cols = hash.cols
|
||||||
if (!cols) throw new Error(`illegal cols: ${cols}`);
|
var row
|
||||||
|
var col
|
||||||
|
if (!cols) throw new Error(`illegal cols: ${cols}`)
|
||||||
|
|
||||||
// build array of arguments to pass to sequential promises...
|
// build array of arguments to pass to sequential promises...
|
||||||
collection = collection.slice(offset, offset + limit);
|
collection = collection.slice(offset, offset + limit)
|
||||||
var contexts = [];
|
var contexts = []
|
||||||
collection.some((item, i) => {
|
collection.some((item, i) => {
|
||||||
var ctx = {};
|
var ctx = {}
|
||||||
ctx[this.variable] = item;
|
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)
|
||||||
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
|
var lastPromise = contexts.reduce((promise, context, currentIndex) => promise
|
||||||
// It's fundamentally equivalent to the following...
|
.then((partial) => {
|
||||||
// emptyPromise.then(renderTemplates(args0).then(renderTemplates(args1).then(renderTemplates(args2)...
|
row = Math.floor(currentIndex / cols) + 1
|
||||||
var lastPromise = contexts.reduce((promise, context, currentIndex) => {
|
col = (currentIndex % cols) + 1
|
||||||
return promise.then((partial) => {
|
|
||||||
row = Math.floor(currentIndex / cols) + 1;
|
|
||||||
col = (currentIndex % cols) + 1;
|
|
||||||
if (col === 1) {
|
if (col === 1) {
|
||||||
if (row !== 1) {
|
if (row !== 1) {
|
||||||
html += '</tr>';
|
html += '</tr>'
|
||||||
}
|
}
|
||||||
html += `<tr class="row${row}">`;
|
html += `<tr class="row${row}">`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ctx[this.variable] = context;
|
// ctx[this.variable] = context;
|
||||||
|
html += `<td class="col${col}">`
|
||||||
return html += `<td class="col${col}">`;
|
return html
|
||||||
})
|
})
|
||||||
.then((partial) => {
|
.then((partial) => {
|
||||||
scope.push(context);
|
scope.push(context)
|
||||||
return liquid.renderer.renderTemplates(this.templates, scope)
|
return liquid.renderer.renderTemplates(this.templates, scope)
|
||||||
})
|
})
|
||||||
.then((partial) => {
|
.then((partial) => {
|
||||||
scope.pop(context);
|
scope.pop(context)
|
||||||
html += partial;
|
html += partial
|
||||||
return html += '</td>';
|
html += '</td>'
|
||||||
});
|
return html
|
||||||
}, Promise.resolve('')); // start the reduce chain with a resolved Promise. After first run, the "promise" argument
|
}), Promise.resolve(''))
|
||||||
// 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
|
return lastPromise
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if (row > 0) {
|
if (row > 0) {
|
||||||
html += '</tr>';
|
html += '</tr>'
|
||||||
|
}
|
||||||
|
html += '</table>'
|
||||||
|
return html
|
||||||
|
})
|
||||||
}
|
}
|
||||||
html += '</table>';
|
|
||||||
return html;
|
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
|
||||||
throw error;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -34,6 +34,12 @@ describe('liquid', function () {
|
|||||||
afterEach(function () {
|
afterEach(function () {
|
||||||
mock.restore()
|
mock.restore()
|
||||||
})
|
})
|
||||||
|
describe('Liquid', function () {
|
||||||
|
it('should ignore invalid root option', function () {
|
||||||
|
var liquid = Liquid({ root: /regex/ })
|
||||||
|
expect(liquid.options.root).to.deep.equal([])
|
||||||
|
})
|
||||||
|
})
|
||||||
describe('{{output}}', function () {
|
describe('{{output}}', function () {
|
||||||
it('should output object', function () {
|
it('should output object', function () {
|
||||||
return expect(engine.parseAndRender('{{obj}}', ctx)).to.eventually.equal('{"foo":"bar"}')
|
return expect(engine.parseAndRender('{{obj}}', ctx)).to.eventually.equal('{"foo":"bar"}')
|
||||||
|
|||||||
+20
-3
@@ -98,7 +98,13 @@ describe('scope', function () {
|
|||||||
expect(scope.get('bar[foo]')).to.equal('coo')
|
expect(scope.get('bar[foo]')).to.equal('coo')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should support nested case', function () {
|
it('should return undefined when not exist', function () {
|
||||||
|
expect(scope.get('foo.foo.foo')).to.be.undefined
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#set', function () {
|
||||||
|
it('should set nested value', function () {
|
||||||
scope.set('posts', {
|
scope.set('posts', {
|
||||||
'first': {
|
'first': {
|
||||||
'name': 'A Nice Day'
|
'name': 'A Nice Day'
|
||||||
@@ -109,8 +115,12 @@ describe('scope', function () {
|
|||||||
})
|
})
|
||||||
expect(scope.get('posts[category.diary[0]].name'), 'A Nice Day')
|
expect(scope.get('posts[category.diary[0]].name'), 'A Nice Day')
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
|
it('should create parents if needed', function () {
|
||||||
|
scope.set('foo.bar.coo', 'COO')
|
||||||
|
expect(scope.get('foo.bar.coo'), 'COO')
|
||||||
|
})
|
||||||
|
})
|
||||||
describe('strict_variables', function () {
|
describe('strict_variables', function () {
|
||||||
var scope
|
var scope
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
@@ -118,12 +128,19 @@ describe('scope', function () {
|
|||||||
strict_variables: true
|
strict_variables: true
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
it('should throw undefined in strict mode', function () {
|
it('should throw when variable not defined', function () {
|
||||||
function fn () {
|
function fn () {
|
||||||
scope.get('notdefined')
|
scope.get('notdefined')
|
||||||
}
|
}
|
||||||
expect(fn).to.throw(/undefined variable: notdefined/)
|
expect(fn).to.throw(/undefined variable: notdefined/)
|
||||||
})
|
})
|
||||||
|
it('should throw when deep variable not exist', function () {
|
||||||
|
scope.set('foo', 'bar')
|
||||||
|
function fn () {
|
||||||
|
scope.get('foo.bar.not.defined')
|
||||||
|
}
|
||||||
|
expect(fn).to.throw(/undefined variable: not/)
|
||||||
|
})
|
||||||
it('should find variable in parent scope', function () {
|
it('should find variable in parent scope', function () {
|
||||||
scope.set('foo', 'foo')
|
scope.set('foo', 'foo')
|
||||||
scope.push({
|
scope.push({
|
||||||
|
|||||||
+22
-4
@@ -7,6 +7,9 @@ describe('tags/for', function () {
|
|||||||
var liquid, ctx
|
var liquid, ctx
|
||||||
before(function () {
|
before(function () {
|
||||||
liquid = Liquid()
|
liquid = Liquid()
|
||||||
|
liquid.registerTag('throwingTag', {
|
||||||
|
render: function () { throw new Error('intended render error') }
|
||||||
|
})
|
||||||
ctx = {
|
ctx = {
|
||||||
one: 1,
|
one: 1,
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
@@ -30,12 +33,20 @@ describe('tags/for', function () {
|
|||||||
.to.eventually.equal('foo-coo-')
|
.to.eventually.equal('foo-coo-')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should throw when for not closed', function () {
|
describe('illegal', function () {
|
||||||
|
it('should reject when for not closed', function () {
|
||||||
var src = '{%for c in alpha%}{{c}}'
|
var src = '{%for c in alpha%}{{c}}'
|
||||||
return expect(liquid.parseAndRender(src, ctx))
|
return expect(liquid.parseAndRender(src, ctx))
|
||||||
.to.be.rejectedWith(/tag .* not closed/)
|
.to.be.rejectedWith(/tag .* not closed/)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should reject when inner templates rejected', function () {
|
||||||
|
var src = '{%for c in alpha%}{%throwingTag%}{%endfor%}'
|
||||||
|
return expect(liquid.parseAndRender(src, ctx))
|
||||||
|
.to.be.rejectedWith(/intended render error/)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('else', function () {
|
describe('else', function () {
|
||||||
it('should goto else for empty array', function () {
|
it('should goto else for empty array', function () {
|
||||||
var src = '{%for c in emptyArray%}a{%else%}b{%endfor%}'
|
var src = '{%for c in emptyArray%}a{%else%}b{%endfor%}'
|
||||||
@@ -43,6 +54,12 @@ describe('tags/for', function () {
|
|||||||
.to.eventually.equal('b')
|
.to.eventually.equal('b')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should treat non-empty string as one single element', function () {
|
||||||
|
var src = '{%for c in "abc"%}x{{c}}{%else%}y{%endfor%}'
|
||||||
|
return expect(liquid.parseAndRender(src, ctx))
|
||||||
|
.to.eventually.equal('xabc')
|
||||||
|
})
|
||||||
|
|
||||||
it('should goto else for empty string', function () {
|
it('should goto else for empty string', function () {
|
||||||
var src = '{%for c in ""%}a{%else%}b{%endfor%}'
|
var src = '{%for c in ""%}a{%else%}b{%endfor%}'
|
||||||
return expect(liquid.parseAndRender(src, ctx))
|
return expect(liquid.parseAndRender(src, ctx))
|
||||||
@@ -95,13 +112,11 @@ describe('tags/for', function () {
|
|||||||
'{% if i == 4 %}{% break %}{% endif %}' +
|
'{% if i == 4 %}{% break %}{% endif %}' +
|
||||||
'{{ i }}' +
|
'{{ i }}' +
|
||||||
'{% endfor %}'
|
'{% endfor %}'
|
||||||
// return liquid.parseAndRender(src, ctx).catch(e => {
|
|
||||||
// console.log(e.stack);
|
|
||||||
// });
|
|
||||||
return expect(liquid.parseAndRender(src, ctx))
|
return expect(liquid.parseAndRender(src, ctx))
|
||||||
.to.eventually.equal('123')
|
.to.eventually.equal('123')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('limit', function () {
|
||||||
it('should support for with limit', function () {
|
it('should support for with limit', function () {
|
||||||
var src = '{% for i in (1..5) limit:2 %}{{ i }}{% endfor %}'
|
var src = '{% for i in (1..5) limit:2 %}{{ i }}{% endfor %}'
|
||||||
return expect(liquid.parseAndRender(src, ctx))
|
return expect(liquid.parseAndRender(src, ctx))
|
||||||
@@ -112,7 +127,9 @@ describe('tags/for', function () {
|
|||||||
return expect(liquid.parseAndRender(src, ctx))
|
return expect(liquid.parseAndRender(src, ctx))
|
||||||
.to.eventually.equal('67')
|
.to.eventually.equal('67')
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('reverse', function () {
|
||||||
it('should support for reversed in the last position', function () {
|
it('should support for reversed in the last position', function () {
|
||||||
var src = '{% for i in (1..5) limit:2 reversed %}{{ i }}{% endfor %}'
|
var src = '{% for i in (1..5) limit:2 reversed %}{{ i }}{% endfor %}'
|
||||||
return expect(liquid.parseAndRender(src, ctx))
|
return expect(liquid.parseAndRender(src, ctx))
|
||||||
@@ -131,3 +148,4 @@ describe('tags/for', function () {
|
|||||||
.to.eventually.equal('543')
|
.to.eventually.equal('543')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
|||||||
@@ -24,6 +24,12 @@ describe('tags/tablerow', function () {
|
|||||||
return expect(liquid.parseAndRender(src)).to.eventually.equal(dst)
|
return expect(liquid.parseAndRender(src)).to.eventually.equal(dst)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should support empty array', function () {
|
||||||
|
var src = '{% tablerow i in alpha.z cols:2 %}{{ i }}{% endtablerow %}'
|
||||||
|
var dst = '<table></table>'
|
||||||
|
return expect(liquid.parseAndRender(src)).to.eventually.equal(dst)
|
||||||
|
})
|
||||||
|
|
||||||
it('should throw when tablerow not closed', function () {
|
it('should throw when tablerow not closed', function () {
|
||||||
var src = '{% tablerow i in (1..0) cols:2 %}{{ i }}'
|
var src = '{% tablerow i in (1..0) cols:2 %}{{ i }}'
|
||||||
return expect(liquid.parseAndRender(src))
|
return expect(liquid.parseAndRender(src))
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
const chai = require('chai')
|
||||||
|
const expect = chai.expect
|
||||||
|
const assert = require('../../src/util/assert.js')
|
||||||
|
|
||||||
|
describe('assert', function () {
|
||||||
|
it('should not throw if predicate is truthy', function () {
|
||||||
|
var fn = () => assert('foo', 'bar')
|
||||||
|
expect(fn).to.not.throw()
|
||||||
|
})
|
||||||
|
it('should not throw if predicate is truthy', function () {
|
||||||
|
var fn = () => assert('', 'bar')
|
||||||
|
expect(fn).to.throw(/bar/)
|
||||||
|
})
|
||||||
|
it('should populate default message', function () {
|
||||||
|
var fn = () => assert(false)
|
||||||
|
expect(fn).to.throw(/expect false to be true/)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -72,6 +72,14 @@ describe('util/underscore', function () {
|
|||||||
expect(log).to.have.been.calledWith('[foo]', 'bar')
|
expect(log).to.have.been.calledWith('[foo]', 'bar')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
describe('.range()', function () {
|
||||||
|
it('should return a range of integers', function () {
|
||||||
|
expect(_.range(3, 5)).to.deep.equal([3, 4])
|
||||||
|
})
|
||||||
|
it('should treat start as 0 if omitted', function () {
|
||||||
|
expect(_.range(3)).to.deep.equal([0, 1, 2])
|
||||||
|
})
|
||||||
|
})
|
||||||
describe('.assign()', function () {
|
describe('.assign()', function () {
|
||||||
it('should handle null dst', function () {
|
it('should handle null dst', function () {
|
||||||
expect(_.assign(null, {
|
expect(_.assign(null, {
|
||||||
|
|||||||
Reference in New Issue
Block a user