From fd9fed154c456f516aba8b3eb7b456395b980f0e Mon Sep 17 00:00:00 2001 From: harttle Date: Mon, 7 Nov 2016 00:04:07 +0800 Subject: [PATCH] dist --- dist/liquid.js | 1078 +++++++++++++++++++++++++------------------- dist/liquid.min.js | 3 +- package.json | 2 +- 3 files changed, 617 insertions(+), 466 deletions(-) diff --git a/dist/liquid.js b/dist/liquid.js index ecbc83c2c..5006b9382 100644 --- a/dist/liquid.js +++ b/dist/liquid.js @@ -203,12 +203,16 @@ function registerAll(liquid) { registerAll.filters = filters; module.exports = registerAll; -},{"./src/util/strftime.js":17,"./src/util/underscore.js":18}],2:[function(require,module,exports){ +},{"./src/util/strftime.js":20,"./src/util/underscore.js":21}],2:[function(require,module,exports){ 'use strict'; var Scope = require('./src/scope'); +var _ = require('./src/util/underscore.js'); +var assert = require('./src/util/assert.js'); var tokenizer = require('./src/tokenizer.js'); -var fs = require('fs'); +var statFileAsync = require('./src/util/fs.js').statFileAsync; +var readFileAsync = require('./src/util/fs.js').readFileAsync; +var path = require('path'); var Render = require('./src/render.js'); var lexical = require('./src/lexical.js'); var Tag = require('./src/tag.js'); @@ -218,6 +222,8 @@ var Syntax = require('./src/syntax.js'); var tags = require('./tags'); var filters = require('./filters'); var Promise = require('any-promise'); +var anySeries = require('./src/util/promise.js').anySeries; +var Errors = require('./src/util/error.js'); var _engine = { init: function init(tag, filter, options) { @@ -240,31 +246,30 @@ var _engine = { return this.parser.parse(tokens); }, render: function render(tpl, ctx, opts) { - opts = opts || {}; - opts.strict_variables = opts.strict_variables || false; - opts.strict_filters = opts.strict_filters || false; - - this.renderer.resetRegisters(); - var scope = Scope.factory(ctx, { - strict: opts.strict_variables - }); - return this.renderer.renderTemplates(tpl, scope, opts); + opts = _.assign({}, this.options, opts); + var scope = Scope.factory(ctx, opts); + return this.renderer.renderTemplates(tpl, scope); }, parseAndRender: function parseAndRender(html, ctx, opts) { - try { - var tpl = this.parse(html); - return this.render(tpl, ctx, opts); - } 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 renderFile(filepath, ctx, opts) { var _this = this; - return this.handleCache(filepath).then(function (templates) { - return _this.render(templates, ctx, opts); + return Promise.resolve().then(function () { + return _this.parse(html); + }).then(function (tpl) { + return _this.render(tpl, ctx, opts); + }).catch(function (e) { + if (e instanceof Errors.RenderBreak) { + return e.html; + } + throw e; + }); + }, + renderFile: function renderFile(filepath, ctx, opts) { + var _this2 = this; + + opts = _.assign({}, opts); + return this.getTemplate(filepath, opts.root).then(function (templates) { + return _this2.render(templates, ctx, opts); }).catch(function (e) { e.file = filepath; throw e; @@ -280,33 +285,54 @@ var _engine = { registerTag: function registerTag(name, tag) { return this.tag.register(name, tag); }, - handleCache: function handleCache(filepath) { - var _this2 = this; - - if (!filepath) throw new Error('filepath cannot be null'); - - return this.getTemplate(filepath).then(function (html) { - var tpl = _this2.options.cache && _this2.cache[filepath] || _this2.parse(html); - return _this2.options.cache ? _this2.cache[filepath] = tpl : tpl; + lookup: function lookup(filepath, root) { + root = this.options.root.concat(root || []); + root = _.uniq(root); + var paths = root.map(function (root) { + return path.resolve(root, filepath); }); - }, - getTemplate: function getTemplate(filepath) { - filepath = resolvePath(this.options.root, filepath); - - if (!filepath.match(/\.\w+$/)) { - filepath += this.options.extname; - } - return new Promise(function (resolve, reject) { - fs.readFile(filepath, 'utf8', function (err, html) { - err ? reject(err) : resolve(html); + return anySeries(paths, function (path) { + return statFileAsync(path).then(function () { + return path; }); + }).catch(function (e) { + if (e.code === 'ENOENT') { + e.message = 'Failed to lookup ' + filepath + ' in: ' + root; + } + throw e; }); }, - express: function express(renderingOptions) { + getTemplate: function getTemplate(filepath, root) { var _this3 = this; - return function (filePath, options, callback) { - _this3.renderFile(filePath, options, renderingOptions).then(function (html) { + if (!path.extname(filepath)) { + filepath += this.options.extname; + } + return this.lookup(filepath, root).then(function (filepath) { + if (_this3.options.cache) { + var tpl = _this3.cache[filepath]; + if (tpl) { + return Promise.resolve(tpl); + } + return readFileAsync(filepath).then(function (str) { + return _this3.parse(str); + }).then(function (tpl) { + return _this3.cache[filepath] = tpl; + }); + } else { + return readFileAsync(filepath).then(function (str) { + return _this3.parse(str); + }); + } + }); + }, + express: function express(opts) { + opts = opts || {}; + var self = this; + return function (filePath, ctx, callback) { + assert(_.isArray(this.root) || _.isString(this.root), 'illegal views root, are you using express.js?'); + opts.root = this.root; + self.renderFile(filePath, ctx, opts).then(function (html) { return callback(null, html); }).catch(function (e) { return callback(e); @@ -316,8 +342,10 @@ var _engine = { }; function factory(options) { - options = options || {}; - options.root = options.root || ''; + options = _.assign({}, options); + options.root = normalizeStringArray(options.root); + if (!options.root.length) options.root = ['.']; + options.extname = options.extname || '.liquid'; var engine = Object.create(_engine); @@ -326,15 +354,10 @@ function factory(options) { return engine; } -function resolvePath(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('/'); +function normalizeStringArray(value) { + if (_.isArray(value)) return value; + if (_.isString(value)) return [value]; + return []; } factory.lexical = lexical; @@ -342,10 +365,16 @@ factory.isTruthy = Syntax.isTruthy; factory.isFalsy = Syntax.isFalsy; factory.evalExp = Syntax.evalExp; factory.evalValue = Syntax.evalValue; +factory.Types = { + ParseError: Errors.ParseError, + TokenizationEroor: Errors.TokenizationError, + RenderBreak: Errors.RenderBreak, + AssertionError: Errors.AssertionError +}; module.exports = factory; -},{"./filters":1,"./src/filter.js":8,"./src/lexical.js":9,"./src/parser":11,"./src/render.js":12,"./src/scope":13,"./src/syntax.js":14,"./src/tag.js":15,"./src/tokenizer.js":16,"./tags":29,"any-promise":3,"fs":6}],3:[function(require,module,exports){ +},{"./filters":1,"./src/filter.js":7,"./src/lexical.js":8,"./src/parser":10,"./src/render.js":11,"./src/scope":12,"./src/syntax.js":13,"./src/tag.js":14,"./src/tokenizer.js":15,"./src/util/assert.js":16,"./src/util/error.js":17,"./src/util/fs.js":18,"./src/util/promise.js":19,"./src/util/underscore.js":21,"./tags":32,"any-promise":3,"path":6}],3:[function(require,module,exports){ 'use strict'; module.exports = require('./register')().Promise; @@ -452,40 +481,11 @@ function loadImplementation() { "use strict"; },{}],7:[function(require,module,exports){ -"use strict"; - -function TokenizationError(message, input, line) { - Error.captureStackTrace(this, this.constructor); - this.name = this.constructor.name; - - this.message = message || ""; - this.input = input; - this.line = line; -} -TokenizationError.prototype = Object.create(Error.prototype); -TokenizationError.prototype.constructor = TokenizationError; - -function ParseError(message, input, line, e) { - Error.captureStackTrace(this, this.constructor); - this.name = this.constructor.name; - this.originalError = e; - - this.message = message || ""; - this.input = input; - this.line = line; -} -ParseError.prototype = Object.create(Error.prototype); -ParseError.prototype.constructor = ParseError; - -module.exports = { - TokenizationError: TokenizationError, ParseError: ParseError -}; - -},{}],8:[function(require,module,exports){ 'use strict'; var lexical = require('./lexical.js'); var Syntax = require('./syntax.js'); +var assert = require('./util/assert.js'); var valueRE = new RegExp('' + lexical.value.source, 'g'); @@ -502,7 +502,7 @@ module.exports = function () { }, parse: function parse(str) { var match = lexical.filterLine.exec(str); - if (!match) throw new Error('illegal filter: ' + str); + assert(match, 'illegal filter: ' + str); var name = match[1], argList = match[2] || '', @@ -510,7 +510,7 @@ module.exports = function () { if (typeof filter !== 'function') { return { name: name, - error: new Error('undefined filter: ' + name) + error: new TypeError('undefined filter: ' + name) }; } @@ -545,7 +545,7 @@ module.exports = function () { }; }; -},{"./lexical.js":9,"./syntax.js":14}],9:[function(require,module,exports){ +},{"./lexical.js":8,"./syntax.js":13,"./util/assert.js":16}],8:[function(require,module,exports){ 'use strict'; // quote related @@ -636,7 +636,7 @@ module.exports = { isLiteral: isLiteral, isVariable: isVariable, parseLiteral: parseLiteral, isRange: isRange, matchValue: matchValue, isInteger: isInteger }; -},{}],10:[function(require,module,exports){ +},{}],9:[function(require,module,exports){ 'use strict'; var operators = { @@ -671,11 +671,12 @@ var operators = { module.exports = operators; -},{}],11:[function(require,module,exports){ +},{}],10:[function(require,module,exports){ 'use strict'; var lexical = require('./lexical.js'); -var ParseError = require('./error.js').ParseError; +var ParseError = require('./util/error.js').ParseError; +var assert = require('./util/assert.js'); module.exports = function (Tag, Filter) { @@ -747,7 +748,7 @@ module.exports = function (Tag, Filter) { function parseOutput(str) { var match = lexical.matchValue(str); - if (!match) throw new Error('illegal output string: ' + str); + assert(match, 'illegal output string: ' + str); var initial = match[0]; str = str.substr(match.index + match[0].length); @@ -776,102 +777,71 @@ module.exports = function (Tag, Filter) { }; }; -},{"./error.js":7,"./lexical.js":9}],12:[function(require,module,exports){ +},{"./lexical.js":8,"./util/assert.js":16,"./util/error.js":17}],11:[function(require,module,exports){ 'use strict'; var Syntax = require('./syntax.js'); var Promise = require('any-promise'); +var mapSeries = require('./util/promise.js').mapSeries; +var RenderBreak = require('./util/error.js').RenderBreak; +var assert = require('./util/assert.js'); +var _ = require('./util/underscore.js'); var render = { - renderTemplates: function renderTemplates(templates, scope, opts) { + renderTemplates: function renderTemplates(templates, scope) { var _this = this; - if (!scope) throw new Error('unable to evalTemplates: scope undefined'); - opts = opts || {}; - opts.strict_filters = opts.strict_filters || false; + assert(scope, 'unable to evalTemplates: scope undefined'); 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(function (promise, template) { - return promise.then(function () { - if (scope.safeGet('forloop.skip')) { - return Promise.resolve(''); - } - if (scope.safeGet('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(function (partial) { - if (partial === undefined) { - return true; // basically a noop (do nothing) - } - return html += partial; - }); - break; - case 'html': - promiseLink = Promise.resolve(template.value).then(function (partial) { - return html += partial; - }); - break; - case 'output': - var val = _this.evalOutput(template, scope, opts); - promiseLink = Promise.resolve(val === undefined ? '' : stringify(val)).then(function (partial) { - return html += partial; - }); - break; - } - - return promiseLink; - }).catch(function (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; + return mapSeries(templates, function (tpl) { + return renderTemplate.call(_this, tpl).then(function (partial) { + return html += partial; + }).catch(function (e) { + if (e instanceof RenderBreak) { + e.resolvedHTML = html; } + throw e; }); - }, 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(function (renderedHtml) { - return renderedHtml; - }).catch(function (error) { - throw error; + }).then(function () { + return html; }); + + function renderTemplate(template) { + if (template.type === 'tag') { + return this.renderTag(template, scope).then(function (partial) { + return partial === undefined ? '' : partial; + }); + } else if (template.type === 'output') { + return Promise.resolve(this.evalOutput(template, scope)).then(function (partial) { + return partial === undefined ? '' : stringify(partial); + }); + } else { + // template.type === 'html' + return Promise.resolve(template.value); + } + } }, - renderTag: function renderTag(template, scope, register) { + renderTag: function renderTag(template, scope) { if (template.name === 'continue') { - scope.set('forloop.skip', true); - return Promise.resolve(''); + return Promise.reject(new RenderBreak('continue')); } if (template.name === 'break') { - scope.set('forloop.stop', true); - scope.set('forloop.skip', true); - return Promise.reject(new Error('forloop.stop')); // this will stop the sequential promise chain + return Promise.reject(new RenderBreak('break')); } - return template.render(scope, register); + return template.render(scope); }, - evalOutput: function evalOutput(template, scope, opts) { - if (!scope) throw new Error('unable to evalOutput: scope undefined'); + evalOutput: function evalOutput(template, scope) { + assert(scope, 'unable to evalOutput: scope undefined'); var val = Syntax.evalExp(template.initial, scope); template.filters.some(function (filter) { if (filter.error) { - if (opts.strict_filters) { + if (scope.get('liquid.strict_filters')) { throw filter.error; } else { - // render as null val = ''; return true; } @@ -879,16 +849,11 @@ var render = { val = filter.render(val, scope); }); return val; - }, - - resetRegisters: function resetRegisters() { - return this.register = {}; } }; function factory() { var instance = Object.create(render); - instance.register = {}; return instance; } @@ -899,177 +864,184 @@ function stringify(val) { module.exports = factory; -},{"./syntax.js":14,"any-promise":3}],13:[function(require,module,exports){ +},{"./syntax.js":13,"./util/assert.js":16,"./util/error.js":17,"./util/promise.js":19,"./util/underscore.js":21,"any-promise":3}],12:[function(require,module,exports){ 'use strict'; var _ = require('./util/underscore.js'); var lexical = require('./lexical.js'); +var assert = require('./util/assert.js'); +var referenceError = /undefined variable|Cannot read property .* of undefined/; var Scope = { - safeGet: function safeGet(str) { - var i; - // get all - if (str === undefined) { - var ctx = {}; - for (i = this.scopes.length - 1; i >= 0; i--) { - var scp = this.scopes[i]; - for (var k in scp) { - if (scp.hasOwnProperty(k)) { - ctx[k] = scp[k]; - } - } - } - return ctx; - } - // get one path - for (i = this.scopes.length - 1; i >= 0; i--) { - var v = this.getPropertyByPath(this.scopes[i], str); - if (v !== undefined) return v; - } - }, - get: function get(str) { - var val = this.safeGet(str); - if (val === undefined && this.opts.strict) { - throw new Error('[strict_variables] undefined variable: ' + str); - } - return val; - }, - set: function set(k, v) { - this.setPropertyByPath(this.scopes[this.scopes.length - 1], k, v); - return this; - }, - push: function push(ctx) { - if (!ctx) throw new Error('trying to push ' + ctx + ' into scopes'); - return this.scopes.push(ctx); - }, - pop: function pop() { - return this.scopes.pop(); - }, + getAll: function getAll() { + var ctx = {}; + for (var i = this.scopes.length - 1; i >= 0; i--) { + _.assign(ctx, this.scopes[i]); + } + return ctx; + }, + get: function get(str) { + for (var i = this.scopes.length - 1; i >= 0; i--) { + try { + return this.getPropertyByPath(this.scopes[i], str); + } catch (e) { + if (!referenceError.test(e.message) || this.opts.strict_variables) { + e.message += ': ' + str; + throw e; + } + } + } + if (this.opts.strict_variables) { + throw new TypeError('undefined variable: ' + str); + } + }, + set: function set(k, v) { + this.setPropertyByPath(this.scopes[this.scopes.length - 1], k, v); + return this; + }, + push: function push(ctx) { + assert(ctx, 'trying to push ' + ctx + ' into scopes'); + return this.scopes.push(ctx); + }, + pop: function pop() { + return this.scopes.pop(); + }, + unshift: function unshift(ctx) { + assert(ctx, 'trying to push ' + ctx + ' into scopes'); + return this.scopes.unshift(ctx); + }, + shift: function shift() { + return this.scopes.shift(); + }, + setPropertyByPath: function setPropertyByPath(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] || {}; + } + } + }, - setPropertyByPath: function setPropertyByPath(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] || {}; - } - return obj; - } - return obj[path] = val; - }, + getPropertyByPath: function getPropertyByPath(obj, path) { + var paths = this.propertyAccessSeq(path + ''); + var varName = paths.shift(); + if (!obj.hasOwnProperty(varName)) { + throw new TypeError('undefined variable'); + } + var variable = obj[varName]; + paths.forEach(function (p) { + return variable = variable[p]; + }); + return variable; + }, - getPropertyByPath: function getPropertyByPath(obj, path) { - if (_.isString(path) && path.length) { - var paths = this.propertyAccessSeq(path); - paths.forEach(function (p) { - return obj = obj && obj[p]; - }); - return obj; - } - return obj[path]; - }, + /* + * Parse property access sequence from access string + * @example + * accessSeq("foo.bar") // ['foo', 'bar'] + * accessSeq("foo['bar']") // ['foo', 'bar'] + * accessSeq("foo['b]r']") // ['foo', 'b]r'] + * accessSeq("foo[bar.coo]") // ['foo', 'bar'], for bar.coo == 'bar' + */ + propertyAccessSeq: function propertyAccessSeq(str) { + var seq = [], + name = ''; + for (var i = 0; i < str.length; i++) { + if (str[i] === '[') { + seq.push(name); + name = ''; - /* - * Parse property access sequence from access string - * @example - * accessSeq("foo.bar") // ['foo', 'bar'] - * accessSeq("foo['bar']") // ['foo', 'bar'] - * accessSeq("foo['b]r']") // ['foo', 'b]r'] - * accessSeq("foo[bar.coo]") // ['foo', 'bar'], for bar.coo == 'bar' - */ - propertyAccessSeq: function propertyAccessSeq(str) { - var seq = [], - name = ''; - for (var i = 0; i < str.length; i++) { - if (str[i] === '[') { - seq.push(name); - name = ''; - - var delemiter = str[i + 1]; - // foo[bar.coo] - if (delemiter !== "'" && delemiter !== '"') { - var j = matchRightBracket(str, i + 1); - if (j === -1) { - throw new Error('unbalanced []: ' + str); - } - name = str.slice(i + 1, j); - // foo[1] - if (lexical.isInteger(name)) { - seq.push(name); - } - // foo["bar"] - else { - seq.push(this.get(name)); - } - name = ''; - i = j; - } - // foo["bar"] - else { - var j = str.indexOf(delemiter, i + 2); - if (j === -1) { - throw new Error('unbalanced ' + delemiter + ': ' + str); - } - name = str.slice(i + 2, j); - seq.push(name); - name = ''; - i = j + 1; - } - } - // foo.bar - else if (str[i] === ".") { - seq.push(name); - name = ''; - } - //foo.bar - else { - name += str[i]; - } - } - if (name.length) seq.push(name); - return seq; - } + var delemiter = str[i + 1]; + // foo[bar.coo] + if (delemiter !== "'" && delemiter !== '"') { + var j = matchRightBracket(str, i + 1); + assert(j !== -1, 'unbalanced []: ' + str); + name = str.slice(i + 1, j); + // foo[1] + if (lexical.isInteger(name)) { + seq.push(name); + } + // foo["bar"] + else { + seq.push(this.get(name)); + } + name = ''; + i = j; + } + // foo["bar"] + else { + j = str.indexOf(delemiter, i + 2); + assert(j !== -1, 'unbalanced ' + delemiter + ': ' + str); + name = str.slice(i + 2, j); + seq.push(name); + name = ''; + i = j + 1; + } + } + // foo.bar + else if (str[i] === ".") { + seq.push(name); + name = ''; + } + //foo.bar + else { + name += str[i]; + } + } + if (name.length) seq.push(name); + return seq; + } }; function matchRightBracket(str, begin) { - var stack = 1; // count of '[' - count of ']' - for (var i = begin; i < str.length; i++) { - if (str[i] === '[') { - stack++; - } - if (str[i] === ']') { - stack--; - if (stack === 0) { - return i; - } - } - } - return -1; + var stack = 1; // count of '[' - count of ']' + for (var i = begin; i < str.length; i++) { + if (str[i] === '[') { + stack++; + } + if (str[i] === ']') { + stack--; + if (stack === 0) { + return i; + } + } + } + return -1; } -exports.factory = function (_ctx, opts) { - opts = opts || {}; - opts.strict = opts.strict || false; +exports.factory = function (ctx, opts) { + opts = _.assign({ + strict_variables: false, + strict_filters: false, + blocks: {}, + root: [] + }, opts); - var scope = Object.create(Scope); - scope.opts = opts; - scope.scopes = [_ctx || {}]; - return scope; + ctx = _.assign(ctx, { + liquid: opts + }); + + var scope = Object.create(Scope); + scope.opts = opts; + scope.scopes = [ctx]; + return scope; }; -},{"./lexical.js":9,"./util/underscore.js":18}],14:[function(require,module,exports){ +},{"./lexical.js":8,"./util/assert.js":16,"./util/underscore.js":21}],13:[function(require,module,exports){ 'use strict'; var operators = require('./operators.js'); var lexical = require('./lexical.js'); +var assert = require('../src/util/assert.js'); function evalExp(exp, scope) { - if (!scope) throw new Error('unable to evalExp: scope undefined'); + assert(scope, 'unable to evalExp: scope undefined'); var operatorREs = lexical.operators, match; for (var i = 0; i < operatorREs.length; i++) { @@ -1121,12 +1093,13 @@ module.exports = { evalExp: evalExp, evalValue: evalValue, isTruthy: isTruthy, isFalsy: isFalsy }; -},{"./lexical.js":9,"./operators.js":10}],15:[function(require,module,exports){ +},{"../src/util/assert.js":16,"./lexical.js":8,"./operators.js":9}],14:[function(require,module,exports){ 'use strict'; var lexical = require('./lexical.js'); var Promise = require('any-promise'); var Syntax = require('./syntax.js'); +var assert = require('./util/assert.js'); function hash(markup, scope) { var obj = {}, @@ -1144,11 +1117,9 @@ module.exports = function () { var tagImpls = {}; var _tagInstance = { - render: function render(scope, register) { - var reg = register[this.name]; - if (!reg) reg = register[this.name] = {}; + render: function render(scope) { var obj = hash(this.token.args, scope); - return this.tagImpl.render && this.tagImpl.render(scope, obj, reg) || Promise.resolve(''); + return this.tagImpl.render && this.tagImpl.render(scope, obj) || Promise.resolve(''); }, parse: function parse(token, tokens) { this.type = 'tag'; @@ -1156,7 +1127,7 @@ module.exports = function () { this.name = token.name; var tagImpl = tagImpls[this.name]; - if (!tagImpl) throw new Error('tag ' + this.name + ' not found'); + assert(tagImpl, 'tag ' + this.name + ' not found'); this.tagImpl = Object.create(tagImpl); if (this.tagImpl.parse) { this.tagImpl.parse(token, tokens); @@ -1183,15 +1154,17 @@ module.exports = function () { }; }; -},{"./lexical.js":9,"./syntax.js":14,"any-promise":3}],16:[function(require,module,exports){ +},{"./lexical.js":8,"./syntax.js":13,"./util/assert.js":16,"any-promise":3}],15:[function(require,module,exports){ 'use strict'; var lexical = require('./lexical.js'); -var TokenizationError = require('./error.js').TokenizationError; +var TokenizationError = require('./util/error.js').TokenizationError; +var _ = require('./util/underscore.js'); +var assert = require('../src/util/assert.js'); function parse(html) { var tokens = []; - if (!html) return tokens; + assert(_.isString(html), new TokenizationError('illegal input type')); var syntax = /({%(.*?)%})|({{(.*?)}})/g; var result, htmlFragment, token; @@ -1268,7 +1241,149 @@ function parse(html) { exports.parse = parse; -},{"./error.js":7,"./lexical.js":9}],17:[function(require,module,exports){ +},{"../src/util/assert.js":16,"./lexical.js":8,"./util/error.js":17,"./util/underscore.js":21}],16:[function(require,module,exports){ +'use strict'; + +var AssertionError = require('./error.js').AssertionError; + +function assert(predicate, message) { + if (!predicate) { + if (message instanceof Error) { + throw message; + } + var message = message || 'expect ' + predicate + ' to be true'; + throw new AssertionError(message); + } +} + +module.exports = assert; + +},{"./error.js":17}],17:[function(require,module,exports){ +"use strict"; + +function TokenizationError(message, input, line) { + if (Error.captureStackTrace) { + Error.captureStackTrace(this, this.constructor); + } + this.name = this.constructor.name; + + this.message = message; + this.input = input; + this.line = line; +} +TokenizationError.prototype = Object.create(Error.prototype); +TokenizationError.prototype.constructor = TokenizationError; + +function ParseError(message, input, line, e) { + if (Error.captureStackTrace) { + Error.captureStackTrace(this, this.constructor); + } + this.name = this.constructor.name; + this.originalError = e; + + this.message = message; + this.input = input; + this.line = line; +} +ParseError.prototype = Object.create(Error.prototype); +ParseError.prototype.constructor = ParseError; + +function RenderBreak(message) { + if (Error.captureStackTrace) { + Error.captureStackTrace(this, this.constructor); + } + this.name = this.constructor.name; + this.message = message; +} +RenderBreak.prototype = Object.create(Error.prototype); +RenderBreak.prototype.constructor = RenderBreak; + +function AssertionError(message) { + if (Error.captureStackTrace) { + Error.captureStackTrace(this, this.constructor); + } + this.name = this.constructor.name; + this.message = message; +} +AssertionError.prototype = Object.create(Error.prototype); +AssertionError.prototype.constructor = AssertionError; + +module.exports = { + TokenizationError: TokenizationError, ParseError: ParseError, RenderBreak: RenderBreak, AssertionError: AssertionError +}; + +},{}],18:[function(require,module,exports){ +'use strict'; + +var 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, function (err, stat) { + return err ? reject(err) : resolve(stat); + }); + }); +}; + +module.exports = { + readFileAsync: readFileAsync, + statFileAsync: statFileAsync +}; + +},{"fs":6}],19:[function(require,module,exports){ +'use strict'; + +var 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 anySeries(iterable, iteratee) { + var ret = Promise.reject(new Error('init')); + iterable.forEach(function (item, idx) { + ret = ret.catch(function (e) { + return iteratee(item, idx, iterable); + }); + }); + return ret; +} + +/* + * Call functions in serial until someone rejected. + * @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 mapSeries(iterable, iteratee) { + var ret = Promise.resolve('init'); + var result = []; + iterable.forEach(function (item, idx) { + ret = ret.then(function () { + return iteratee(item, idx, iterable); + }).then(function (x) { + return result.push(x); + }); + }); + return ret.then(function () { + return result; + }); +} + +exports.anySeries = anySeries; +exports.mapSeries = mapSeries; + +},{"any-promise":3}],20:[function(require,module,exports){ "use strict"; var monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; @@ -1289,14 +1404,6 @@ var _date = { return [31, feb, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; }, - getTimezone: function getTimezone(d) { - return d.toString().replace(/^.*? ([A-Z]{3}) [0-9]{4}.*$/, "$1").replace(/^.*?\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\)$/, "$1$2$3"); - }, - - getGMTOffset: function getGMTOffset(d) { - return (d.getTimezoneOffset() > 0 ? "-" : "+") + _number.pad(Math.floor(d.getTimezoneOffset() / 60), 2) + _number.pad(d.getTimezoneOffset() % 60, 2); - }, - getDayOfYear: function getDayOfYear(d) { var num = 0; for (var i = 0; i < d.getMonth(); ++i) { @@ -1321,27 +1428,12 @@ var _date = { return !!((year & 3) === 0 && (year % 100 || year % 400 === 0 && year)); }, - getFirstDayOfMonth: function getFirstDayOfMonth(d) { - var day = (d.getDay() - (d.getDate() - 1)) % 7; - return day < 0 ? day + 7 : day; - }, - - getLastDayOfMonth: function getLastDayOfMonth(d) { - var day = (d.getDay() + (_date.daysInMonth(d)[d.getMonth()] - d.getDate())) % 7; - return day < 0 ? day + 7 : day; - }, - getSuffix: function getSuffix(d) { var str = d.getDate().toString(); var index = parseInt(str.slice(-1)); return suffixes[index] || suffixes['default']; }, - applyOffset: function applyOffset(date, offset_seconds) { - date.setTime(date.valueOf() - offset_seconds * 1000); - return date; - }, - century: function century(d) { return parseInt(d.getFullYear().toString().substring(0, 2), 10); } @@ -1449,12 +1541,9 @@ var format_codes = { Y: function Y(d) { return d.getFullYear(); }, - // TODO: guessing the pad function won't work with negative numbers? - // TODO: getTimezoneOffset returns a positive number for GMT-7. Verify my - // assumption that it will return negative for GMT+x z: function z(d) { var tz = d.getTimezoneOffset() / 60 * 100; - return (tz > 0 ? '-' : '+') + _number.pad(tz, 4); + return (tz > 0 ? '-' : '+') + _number.pad(Math.abs(tz), 4); }, "%": function _() { return '%'; @@ -1464,19 +1553,6 @@ format_codes.h = format_codes.b; format_codes.N = format_codes.L; var strftime = function strftime(d, format) { - // I used to use string split with a regex and a capturing block here, - // which I thought was really clever, but apparently this exact feature is - // fucked in IE. In every other browser (and languages), the captured - // blocks are present in the output. E.g. - // var pairs = "hello%athere".split(/(%.)/); - // => ['hello', '%a', 'there'] - // IE however, just treats it the same as if no capturing block is present - // => ['hello', 'there'] - // An alternate implementation of split is available here - // http://blog.stevenlevithan.com/archives/cross-browser-split - // Because that's a large amount of code for this one specific use case, - // I've just decided to loop through a regex instead. - var output = ''; var remaining = format; @@ -1502,9 +1578,11 @@ var strftime = function strftime(d, format) { module.exports = strftime; -},{}],18:[function(require,module,exports){ +},{}],21:[function(require,module,exports){ 'use strict'; +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; }; + /* * Checks if value is classified as a String primitive or object. * @param {any} value The value to check. @@ -1520,7 +1598,7 @@ function isString(value) { * Iteratee functions may exit iteration early by explicitly returning false. * @param {Object} object The object to iterate over. * @param {Function} iteratee The function invoked per iteration. - * @return {Object} Returs object. + * @return {Object} Returns object. */ function forOwn(object, iteratee) { object = object || {}; @@ -1532,23 +1610,93 @@ function forOwn(object, iteratee) { return object; } -exports.isString = isString; -exports.forOwn = forOwn; +/* + * Assigns own enumerable string keyed properties of source objects to the destination object. + * Source objects are applied from left to right. + * Subsequent sources overwrite property assignments of previous sources. + * + * Note: This method mutates object and is loosely based on Object.assign. + * + * @param {Object} object The destination object. + * @param {...Object} sources The source objects. + * @return {Object} Returns object. + */ +function assign(object) { + object = isObject(object) ? object : {}; + var srcs = Array.prototype.slice.call(arguments, 1); + srcs.forEach(function (src) { + _assignBinary(object, src); + }); + return object; +} -},{}],19:[function(require,module,exports){ +function _assignBinary(dst, src) { + if (!dst) return dst; + forOwn(src, function (v, k) { + dst[k] = v; + }); + return dst; +} + +function isArray(value) { + return value instanceof Array; +} + +function echo(prefix) { + return function (v) { + console.log('[' + prefix + ']', v); + return v; + }; +} + +function uniq(arr) { + var u = {}, + a = []; + for (var i = 0, l = arr.length; i < l; ++i) { + if (u.hasOwnProperty(arr[i])) { + continue; + } + a.push(arr[i]); + u[arr[i]] = 1; + } + return a; +} + +/* + * Checks if value is the language type of Object. + * (e.g. arrays, functions, objects, regexes, new Number(0), and new String('')) + * @param {any} value The value to check. + * @return {Boolean} Returns true if value is an object, else false. + */ +function isObject(value) { + return value !== null && (typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object'; +} + +exports.isString = isString; +exports.isArray = isArray; +exports.isObject = isObject; + +exports.forOwn = forOwn; +exports.assign = assign; +exports.uniq = uniq; + +exports.echo = echo; + +},{}],22:[function(require,module,exports){ 'use strict'; var Liquid = require('..'); var lexical = Liquid.lexical; var Promise = require('any-promise'); var re = new RegExp('(' + lexical.identifier.source + ')\\s*=(.*)'); +var assert = require('../src/util/assert.js'); module.exports = function (liquid) { liquid.registerTag('assign', { parse: function parse(token) { var match = token.args.match(re); - if (!match) throw new Error('illegal token ' + token.raw); + assert(match, 'illegal token ' + token.raw); this.key = match[1]; this.value = match[2]; }, @@ -1559,12 +1707,13 @@ module.exports = function (liquid) { }); }; -},{"..":2,"any-promise":3}],20:[function(require,module,exports){ +},{"..":2,"../src/util/assert.js":16,"any-promise":3}],23:[function(require,module,exports){ 'use strict'; var Liquid = require('..'); var lexical = Liquid.lexical; var re = new RegExp('(' + lexical.identifier.source + ')'); +var assert = require('../src/util/assert.js'); module.exports = function (liquid) { @@ -1573,7 +1722,7 @@ module.exports = function (liquid) { var _this = this; var match = tagToken.args.match(re); - if (!match) throw new Error(tagToken.args + ' not valid identifier'); + assert(match, tagToken.args + ' not valid identifier'); this.variable = match[1]; this.templates = []; @@ -1598,10 +1747,11 @@ module.exports = function (liquid) { }); }; -},{"..":2}],21:[function(require,module,exports){ +},{"..":2,"../src/util/assert.js":16}],24:[function(require,module,exports){ 'use strict'; var Liquid = require('..'); +var assert = require('../src/util/assert.js'); module.exports = function (liquid) { liquid.registerTag('case', { @@ -1649,7 +1799,7 @@ module.exports = function (liquid) { }); }; -},{"..":2}],22:[function(require,module,exports){ +},{"..":2,"../src/util/assert.js":16}],25:[function(require,module,exports){ 'use strict'; module.exports = function (liquid) { @@ -1667,7 +1817,7 @@ module.exports = function (liquid) { }); }; -},{}],23:[function(require,module,exports){ +},{}],26:[function(require,module,exports){ 'use strict'; var Liquid = require('..'); @@ -1675,13 +1825,14 @@ 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'); +var assert = require('../src/util/assert.js'); module.exports = function (liquid) { liquid.registerTag('cycle', { parse: function parse(tagToken, remainTokens) { var match = groupRE.exec(tagToken.args); - if (!match) throw new Error('illegal tag: ' + tagToken.raw); + assert(match, 'illegal tag: ' + tagToken.raw); this.group = match[1] || ''; var candidates = match[2]; @@ -1692,13 +1843,13 @@ module.exports = function (liquid) { this.candidates.push(match[0]); } - if (!this.candidates.length) { - throw new Error('empty candidates: ' + tagToken.raw); - } + assert(this.candidates.length, 'empty candidates: ' + tagToken.raw); }, - render: function render(scope, hash, register) { - var fingerprint = Liquid.evalValue(this.group, scope) + ':' + this.candidates.join(','); + render: function render(scope, hash) { + var group = Liquid.evalValue(this.group, scope); + var fingerprint = 'cycle:' + group + ':' + this.candidates.join(','); + var register = scope.get('liquid'); var idx = register[fingerprint]; if (idx === undefined) { @@ -1714,18 +1865,19 @@ module.exports = function (liquid) { }); }; -},{"..":2,"any-promise":3}],24:[function(require,module,exports){ +},{"..":2,"../src/util/assert.js":16,"any-promise":3}],27:[function(require,module,exports){ 'use strict'; var Liquid = require('..'); var lexical = Liquid.lexical; +var assert = require('../src/util/assert.js'); module.exports = function (liquid) { liquid.registerTag('decrement', { parse: function parse(token) { var match = token.args.match(lexical.identifier); - if (!match) throw new Error('illegal identifier ' + token.args); + assert(match, 'illegal identifier ' + token.args); this.variable = match[0]; }, render: function render(scope, hash) { @@ -1736,12 +1888,15 @@ module.exports = function (liquid) { }); }; -},{"..":2}],25:[function(require,module,exports){ +},{"..":2,"../src/util/assert.js":16}],28:[function(require,module,exports){ 'use strict'; var Liquid = require('..'); var Promise = require('any-promise'); var lexical = Liquid.lexical; +var mapSeries = require('../src/util/promise.js').mapSeries; +var RenderBreak = Liquid.Types.RenderBreak; +var assert = require('../src/util/assert.js'); var re = new RegExp('^(' + lexical.identifier.source + ')\\s+in\\s+' + ('(' + lexical.value.source + ')') + ('(?:\\s+' + lexical.hash.source + ')*') + '(?:\\s+(reversed))?$'); module.exports = function (liquid) { @@ -1751,7 +1906,7 @@ module.exports = function (liquid) { var _this = this; var match = re.exec(tagToken.args); - if (!match) throw new Error('illegal tag: ' + tagToken.raw); + assert(match, 'illegal tag: ' + tagToken.raw); this.variable = match[1]; this.collection = match[2]; this.reversed = !!match[3]; @@ -1783,7 +1938,6 @@ module.exports = function (liquid) { return liquid.renderer.renderTemplates(this.elseTemplates, scope); } - var html = ''; var length = collection.length; var offset = hash.offset || 0; var limit = hash.limit === undefined ? collection.length : hash.limit; @@ -1791,11 +1945,7 @@ module.exports = function (liquid) { 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(function (item, i) { + var contexts = collection.map(function (item, i) { var ctx = {}; ctx[_this2.variable] = item; ctx.forloop = { @@ -1809,51 +1959,36 @@ module.exports = function (liquid) { stop: false, skip: false }; - // We are just putting together an array of the arguments we will be passing to our sequential promises - contexts.push(ctx); + return ctx; }); - // 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(function (promise, context) { - return promise.then(function (partial) { - if (scope.get('forloop.stop')) { - throw new Error('forloop.stop'); // this will stop the sequential promise chain - } - + var html = ''; + return mapSeries(contexts, function (context) { + scope.push(context); + return liquid.renderer.renderTemplates(_this2.templates, scope).then(function (partial) { return html += partial; - }).then(function (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(_this2.templates, scope); - }).then(function (partial) { - scope.pop(context); - return partial; + }).catch(function (e) { + if (e instanceof RenderBreak) { + html += e.resolvedHTML; + if (e.message === 'continue') return; + } + throw e; + }).then(function () { + return scope.pop(); }); - }, 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(function (partial) { - return html += partial; - }).catch(function (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; + }).catch(function (e) { + if (e instanceof RenderBreak && e.message === 'break') { + return; } + throw e; + }).then(function () { + return html; }); } }); }; -},{"..":2,"any-promise":3}],26:[function(require,module,exports){ +},{"..":2,"../src/util/assert.js":16,"../src/util/promise.js":19,"any-promise":3}],29:[function(require,module,exports){ 'use strict'; var Liquid = require('..'); @@ -1907,19 +2042,20 @@ module.exports = function (liquid) { }); }; -},{"..":2}],27:[function(require,module,exports){ +},{"..":2}],30:[function(require,module,exports){ 'use strict'; var Liquid = require('..'); var lexical = Liquid.lexical; var withRE = new RegExp('with\\s+(' + lexical.value.source + ')'); +var assert = require('../src/util/assert.js'); module.exports = function (liquid) { liquid.registerTag('include', { parse: function parse(token) { var match = lexical.value.exec(token.args); - if (!match) throw new Error('illegal token ' + token.raw); + assert(match, 'illegal token ' + token.raw); this.value = match[0]; match = withRE.exec(token.args); @@ -1929,24 +2065,31 @@ module.exports = function (liquid) { }, render: function render(scope, hash) { var filepath = Liquid.evalValue(this.value, scope); + + var register = scope.get('liquid'); + var originBlocks = register.blocks; + register.blocks = {}; + if (this.with) { hash[filepath] = Liquid.evalValue(this.with, scope); } - return liquid.handleCache(filepath).then(function (templates) { + return liquid.getTemplate(filepath, register.root).then(function (templates) { scope.push(hash); return liquid.renderer.renderTemplates(templates, scope); }).then(function (html) { scope.pop(); + register.blocks = originBlocks; return html; }); } }); }; -},{"..":2}],28:[function(require,module,exports){ +},{"..":2,"../src/util/assert.js":16}],31:[function(require,module,exports){ 'use strict'; var Liquid = require('..'); +var assert = require('../src/util/assert.js'); var lexical = Liquid.lexical; module.exports = function (liquid) { @@ -1954,7 +2097,7 @@ module.exports = function (liquid) { liquid.registerTag('increment', { parse: function parse(token) { var match = token.args.match(lexical.identifier); - if (!match) throw new Error('illegal identifier ' + token.args); + assert(match, 'illegal identifier ' + token.args); this.variable = match[0]; }, render: function render(scope, hash) { @@ -1965,7 +2108,7 @@ module.exports = function (liquid) { }); }; -},{"..":2}],29:[function(require,module,exports){ +},{"..":2,"../src/util/assert.js":16}],32:[function(require,module,exports){ "use strict"; module.exports = function (engine) { @@ -1985,40 +2128,45 @@ module.exports = function (engine) { require("./unless.js")(engine); }; -},{"./assign.js":19,"./capture.js":20,"./case.js":21,"./comment.js":22,"./cycle.js":23,"./decrement.js":24,"./for.js":25,"./if.js":26,"./include.js":27,"./increment.js":28,"./layout.js":30,"./raw.js":31,"./tablerow.js":32,"./unless.js":33}],30:[function(require,module,exports){ +},{"./assign.js":22,"./capture.js":23,"./case.js":24,"./comment.js":25,"./cycle.js":26,"./decrement.js":27,"./for.js":28,"./if.js":29,"./include.js":30,"./increment.js":31,"./layout.js":33,"./raw.js":34,"./tablerow.js":35,"./unless.js":36}],33:[function(require,module,exports){ 'use strict'; var Liquid = require('..'); var Promise = require('any-promise'); var lexical = Liquid.lexical; +var assert = require('../src/util/assert.js'); module.exports = function (liquid) { liquid.registerTag('layout', { parse: function parse(token, remainTokens) { var match = lexical.value.exec(token.args); - if (!match) throw new Error('illegal token ' + token.raw); + assert(match, 'illegal token ' + token.raw); this.layout = match[0]; this.tpls = liquid.parser.parse(remainTokens); }, render: function render(scope, hash) { var layout = Liquid.evalValue(this.layout, scope); + var register = scope.get('liquid'); - var html = ''; - scope.push({}); - // not sure if this first one is needed, since the results are ignored - return liquid.renderer.renderTemplates(this.tpls, scope).then(function (partial) { - html += partial; - return liquid.handleCache(layout); - }).then(function (templates) { + // render the remaining tokens immediately + return liquid.renderer.renderTemplates(this.tpls, scope) + // now register.blocks contains rendered blocks + .then(function () { + return liquid.getTemplate(layout, register.root); + }) + // push the hash + .then(function (templates) { + return scope.push(hash), templates; + }) + // render the parent + .then(function (templates) { return liquid.renderer.renderTemplates(templates, scope); - }).then(function (partial) { - scope.pop(); - return partial; - }).catch(function (e) { - e.file = layout; - throw e; + }) + // pop the hash + .then(function (partial) { + return scope.pop(), partial; }); } }); @@ -2031,36 +2179,37 @@ module.exports = function (liquid) { this.block = match ? match[0] : 'anonymous'; this.tpls = []; - var p, - stream = liquid.parser.parseStream(remainTokens).on('tag:endblock', function (token) { + var stream = liquid.parser.parseStream(remainTokens).on('tag:endblock', function () { return stream.stop(); }).on('template', function (tpl) { return _this.tpls.push(tpl); - }).on('end', function (x) { + }).on('end', function () { throw new Error('tag ' + token.raw + ' not closed'); }); stream.start(); }, - render: function render(scope, hash) { + render: function render(scope) { var _this2 = this; - var html = scope.get('_liquid.blocks.' + this.block); - var promise = Promise.resolve(''); + var register = scope.get('liquid'); + var html = register.blocks[this.block]; + // if not defined yet if (html === undefined) { - promise = liquid.renderer.renderTemplates(this.tpls, scope).then(function (partial) { - scope.set('_liquid.blocks.' + _this2.block, partial); + return liquid.renderer.renderTemplates(this.tpls, scope).then(function (partial) { + register.blocks[_this2.block] = partial; return partial; }); - } else { - scope.set('_liquid.blocks.' + this.block, html); - promise = Promise.resolve(html); } - return promise; + // if already defined by desendents + else { + register.blocks[this.block] = html; + return Promise.resolve(html); + } } }); }; -},{"..":2,"any-promise":3}],31:[function(require,module,exports){ +},{"..":2,"../src/util/assert.js":16,"any-promise":3}],34:[function(require,module,exports){ 'use strict'; var Promise = require('any-promise'); @@ -2090,12 +2239,13 @@ module.exports = function (liquid) { }); }; -},{"any-promise":3}],32:[function(require,module,exports){ +},{"any-promise":3}],35:[function(require,module,exports){ 'use strict'; var Liquid = require('..'); var Promise = require('any-promise'); var lexical = Liquid.lexical; +var assert = require('../src/util/assert.js'); var re = new RegExp('^(' + lexical.identifier.source + ')\\s+in\\s+' + ('(' + lexical.value.source + ')') + ('(?:\\s+' + lexical.hash.source + ')*$')); module.exports = function (liquid) { @@ -2105,7 +2255,7 @@ module.exports = function (liquid) { var _this = this; var match = re.exec(tagToken.args); - if (!match) throw new Error('illegal tag: ' + tagToken.raw); + assert(match, 'illegal tag: ' + tagToken.raw); this.variable = match[1]; this.collection = match[2]; @@ -2191,7 +2341,7 @@ module.exports = function (liquid) { }); }; -},{"..":2,"any-promise":3}],33:[function(require,module,exports){ +},{"..":2,"../src/util/assert.js":16,"any-promise":3}],36:[function(require,module,exports){ 'use strict'; var Liquid = require('..'); diff --git a/dist/liquid.min.js b/dist/liquid.min.js index ec36a6737..6b32761bc 100644 --- a/dist/liquid.min.js +++ b/dist/liquid.min.js @@ -1 +1,2 @@ -!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var r;r="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,r.Liquid=e()}}(function(){return function e(r,t,n){function i(o,a){if(!t[o]){if(!r[o]){var u="function"==typeof require&&require;if(!a&&u)return u(o,!0);if(s)return s(o,!0);var c=new Error("Cannot find module '"+o+"'");throw c.code="MODULE_NOT_FOUND",c}var l=t[o]={exports:{}};r[o][0].call(l.exports,function(e){var t=r[o][1][e];return i(t?t:e)},l,l.exports,e,r,t,n)}return t[o].exports}for(var s="function"==typeof require&&require,o=0;o|"|'/g,function(e){return f[e]})}function n(e){return o(e).replace(/&(amp|lt|gt|#34|#39);/g,function(e){return p[e]})}function i(e){var r=(e+"").split(".");return r.length>1?r[1].length:0}function s(e,r){return Math.max(i(e),i(r))}function o(e){return e=e||"",e+""}function a(e){return function(r,t){var n=s(r,t);return e(r,t).toFixed(n)}}function u(e){return l.forOwn(h,function(r,t){return e.registerFilter(t,r)})}var c=e("./src/util/strftime.js"),l=e("./src/util/underscore.js"),f={"&":"&","<":"<",">":">",'"':""","'":"'"},p={"&":"&","<":"<",">":">",""":'"',"'":"'"},h={abs:function(e){return Math.abs(e)},append:function(e,r){return e+r},capitalize:function(e){return o(e).charAt(0).toUpperCase()+e.slice(1)},ceil:function(e){return Math.ceil(e)},date:function(e,r){return"now"===e&&(e=new Date),c(e,r)},"default":function(e,r){return r||e},divided_by:function(e,r){return Math.floor(e/r)},downcase:function(e){return e.toLowerCase()},escape:t,escape_once:function(e){return t(n(e))},first:function(e){return e[0]},floor:function(e){return Math.floor(e)},join:function(e,r){return e.join(r)},last:function(e){return e[e.length-1]},lstrip:function(e){return o(e).replace(/^\s+/,"")},map:function(e,r){return e.map(function(e){return e[r]})},minus:a(function(e,r){return e-r}),modulo:a(function(e,r){return e%r}),newline_to_br:function(e){return e.replace(/\n/g,"
")},plus:a(function(e,r){return e+r}),prepend:function(e,r){return r+e},remove:function(e,r){return e.split(r).join("")},remove_first:function(e,r){return e.replace(r,"")},replace:function(e,r,t){return o(e).split(r).join(t)},replace_first:function(e,r,t){return o(e).replace(r,t)},reverse:function(e){return e.reverse()},round:function(e,r){var t=Math.pow(10,r||0);return Math.round(e*t,r)/t},rstrip:function(e){return o(e).replace(/\s+$/,"")},size:function(e){return e.length},slice:function(e,r,t){return e.substr(r,void 0===t?1:t)},sort:function(e,r){return e.sort(r)},split:function(e,r){return o(e).split(r)},strip:function(e){return o(e).trim()},strip_html:function(e){return o(e).replace(/<\/?\s*\w+\s*\/?>/g,"")},strip_newlines:function(e){return o(e).replace(/\n/g,"")},times:function(e,r){return e*r},truncate:function(e,r,t){return e=o(e),t=void 0===t?"...":t,r=r||16,e.length<=r?e:e.substr(0,r-t.length)+t},truncatewords:function(e,r,t){void 0===t&&(t="...");var n=e.split(" "),i=n.slice(0,r).join(" ");return n.length>r&&(i+=t),i},uniq:function(e){var r={};return(e||[]).filter(function(e){return r.hasOwnProperty(e)?!1:(r[e]=!0,!0)})},upcase:function(e){return o(e).toUpperCase()},url_encode:encodeURIComponent};u.filters=h,r.exports=u},{"./src/util/strftime.js":17,"./src/util/underscore.js":18}],2:[function(e,r){"use strict";function t(e){e=e||{},e.root=e.root||"",e.extname=e.extname||".liquid";var r=Object.create(v);return r.init(c(),l(),e),r}function n(e,r){if("/"==r[0])return r;var t=e.split("/").concat(r.split("/")),n=[];return t.forEach(function(e){".."==e?n.pop():e&&"."!=e&&n.push(e)}),"/"+n.join("/")}var i=e("./src/scope"),s=e("./src/tokenizer.js"),o=e("fs"),a=e("./src/render.js"),u=e("./src/lexical.js"),c=e("./src/tag.js"),l=e("./src/filter.js"),f=e("./src/parser"),p=e("./src/syntax.js"),h=e("./tags"),g=e("./filters"),d=e("any-promise"),v={init:function(e,r,t){return t.cache&&(this.cache={}),this.options=t,this.tag=e,this.filter=r,this.parser=f(e,r),this.renderer=a(),h(this),g(this),this},parse:function(e){var r=s.parse(e);return this.parser.parse(r)},render:function(e,r,t){t=t||{},t.strict_variables=t.strict_variables||!1,t.strict_filters=t.strict_filters||!1,this.renderer.resetRegisters();var n=i.factory(r,{strict:t.strict_variables});return this.renderer.renderTemplates(e,n,t)},parseAndRender:function(e,r,t){try{var n=this.parse(e);return this.render(n,r,t)}catch(i){return d.reject(i)}},renderFile:function(e,r,t){var n=this;return this.handleCache(e).then(function(e){return n.render(e,r,t)})["catch"](function(r){throw r.file=e,r})},evalOutput:function(e,r){var t=this.parser.parseOutput(e.trim());return this.renderer.evalOutput(t,r)},registerFilter:function(e,r){return this.filter.register(e,r)},registerTag:function(e,r){return this.tag.register(e,r)},handleCache:function(e){var r=this;if(!e)throw new Error("filepath cannot be null");return this.getTemplate(e).then(function(t){var n=r.options.cache&&r.cache[e]||r.parse(t);return r.options.cache?r.cache[e]=n:n})},getTemplate:function(e){return e=n(this.options.root,e),e.match(/\.\w+$/)||(e+=this.options.extname),new d(function(r,t){o.readFile(e,"utf8",function(e,n){e?t(e):r(n)})})},express:function(e){var r=this;return function(t,n,i){r.renderFile(t,n,e).then(function(e){return i(null,e)})["catch"](function(e){return i(e)})}}};t.lexical=u,t.isTruthy=p.isTruthy,t.isFalsy=p.isFalsy,t.evalExp=p.evalExp,t.evalValue=p.evalValue,r.exports=t},{"./filters":1,"./src/filter.js":8,"./src/lexical.js":9,"./src/parser":11,"./src/render.js":12,"./src/scope":13,"./src/syntax.js":14,"./src/tag.js":15,"./src/tokenizer.js":16,"./tags":29,"any-promise":3,fs:6}],3:[function(e,r){"use strict";r.exports=e("./register")().Promise},{"./register":5}],4:[function(e,r){"use strict";var t="@@any-promise/REGISTRATION",n=null;r.exports=function(e,r){return function(i,s){i=i||null,s=s||{};var o=s.global!==!1;if(null===n&&o&&(n=e[t]||null),null!==n&&null!==i&&n.implementation!==i)throw new Error('any-promise already defined as "'+n.implementation+'". You can only register an implementation before the first call to require("any-promise") and an implementation cannot be changed');return null===n&&(n=null!==i&&"undefined"!=typeof s.Promise?{Promise:s.Promise,implementation:i}:r(i),o&&(e[t]=n)),n}}},{}],5:[function(e,r){"use strict";function t(){if("undefined"==typeof window.Promise)throw new Error("any-promise browser requires a polyfill or explicit registration e.g: require('any-promise/register/bluebird')");return{Promise:window.Promise,implementation:"window.Promise"}}r.exports=e("./loader")(window,t)},{"./loader":4}],6:[function(){"use strict"},{}],7:[function(e,r){"use strict";function t(e,r,t){Error.captureStackTrace(this,this.constructor),this.name=this.constructor.name,this.message=e||"",this.input=r,this.line=t}function n(e,r,t,n){Error.captureStackTrace(this,this.constructor),this.name=this.constructor.name,this.originalError=n,this.message=e||"",this.input=r,this.line=t}t.prototype=Object.create(Error.prototype),t.prototype.constructor=t,n.prototype=Object.create(Error.prototype),n.prototype.constructor=n,r.exports={TokenizationError:t,ParseError:n}},{}],8:[function(e,r){"use strict";var t=e("./lexical.js"),n=e("./syntax.js"),i=new RegExp(""+t.value.source,"g");r.exports=function(){function e(e){var r=Object.create(a);return r.parse(e)}function r(e,r){o[e]=r}function s(){o={}}var o={},a={render:function(e,r){var t=this.args.map(function(e){return n.evalValue(e,r)});return t.unshift(e),this.filter.apply(null,t)},parse:function(e){var r=t.filterLine.exec(e);if(!r)throw new Error("illegal filter: "+e);var n=r[1],s=r[2]||"",a=o[n];if("function"!=typeof a)return{name:n,error:new Error("undefined filter: "+n)};for(var u=[];r=i.exec(s.trim());)u.push(r[0]);return this.name=n,this.filter=a,this.args=u,this}};return{construct:e,register:r,clear:s}}},{"./lexical.js":9,"./syntax.js":14}],9:[function(e,r){"use strict";function t(e){return q.test(e)}function n(e){return k.test(e)}function i(e){return L.test(e)}function s(e){return R.test(e)}function o(e){return E.exec(e)}function a(e){var r;return(r=e.match(S))?Number(e):(r=e.match(M))?"true"===e.toLowerCase():(r=e.match(D))?e.slice(1,-1):void 0}var u=/'[^']*'/,c=/"[^"]*"/,l=new RegExp(u.source+"|"+c.source),f=new RegExp("(?:"+l.source+"|[^'\"])*"),p=/-?\d+/,h=/-?\d+\.?\d*|\.?\d+/,g=/true|false/,d=/[\w-]+/,v=new RegExp("\\[(?:"+l.source+"|[\\w-\\.]+)\\]"),m=new RegExp("(?:"+l.source+"|"+g.source+"|"+h.source+")"),w=new RegExp(d.source+"(?:\\."+d.source+"|"+v.source+")*"),x=new RegExp("(?:"+w.source+"|"+h.source+")"),y=new RegExp("\\("+x.source+"\\.\\."+x.source+"\\)"),b=new RegExp("\\(("+x.source+")\\.\\.("+x.source+")\\)"),E=new RegExp("(?:"+w.source+"|"+m.source+"|"+y.source+")"),j=new RegExp("(?:"+d.source+")\\s*:\\s*(?:"+E.source+")"),T=new RegExp("("+d.source+")\\s*:\\s*("+E.source+")","g"),O=new RegExp("^\\s*("+d.source+")\\s*(.*)\\s*$"),k=new RegExp("^"+m.source+"$","i"),R=new RegExp("^"+w.source+"$"),S=new RegExp("^"+h.source+"$"),M=new RegExp("^"+g.source+"$","i"),D=new RegExp("^"+l.source+"$"),L=new RegExp("^"+b.source+"$"),q=new RegExp("^"+p.source+"$"),P=new RegExp(E.source+"(\\s*,\\s*"+E.source+")*"),_=new RegExp(d.source+"(?:\\s*:\\s*"+P.source+")?","g"),F=new RegExp("("+d.source+")(?:\\s*:\\s*("+P.source+"))?"),I=new RegExp("^"+F.source+"$"),$=[/\s+or\s+/,/\s+and\s+/,/==|!=|<=|>=|<|>|\s+contains\s+/];r.exports={quoted:l,number:h,bool:g,literal:m,filter:_,integer:p,hash:j,hashCapture:T,range:y,rangeCapture:b,identifier:d,value:E,quoteBalanced:f,operators:$,quotedLine:D,numberLine:S,boolLine:M,rangeLine:L,literalLine:k,filterLine:I,tagLine:O,isLiteral:n,isVariable:s,parseLiteral:a,isRange:i,matchValue:o,isInteger:t}},{}],10:[function(e,r){"use strict";var t={"==":function(e,r){return e==r},"!=":function(e,r){return e!=r},">":function(e,r){return e>r},"<":function(e,r){return r>e},">=":function(e,r){return e>=r},"<=":function(e,r){return r>=e},contains:function(e,r){return e.indexOf(r)>-1},and:function(e,r){return e&&r},or:function(e,r){return e||r}};r.exports=t},{}],11:[function(e,r){"use strict";var t=e("./lexical.js"),n=e("./error.js").ParseError;r.exports=function(e,r){function i(e){for(var r,t=[];r=e.shift();)t.push(s(r,e));return t}function s(e,r){try{switch(e.type){case"tag":return o(e,r);case"output":return a(e.value);case"html":return e}}catch(t){throw new n(t.message,e.input,e.line,t)}}function o(r,t){return"continue"===r.name||"break"===r.name?r:e.construct(r,t)}function a(e){var n=t.matchValue(e);if(!n)throw new Error("illegal output string: "+e);var i=n[0];e=e.substr(n.index+n[0].length);for(var s=[];n=t.filter.exec(e);)s.push([n[0].trim()]);return{type:"output",initial:i,filters:s.map(function(e){return r.construct(e)})}}function u(e){var r=Object.create(c);return r.init(e)}var c={init:function(e){return this.tokens=e,this.handlers={},this},on:function(e,r){return this.handlers[e]=r,this},trigger:function(e,r){var t=this.handlers[e];return"function"==typeof t?(t(r),!0):void 0},start:function(){this.trigger("start");for(var e;!this.stopRequested&&(e=this.tokens.shift());)if(!(this.trigger("token",e)||"tag"==e.type&&this.trigger("tag:"+e.name,e))){var r=s(e,this.tokens);this.trigger("template",r)}return this.stopRequested||this.trigger("end"),this},stop:function(){return this.stopRequested=!0,this}};return{parse:i,parseTag:o,parseStream:u,parseOutput:a}}},{"./error.js":7,"./lexical.js":9}],12:[function(e,r){"use strict";function t(){var e=Object.create(o);return e.register={},e}function n(e){return"string"==typeof e?e:JSON.stringify(e)}var i=e("./syntax.js"),s=e("any-promise"),o={renderTemplates:function(e,r,t){var i=this;if(!r)throw new Error("unable to evalTemplates: scope undefined");t=t||{},t.strict_filters=t.strict_filters||!1;var o="",a=e.reduce(function(e,a){return e.then(function(){if(r.safeGet("forloop.skip"))return s.resolve("");if(r.safeGet("forloop.stop"))throw new Error("forloop.stop");var e=s.resolve("");switch(a.type){case"tag":e=i.renderTag(a,r,i.register).then(function(e){return void 0===e?!0:o+=e});break;case"html":e=s.resolve(a.value).then(function(e){return o+=e});break;case"output":var u=i.evalOutput(a,r,t);e=s.resolve(void 0===u?"":n(u)).then(function(e){return o+=e})}return e})["catch"](function(e){if("forloop.skip"===e.message)return o;throw e})},s.resolve(""));return a.then(function(e){return e})["catch"](function(e){throw e})},renderTag:function(e,r,t){return"continue"===e.name?(r.set("forloop.skip",!0),s.resolve("")):"break"===e.name?(r.set("forloop.stop",!0),r.set("forloop.skip",!0),s.reject(new Error("forloop.stop"))):e.render(r,t)},evalOutput:function(e,r,t){if(!r)throw new Error("unable to evalOutput: scope undefined");var n=i.evalExp(e.initial,r);return e.filters.some(function(e){if(e.error){if(t.strict_filters)throw e.error;return n="",!0}n=e.render(n,r)}),n},resetRegisters:function(){return this.register={}}};r.exports=t},{"./syntax.js":14,"any-promise":3}],13:[function(e,r,t){"use strict";function n(e,r){for(var t=1,n=r;n=0;r--){var n=this.scopes[r];for(var i in n)n.hasOwnProperty(i)&&(t[i]=n[i])}return t}for(r=this.scopes.length-1;r>=0;r--){var s=this.getPropertyByPath(this.scopes[r],e);if(void 0!==s)return s}},get:function(e){var r=this.safeGet(e);if(void 0===r&&this.opts.strict)throw new Error("[strict_variables] undefined variable: "+e);return r},set:function(e,r){return this.setPropertyByPath(this.scopes[this.scopes.length-1],e,r),this},push:function(e){if(!e)throw new Error("trying to push "+e+" into scopes");return this.scopes.push(e)},pop:function(){return this.scopes.pop()},setPropertyByPath:function(e,r,t){if(i.isString(r)){for(var n=r.replace(/\[/g,".").replace(/\]/g,"").split("."),s=0;s=m;m++)v.push(m);return v}return n(e,r)}function n(e,r){return e=e&&e.trim(),e?a.isLiteral(e)?a.parseLiteral(e):a.isVariable(e)?r.get(e):void 0:void 0}function i(e){return e instanceof Array?!!e.length:!!e}function s(e){return!i(e)}var o=e("./operators.js"),a=e("./lexical.js");r.exports={evalExp:t,evalValue:n,isTruthy:i,isFalsy:s}},{"./lexical.js":9,"./operators.js":10}],15:[function(e,r){"use strict";function t(e,r){var t,i={};for(n.hashCapture.lastIndex=0;t=n.hashCapture.exec(e);){var o=t[1],a=t[2];i[o]=s.evalValue(a,r)}return i}var n=e("./lexical.js"),i=e("any-promise"),s=e("./syntax.js");r.exports=function(){function e(e,r){s[e]=r}function r(e,r){var t=Object.create(o);return t.parse(e,r),t}function n(){s={}}var s={},o={render:function(e,r){var n=r[this.name];n||(n=r[this.name]={});var s=t(this.token.args,e);return this.tagImpl.render&&this.tagImpl.render(e,s,n)||i.resolve("")},parse:function(e,r){this.type="tag",this.token=e,this.name=e.name;var t=s[this.name];if(!t)throw new Error("tag "+this.name+" not found");this.tagImpl=Object.create(t),this.tagImpl.parse&&this.tagImpl.parse(e,r)}};return{construct:r,register:e,clear:n}}},{"./lexical.js":9,"./syntax.js":14,"any-promise":3}],16:[function(e,r,t){"use strict";function n(e){function r(e,r,i){return{type:e,raw:i[r],value:i[r+1].trim(),line:n(i),input:t(i)}}function t(e){var r=e.input.lastIndexOf("\n",e.index),t=e.input.indexOf("\n",e.index);return-1===t&&(t=e.input.length),e.input.slice(r+1,t)}function n(e){var r=e.input.slice(p+1,e.index).split("\n");return h+=r.length-1,p=e.index,h+1}var o=[];if(!e)return o;for(var a,u,c,l=/({%(.*?)%})|({{(.*?)}})/g,f=0,p=-1,h=0;null!==(a=l.exec(e));){if(a.index>f&&(u=e.slice(f,a.index),o.push({type:"html",raw:u,value:u})),a[1]){c=r("tag",1,a);var g=c.value.match(i.tagLine);if(!g)throw new s("illegal tag: "+c.raw,c.input,c.line);c.name=g[1],c.args=g[2],o.push(c)}else c=r("output",3,a),o.push(c);f=l.lastIndex}return e.length>f&&(u=e.slice(f,e.length),o.push({type:"html",raw:u,value:u})),o}var i=e("./lexical.js"),s=e("./error.js").TokenizationError;t.parse=n},{"./error.js":7,"./lexical.js":9}],17:[function(e,r){"use strict";var t=["January","February","March","April","May","June","July","August","September","October","November","December"],n=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],i=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],s=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],o={1:"st",2:"nd",3:"rd","default":"th"},a={daysInMonth:function(e){var r=a.isLeapYear(e)?29:28;return[31,r,31,30,31,30,31,31,30,31,30,31]},getTimezone:function(e){return e.toString().replace(/^.*? ([A-Z]{3}) [0-9]{4}.*$/,"$1").replace(/^.*?\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\)$/,"$1$2$3")},getGMTOffset:function(e){return(e.getTimezoneOffset()>0?"-":"+")+u.pad(Math.floor(e.getTimezoneOffset()/60),2)+u.pad(e.getTimezoneOffset()%60,2)},getDayOfYear:function(e){for(var r=0,t=0;tr?r+7:r},getLastDayOfMonth:function(e){var r=(e.getDay()+(a.daysInMonth(e)[e.getMonth()]-e.getDate()))%7;return 0>r?r+7:r},getSuffix:function(e){var r=e.getDate().toString(),t=parseInt(r.slice(-1));return o[t]||o["default"]},applyOffset:function(e,r){return e.setTime(e.valueOf()-1e3*r),e},century:function(e){return parseInt(e.getFullYear().toString().substring(0,2),10)}},u={pad:function f(e,r,t){t||(t="0");for(var n=e.toString(),f=r-n.length;f-->0;)n=t+n;return n}},c={a:function(e){return s[e.getDay()]},A:function(e){return i[e.getDay()]},b:function(e){return n[e.getMonth()]},B:function(e){return t[e.getMonth()]},c:function(e){return e.toLocaleString()},C:function(e){return a.century(e)},d:function(e){return u.pad(e.getDate(),2)},e:function(e){return u.pad(e.getDate(),2," ")},H:function(e){return u.pad(e.getHours(),2)},I:function(e){return u.pad(e.getHours()%12||12,2)},j:function(e){return u.pad(a.getDayOfYear(e),3)},k:function(e){return u.pad(e.getHours(),2," ")},l:function(e){return u.pad(e.getHours()%12||12,2," ")},L:function(e){return u.pad(e.getMilliseconds(),3)},m:function(e){return u.pad(e.getMonth()+1,2)},M:function(e){return u.pad(e.getMinutes(),2)},p:function(e){return e.getHours()<12?"AM":"PM"},P:function(e){return e.getHours()<12?"am":"pm"},q:function(e){return a.getSuffix(e)},s:function(e){return Math.round(e.valueOf()/1e3)},S:function(e){return u.pad(e.getSeconds(),2)},u:function(e){return e.getDay()||7},U:function(e){return a.getWeekOfYear(e,0)},w:function(e){return e.getDay()},W:function(e){return a.getWeekOfYear(e,1)},x:function(e){return e.toLocaleDateString()},X:function(e){return e.toLocaleTimeString()},y:function(e){return e.getFullYear().toString().substring(2,4)},Y:function(e){return e.getFullYear()},z:function(e){var r=e.getTimezoneOffset()/60*100;return(r>0?"-":"+")+u.pad(r,4)},"%":function(){return"%"}};c.h=c.b,c.N=c.L;var l=function(e,r){for(var t="",n=r;;){var i=/%./g,s=i.exec(n);if(!s)return t+n;t+=n.slice(0,i.lastIndex-2),n=n.slice(i.lastIndex);var o=s[0].charAt(1),a=c[o];t+=a?a.call(this,e):"%"+o}};r.exports=l},{}],18:[function(e,r,t){"use strict";function n(e){return e instanceof String||"string"==typeof e}function i(e,r){e=e||{};for(var t in e)if(e.hasOwnProperty(t)&&r(e[t],t,e)===!1)break;return e}t.isString=n,t.forOwn=i},{}],19:[function(e,r){"use strict";var t=e(".."),n=t.lexical,i=e("any-promise"),s=new RegExp("("+n.identifier.source+")\\s*=(.*)");r.exports=function(e){e.registerTag("assign",{parse:function(e){var r=e.args.match(s);if(!r)throw new Error("illegal token "+e.raw);this.key=r[1],this.value=r[2]},render:function(r){return r.set(this.key,e.evalOutput(this.value,r)),i.resolve("")}})}},{"..":2,"any-promise":3}],20:[function(e,r){"use strict";var t=e(".."),n=t.lexical,i=new RegExp("("+n.identifier.source+")");r.exports=function(e){e.registerTag("capture",{parse:function(r,t){var n=this,s=r.args.match(i);if(!s)throw new Error(r.args+" not valid identifier");this.variable=s[1],this.templates=[];var o=e.parser.parseStream(t);o.on("tag:endcapture",function(){return o.stop()}).on("template",function(e){return n.templates.push(e)}).on("end",function(){throw new Error("tag "+r.raw+" not closed")}),o.start()},render:function(r){var t=this;return e.renderer.renderTemplates(this.templates,r).then(function(e){r.set(t.variable,e)})}})}},{"..":2}],21:[function(e,r){"use strict";var t=e("..");r.exports=function(e){e.registerTag("case",{parse:function(r,t){var n=this;this.cond=r.args,this.cases=[],this.elseTemplates=[];var i=[],s=e.parser.parseStream(t).on("tag:when",function(e){n.cases[e.args]||n.cases.push({val:e.args,templates:i=[]})}).on("tag:else",function(){return i=n.elseTemplates}).on("tag:endcase",function(){return s.stop()}).on("template",function(e){return i.push(e)}).on("end",function(){throw new Error("tag "+r.raw+" not closed")});s.start()},render:function(r){for(var n=0;n",l=i.offset||0,f=void 0===i.limit?u.length:i.limit,p=i.cols;if(!p)throw new Error("illegal cols: "+p);u=u.slice(l,l+f);var h=[];u.some(function(e){var r={};r[a.variable]=e,h.push(r)});var g=h.reduce(function(t,n,i){return t.then(function(){return s=Math.floor(i/p)+1,o=i%p+1,1===o&&(1!==s&&(c+=""),c+=''),c+=''}).then(function(){return r.push(n),e.renderer.renderTemplates(a.templates,r)}).then(function(e){return r.pop(n),c+=e,c+=""})},n.resolve(""));return g.then(function(){return s>0&&(c+=""),c+=""})["catch"](function(e){throw e})}})}},{"..":2,"any-promise":3}],33:[function(e,r){"use strict";var t=e("..");r.exports=function(e){e.registerTag("unless",{parse:function(r,t){var n=this;this.templates=[],this.elseTemplates=[];var i,s=e.parser.parseStream(t).on("start",function(){i=n.templates,n.cond=r.args}).on("tag:else",function(){return i=n.elseTemplates}).on("tag:endunless",function(){return s.stop()}).on("template",function(e){return i.push(e)}).on("end",function(){throw new Error("tag "+r.raw+" not closed")});s.start()},render:function(r){var n=t.evalExp(this.cond,r);return t.isFalsy(n)?e.renderer.renderTemplates(this.templates,r):e.renderer.renderTemplates(this.elseTemplates,r)}})}},{"..":2}]},{},[2])(2)}); \ No newline at end of file +!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.Liquid=e()}}(function(){return function e(t,r,n){function s(o,u){if(!r[o]){if(!t[o]){var a="function"==typeof require&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var c=new Error("Cannot find module '"+o+"'");throw c.code="MODULE_NOT_FOUND",c}var l=r[o]={exports:{}};t[o][0].call(l.exports,function(e){var r=t[o][1][e];return s(r?r:e)},l,l.exports,e,t,r,n)}return r[o].exports}for(var i="function"==typeof require&&require,o=0;o|"|'/g,function(e){return f[e]})}function n(e){return o(e).replace(/&(amp|lt|gt|#34|#39);/g,function(e){return p[e]})}function s(e){var t=(e+"").split(".");return t.length>1?t[1].length:0}function i(e,t){return Math.max(s(e),s(t))}function o(e){return e=e||"",e+""}function u(e){return function(t,r){var n=i(t,r);return e(t,r).toFixed(n)}}function a(e){return l.forOwn(h,function(t,r){return e.registerFilter(r,t)})}var c=e("./src/util/strftime.js"),l=e("./src/util/underscore.js"),f={"&":"&","<":"<",">":">",'"':""","'":"'"},p={"&":"&","<":"<",">":">",""":'"',"'":"'"},h={abs:function(e){return Math.abs(e)},append:function(e,t){return e+t},capitalize:function(e){return o(e).charAt(0).toUpperCase()+e.slice(1)},ceil:function(e){return Math.ceil(e)},date:function(e,t){return"now"===e&&(e=new Date),c(e,t)},"default":function(e,t){return t||e},divided_by:function(e,t){return Math.floor(e/t)},downcase:function(e){return e.toLowerCase()},escape:r,escape_once:function(e){return r(n(e))},first:function(e){return e[0]},floor:function(e){return Math.floor(e)},join:function(e,t){return e.join(t)},last:function(e){return e[e.length-1]},lstrip:function(e){return o(e).replace(/^\s+/,"")},map:function(e,t){return e.map(function(e){return e[t]})},minus:u(function(e,t){return e-t}),modulo:u(function(e,t){return e%t}),newline_to_br:function(e){return e.replace(/\n/g,"
")},plus:u(function(e,t){return e+t}),prepend:function(e,t){return t+e},remove:function(e,t){return e.split(t).join("")},remove_first:function(e,t){return e.replace(t,"")},replace:function(e,t,r){return o(e).split(t).join(r)},replace_first:function(e,t,r){return o(e).replace(t,r)},reverse:function(e){return e.reverse()},round:function(e,t){var r=Math.pow(10,t||0);return Math.round(e*r,t)/r},rstrip:function(e){return o(e).replace(/\s+$/,"")},size:function(e){return e.length},slice:function(e,t,r){return e.substr(t,void 0===r?1:r)},sort:function(e,t){return e.sort(t)},split:function(e,t){return o(e).split(t)},strip:function(e){return o(e).trim()},strip_html:function(e){return o(e).replace(/<\/?\s*\w+\s*\/?>/g,"")},strip_newlines:function(e){return o(e).replace(/\n/g,"")},times:function(e,t){return e*t},truncate:function(e,t,r){return e=o(e),r=void 0===r?"...":r,t=t||16,e.length<=t?e:e.substr(0,t-r.length)+r},truncatewords:function(e,t,r){void 0===r&&(r="...");var n=e.split(" "),s=n.slice(0,t).join(" ");return n.length>t&&(s+=r),s},uniq:function(e){var t={};return(e||[]).filter(function(e){return t.hasOwnProperty(e)?!1:(t[e]=!0,!0)})},upcase:function(e){return o(e).toUpperCase()},url_encode:encodeURIComponent};a.filters=h,t.exports=a},{"./src/util/strftime.js":20,"./src/util/underscore.js":21}],2:[function(e,t){"use strict";function r(e){e=i.assign({},e),e.root=n(e.root),e.root.length||(e.root=["."]),e.extname=e.extname||".liquid";var t=Object.create(b);return t.init(h(),g(),e),t}function n(e){return i.isArray(e)?e:i.isString(e)?[e]:[]}var s=e("./src/scope"),i=e("./src/util/underscore.js"),o=e("./src/util/assert.js"),u=e("./src/tokenizer.js"),a=e("./src/util/fs.js").statFileAsync,c=e("./src/util/fs.js").readFileAsync,l=e("path"),f=e("./src/render.js"),p=e("./src/lexical.js"),h=e("./src/tag.js"),g=e("./src/filter.js"),d=e("./src/parser"),v=e("./src/syntax.js"),m=e("./tags"),y=e("./filters"),x=e("any-promise"),w=e("./src/util/promise.js").anySeries,j=e("./src/util/error.js"),b={init:function(e,t,r){return r.cache&&(this.cache={}),this.options=r,this.tag=e,this.filter=t,this.parser=d(e,t),this.renderer=f(),m(this),y(this),this},parse:function(e){var t=u.parse(e);return this.parser.parse(t)},render:function(e,t,r){r=i.assign({},this.options,r);var n=s.factory(t,r);return this.renderer.renderTemplates(e,n)},parseAndRender:function(e,t,r){var n=this;return x.resolve().then(function(){return n.parse(e)}).then(function(e){return n.render(e,t,r)})["catch"](function(e){if(e instanceof j.RenderBreak)return e.html;throw e})},renderFile:function(e,t,r){var n=this;return r=i.assign({},r),this.getTemplate(e,r.root).then(function(e){return n.render(e,t,r)})["catch"](function(t){throw t.file=e,t})},evalOutput:function(e,t){var r=this.parser.parseOutput(e.trim());return this.renderer.evalOutput(r,t)},registerFilter:function(e,t){return this.filter.register(e,t)},registerTag:function(e,t){return this.tag.register(e,t)},lookup:function(e,t){t=this.options.root.concat(t||[]),t=i.uniq(t);var r=t.map(function(t){return l.resolve(t,e)});return w(r,function(e){return a(e).then(function(){return e})})["catch"](function(r){throw"ENOENT"===r.code&&(r.message="Failed to lookup "+e+" in: "+t),r})},getTemplate:function(e,t){var r=this;return l.extname(e)||(e+=this.options.extname),this.lookup(e,t).then(function(e){if(r.options.cache){var t=r.cache[e];return t?x.resolve(t):c(e).then(function(e){return r.parse(e)}).then(function(t){return r.cache[e]=t})}return c(e).then(function(e){return r.parse(e)})})},express:function(e){e=e||{};var t=this;return function(r,n,s){o(i.isArray(this.root)||i.isString(this.root),"illegal views root, are you using express.js?"),e.root=this.root,t.renderFile(r,n,e).then(function(e){return s(null,e)})["catch"](function(e){return s(e)})}}};r.lexical=p,r.isTruthy=v.isTruthy,r.isFalsy=v.isFalsy,r.evalExp=v.evalExp,r.evalValue=v.evalValue,r.Types={ParseError:j.ParseError,TokenizationEroor:j.TokenizationError,RenderBreak:j.RenderBreak,AssertionError:j.AssertionError},t.exports=r},{"./filters":1,"./src/filter.js":7,"./src/lexical.js":8,"./src/parser":10,"./src/render.js":11,"./src/scope":12,"./src/syntax.js":13,"./src/tag.js":14,"./src/tokenizer.js":15,"./src/util/assert.js":16,"./src/util/error.js":17,"./src/util/fs.js":18,"./src/util/promise.js":19,"./src/util/underscore.js":21,"./tags":32,"any-promise":3,path:6}],3:[function(e,t){"use strict";t.exports=e("./register")().Promise},{"./register":5}],4:[function(e,t){"use strict";var r="@@any-promise/REGISTRATION",n=null;t.exports=function(e,t){return function(s,i){s=s||null,i=i||{};var o=i.global!==!1;if(null===n&&o&&(n=e[r]||null),null!==n&&null!==s&&n.implementation!==s)throw new Error('any-promise already defined as "'+n.implementation+'". You can only register an implementation before the first call to require("any-promise") and an implementation cannot be changed');return null===n&&(n=null!==s&&"undefined"!=typeof i.Promise?{Promise:i.Promise,implementation:s}:t(s),o&&(e[r]=n)),n}}},{}],5:[function(e,t){"use strict";function r(){if("undefined"==typeof window.Promise)throw new Error("any-promise browser requires a polyfill or explicit registration e.g: require('any-promise/register/bluebird')");return{Promise:window.Promise,implementation:"window.Promise"}}t.exports=e("./loader")(window,r)},{"./loader":4}],6:[function(){"use strict"},{}],7:[function(e,t){"use strict";var r=e("./lexical.js"),n=e("./syntax.js"),s=e("./util/assert.js"),i=new RegExp(""+r.value.source,"g");t.exports=function(){function e(e){var t=Object.create(a);return t.parse(e)}function t(e,t){u[e]=t}function o(){u={}}var u={},a={render:function(e,t){var r=this.args.map(function(e){return n.evalValue(e,t)});return r.unshift(e),this.filter.apply(null,r)},parse:function(e){var t=r.filterLine.exec(e);s(t,"illegal filter: "+e);var n=t[1],o=t[2]||"",a=u[n];if("function"!=typeof a)return{name:n,error:new TypeError("undefined filter: "+n)};for(var c=[];t=i.exec(o.trim());)c.push(t[0]);return this.name=n,this.filter=a,this.args=c,this}};return{construct:e,register:t,clear:o}}},{"./lexical.js":8,"./syntax.js":13,"./util/assert.js":16}],8:[function(e,t){"use strict";function r(e){return A.test(e)}function n(e){return S.test(e)}function s(e){return P.test(e)}function i(e){return O.test(e)}function o(e){return b.exec(e)}function u(e){var t;return(t=e.match(R))?Number(e):(t=e.match(M))?"true"===e.toLowerCase():(t=e.match(q))?e.slice(1,-1):void 0}var a=/'[^']*'/,c=/"[^"]*"/,l=new RegExp(a.source+"|"+c.source),f=new RegExp("(?:"+l.source+"|[^'\"])*"),p=/-?\d+/,h=/-?\d+\.?\d*|\.?\d+/,g=/true|false/,d=/[\w-]+/,v=new RegExp("\\[(?:"+l.source+"|[\\w-\\.]+)\\]"),m=new RegExp("(?:"+l.source+"|"+g.source+"|"+h.source+")"),y=new RegExp(d.source+"(?:\\."+d.source+"|"+v.source+")*"),x=new RegExp("(?:"+y.source+"|"+h.source+")"),w=new RegExp("\\("+x.source+"\\.\\."+x.source+"\\)"),j=new RegExp("\\(("+x.source+")\\.\\.("+x.source+")\\)"),b=new RegExp("(?:"+y.source+"|"+m.source+"|"+w.source+")"),E=new RegExp("(?:"+d.source+")\\s*:\\s*(?:"+b.source+")"),T=new RegExp("("+d.source+")\\s*:\\s*("+b.source+")","g"),k=new RegExp("^\\s*("+d.source+")\\s*(.*)\\s*$"),S=new RegExp("^"+m.source+"$","i"),O=new RegExp("^"+y.source+"$"),R=new RegExp("^"+h.source+"$"),M=new RegExp("^"+g.source+"$","i"),q=new RegExp("^"+l.source+"$"),P=new RegExp("^"+j.source+"$"),A=new RegExp("^"+p.source+"$"),L=new RegExp(b.source+"(\\s*,\\s*"+b.source+")*"),F=new RegExp(d.source+"(?:\\s*:\\s*"+L.source+")?","g"),D=new RegExp("("+d.source+")(?:\\s*:\\s*("+L.source+"))?"),I=new RegExp("^"+D.source+"$"),_=[/\s+or\s+/,/\s+and\s+/,/==|!=|<=|>=|<|>|\s+contains\s+/];t.exports={quoted:l,number:h,bool:g,literal:m,filter:F,integer:p,hash:E,hashCapture:T,range:w,rangeCapture:j,identifier:d,value:b,quoteBalanced:f,operators:_,quotedLine:q,numberLine:R,boolLine:M,rangeLine:P,literalLine:S,filterLine:I,tagLine:k,isLiteral:n,isVariable:i,parseLiteral:u,isRange:s,matchValue:o,isInteger:r}},{}],9:[function(e,t){"use strict";var r={"==":function(e,t){return e==t},"!=":function(e,t){return e!=t},">":function(e,t){return e>t},"<":function(e,t){return t>e},">=":function(e,t){return e>=t},"<=":function(e,t){return t>=e},contains:function(e,t){return e.indexOf(t)>-1},and:function(e,t){return e&&t},or:function(e,t){return e||t}};t.exports=r},{}],10:[function(e,t){"use strict";var r=e("./lexical.js"),n=e("./util/error.js").ParseError,s=e("./util/assert.js");t.exports=function(e,t){function i(e){for(var t,r=[];t=e.shift();)r.push(o(t,e));return r}function o(e,t){try{switch(e.type){case"tag":return u(e,t);case"output":return a(e.value);case"html":return e}}catch(r){throw new n(r.message,e.input,e.line,r)}}function u(t,r){return"continue"===t.name||"break"===t.name?t:e.construct(t,r)}function a(e){var n=r.matchValue(e);s(n,"illegal output string: "+e);var i=n[0];e=e.substr(n.index+n[0].length);for(var o=[];n=r.filter.exec(e);)o.push([n[0].trim()]);return{type:"output",initial:i,filters:o.map(function(e){return t.construct(e)})}}function c(e){var t=Object.create(l);return t.init(e)}var l={init:function(e){return this.tokens=e,this.handlers={},this},on:function(e,t){return this.handlers[e]=t,this},trigger:function(e,t){var r=this.handlers[e];return"function"==typeof r?(r(t),!0):void 0},start:function(){this.trigger("start");for(var e;!this.stopRequested&&(e=this.tokens.shift());)if(!(this.trigger("token",e)||"tag"==e.type&&this.trigger("tag:"+e.name,e))){var t=o(e,this.tokens);this.trigger("template",t)}return this.stopRequested||this.trigger("end"),this},stop:function(){return this.stopRequested=!0,this}};return{parse:i,parseTag:u,parseStream:c,parseOutput:a}}},{"./lexical.js":8,"./util/assert.js":16,"./util/error.js":17}],11:[function(e,t){"use strict";function r(){var e=Object.create(c);return e}function n(e){return"string"==typeof e?e:JSON.stringify(e)}var s=e("./syntax.js"),i=e("any-promise"),o=e("./util/promise.js").mapSeries,u=e("./util/error.js").RenderBreak,a=e("./util/assert.js"),c=(e("./util/underscore.js"),{renderTemplates:function(e,t){function r(e){return"tag"===e.type?this.renderTag(e,t).then(function(e){return void 0===e?"":e}):"output"===e.type?i.resolve(this.evalOutput(e,t)).then(function(e){return void 0===e?"":n(e)}):i.resolve(e.value)}var s=this;a(t,"unable to evalTemplates: scope undefined");var c="";return o(e,function(e){return r.call(s,e).then(function(e){return c+=e})["catch"](function(e){throw e instanceof u&&(e.resolvedHTML=c),e})}).then(function(){return c})},renderTag:function(e,t){return"continue"===e.name?i.reject(new u("continue")):"break"===e.name?i.reject(new u("break")):e.render(t)},evalOutput:function(e,t){a(t,"unable to evalOutput: scope undefined");var r=s.evalExp(e.initial,t);return e.filters.some(function(e){if(e.error){if(t.get("liquid.strict_filters"))throw e.error;return r="",!0}r=e.render(r,t)}),r}});t.exports=r},{"./syntax.js":13,"./util/assert.js":16,"./util/error.js":17,"./util/promise.js":19,"./util/underscore.js":21,"any-promise":3}],12:[function(e,t,r){"use strict";function n(e,t){for(var r=1,n=t;n=0;t--)s.assign(e,this.scopes[t]);return e},get:function(e){for(var t=this.scopes.length-1;t>=0;t--)try{return this.getPropertyByPath(this.scopes[t],e)}catch(r){if(!u.test(r.message)||this.opts.strict_variables)throw r.message+=": "+e,r}if(this.opts.strict_variables)throw new TypeError("undefined variable: "+e)},set:function(e,t){return this.setPropertyByPath(this.scopes[this.scopes.length-1],e,t),this},push:function(e){return o(e,"trying to push "+e+" into scopes"),this.scopes.push(e)},pop:function(){return this.scopes.pop()},unshift:function(e){return o(e,"trying to push "+e+" into scopes"),this.scopes.unshift(e)},shift:function(){return this.scopes.shift()},setPropertyByPath:function(e,t,r){if(s.isString(t))for(var n=t.replace(/\[/g,".").replace(/\]/g,"").split("."),i=0;i=y;y++)m.push(y);return m}return n(e,t)}function n(e,t){return e=e&&e.trim(),e?u.isLiteral(e)?u.parseLiteral(e):u.isVariable(e)?t.get(e):void 0:void 0}function s(e){return e instanceof Array?!!e.length:!!e}function i(e){return!s(e)}var o=e("./operators.js"),u=e("./lexical.js"),a=e("../src/util/assert.js");t.exports={evalExp:r,evalValue:n,isTruthy:s,isFalsy:i}},{"../src/util/assert.js":16,"./lexical.js":8,"./operators.js":9}],14:[function(e,t){"use strict";function r(e,t){var r,s={};for(n.hashCapture.lastIndex=0;r=n.hashCapture.exec(e);){var o=r[1],u=r[2];s[o]=i.evalValue(u,t)}return s}var n=e("./lexical.js"),s=e("any-promise"),i=e("./syntax.js"),o=e("./util/assert.js");t.exports=function(){function e(e,t){i[e]=t}function t(e,t){var r=Object.create(u);return r.parse(e,t),r}function n(){i={}}var i={},u={render:function(e){var t=r(this.token.args,e);return this.tagImpl.render&&this.tagImpl.render(e,t)||s.resolve("")},parse:function(e,t){this.type="tag",this.token=e,this.name=e.name;var r=i[this.name];o(r,"tag "+this.name+" not found"),this.tagImpl=Object.create(r),this.tagImpl.parse&&this.tagImpl.parse(e,t)}};return{construct:t,register:e,clear:n}}},{"./lexical.js":8,"./syntax.js":13,"./util/assert.js":16,"any-promise":3}],15:[function(e,t,r){"use strict";function n(e){function t(e,t,s){return{type:e,raw:s[t],value:s[t+1].trim(),line:n(s),input:r(s)}}function r(e){var t=e.input.lastIndexOf("\n",e.index),r=e.input.indexOf("\n",e.index);return-1===r&&(r=e.input.length),e.input.slice(t+1,r)}function n(e){var t=e.input.slice(g+1,e.index).split("\n");return d+=t.length-1,g=e.index,d+1}var a=[];u(o.isString(e),new i("illegal input type"));for(var c,l,f,p=/({%(.*?)%})|({{(.*?)}})/g,h=0,g=-1,d=0;null!==(c=p.exec(e));){if(c.index>h&&(l=e.slice(h,c.index),a.push({type:"html",raw:l,value:l})),c[1]){f=t("tag",1,c);var v=f.value.match(s.tagLine);if(!v)throw new i("illegal tag: "+f.raw,f.input,f.line);f.name=v[1],f.args=v[2],a.push(f)}else f=t("output",3,c),a.push(f);h=p.lastIndex}return e.length>h&&(l=e.slice(h,e.length),a.push({type:"html",raw:l,value:l})),a}var s=e("./lexical.js"),i=e("./util/error.js").TokenizationError,o=e("./util/underscore.js"),u=e("../src/util/assert.js");r.parse=n},{"../src/util/assert.js":16,"./lexical.js":8,"./util/error.js":17,"./util/underscore.js":21}],16:[function(e,t){"use strict";function r(e,t){if(!e){if(t instanceof Error)throw t;var t=t||"expect "+e+" to be true";throw new n(t)}}var n=e("./error.js").AssertionError;t.exports=r},{"./error.js":17}],17:[function(e,t){"use strict";function r(e,t,r){Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor),this.name=this.constructor.name,this.message=e,this.input=t,this.line=r}function n(e,t,r,n){Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor),this.name=this.constructor.name,this.originalError=n,this.message=e,this.input=t,this.line=r}function s(e){Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor),this.name=this.constructor.name,this.message=e}function i(e){Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor),this.name=this.constructor.name,this.message=e}r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,n.prototype=Object.create(Error.prototype),n.prototype.constructor=n,s.prototype=Object.create(Error.prototype),s.prototype.constructor=s,i.prototype=Object.create(Error.prototype),i.prototype.constructor=i,t.exports={TokenizationError:r,ParseError:n,RenderBreak:s,AssertionError:i}},{}],18:[function(e,t){"use strict";function r(e){return new Promise(function(t,r){s.readFile(e,"utf8",function(e,n){e?r(e):t(n)})})}function n(e){return new Promise(function(t,r){s.stat(e,function(e,n){return e?r(e):t(n)})})}var s=e("fs");t.exports={readFileAsync:r,statFileAsync:n}},{fs:6}],19:[function(e,t,r){"use strict";function n(e,t){var r=i.reject(new Error("init"));return e.forEach(function(n,s){r=r["catch"](function(){return t(n,s,e)})}),r}function s(e,t){var r=i.resolve("init"),n=[];return e.forEach(function(s,i){r=r.then(function(){return t(s,i,e)}).then(function(e){return n.push(e)})}),r.then(function(){return n})}var i=e("any-promise");r.anySeries=n,r.mapSeries=s},{"any-promise":3}],20:[function(e,t){"use strict";var r=["January","February","March","April","May","June","July","August","September","October","November","December"],n=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],s=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],i=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],o={1:"st",2:"nd",3:"rd","default":"th"},u={daysInMonth:function(e){var t=u.isLeapYear(e)?29:28;return[31,t,31,30,31,30,31,31,30,31,30,31]},getDayOfYear:function(e){for(var t=0,r=0;r0;)n=r+n;return n}},c={a:function(e){return i[e.getDay()]},A:function(e){return s[e.getDay()]},b:function(e){return n[e.getMonth()]},B:function(e){return r[e.getMonth()]},c:function(e){return e.toLocaleString()},C:function(e){return u.century(e)},d:function(e){return a.pad(e.getDate(),2)},e:function(e){return a.pad(e.getDate(),2," ")},H:function(e){return a.pad(e.getHours(),2)},I:function(e){return a.pad(e.getHours()%12||12,2)},j:function(e){return a.pad(u.getDayOfYear(e),3)},k:function(e){return a.pad(e.getHours(),2," ")},l:function(e){return a.pad(e.getHours()%12||12,2," ")},L:function(e){return a.pad(e.getMilliseconds(),3)},m:function(e){return a.pad(e.getMonth()+1,2)},M:function(e){return a.pad(e.getMinutes(),2)},p:function(e){return e.getHours()<12?"AM":"PM"},P:function(e){return e.getHours()<12?"am":"pm"},q:function(e){return u.getSuffix(e)},s:function(e){return Math.round(e.valueOf()/1e3)},S:function(e){return a.pad(e.getSeconds(),2)},u:function(e){return e.getDay()||7},U:function(e){return u.getWeekOfYear(e,0)},w:function(e){return e.getDay()},W:function(e){return u.getWeekOfYear(e,1)},x:function(e){return e.toLocaleDateString()},X:function(e){return e.toLocaleTimeString()},y:function(e){return e.getFullYear().toString().substring(2,4)},Y:function(e){return e.getFullYear()},z:function(e){var t=e.getTimezoneOffset()/60*100;return(t>0?"-":"+")+a.pad(Math.abs(t),4)},"%":function(){return"%"}};c.h=c.b,c.N=c.L;var l=function(e,t){for(var r="",n=t;;){var s=/%./g,i=s.exec(n);if(!i)return r+n;r+=n.slice(0,s.lastIndex-2),n=n.slice(s.lastIndex);var o=i[0].charAt(1),u=c[o];r+=u?u.call(this,e):"%"+o}};t.exports=l},{}],21:[function(e,t,r){"use strict";function n(e){return e instanceof String||"string"==typeof e}function s(e,t){e=e||{};for(var r in e)if(e.hasOwnProperty(r)&&t(e[r],r,e)===!1)break;return e}function i(e){e=l(e)?e:{};var t=Array.prototype.slice.call(arguments,1);return t.forEach(function(t){o(e,t)}),e}function o(e,t){return e?(s(t,function(t,r){e[r]=t}),e):e}function u(e){return e instanceof Array}function a(e){return function(t){return console.log("["+e+"]",t),t}}function c(e){for(var t={},r=[],n=0,s=e.length;s>n;++n)t.hasOwnProperty(e[n])||(r.push(e[n]),t[e[n]]=1);return r}function l(e){return null!==e&&"object"===("undefined"==typeof e?"undefined":f(e))}var f="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};r.isString=n,r.isArray=u,r.isObject=l,r.forOwn=s,r.assign=i,r.uniq=c,r.echo=a},{}],22:[function(e,t){"use strict";var r=e(".."),n=r.lexical,s=e("any-promise"),i=new RegExp("("+n.identifier.source+")\\s*=(.*)"),o=e("../src/util/assert.js");t.exports=function(e){e.registerTag("assign",{parse:function(e){var t=e.args.match(i);o(t,"illegal token "+e.raw),this.key=t[1],this.value=t[2]},render:function(t){return t.set(this.key,e.evalOutput(this.value,t)),s.resolve("")}})}},{"..":2,"../src/util/assert.js":16,"any-promise":3}],23:[function(e,t){"use strict";var r=e(".."),n=r.lexical,s=new RegExp("("+n.identifier.source+")"),i=e("../src/util/assert.js");t.exports=function(e){e.registerTag("capture",{parse:function(t,r){var n=this,o=t.args.match(s);i(o,t.args+" not valid identifier"),this.variable=o[1],this.templates=[];var u=e.parser.parseStream(r);u.on("tag:endcapture",function(){return u.stop()}).on("template",function(e){return n.templates.push(e)}).on("end",function(){throw new Error("tag "+t.raw+" not closed")}),u.start()},render:function(t){var r=this;return e.renderer.renderTemplates(this.templates,t).then(function(e){t.set(r.variable,e)})}})}},{"..":2,"../src/util/assert.js":16}],24:[function(e,t){"use strict";{var r=e("..");e("../src/util/assert.js")}t.exports=function(e){e.registerTag("case",{parse:function(t,r){var n=this;this.cond=t.args,this.cases=[],this.elseTemplates=[];var s=[],i=e.parser.parseStream(r).on("tag:when",function(e){n.cases[e.args]||n.cases.push({val:e.args,templates:s=[]})}).on("tag:else",function(){return s=n.elseTemplates}).on("tag:endcase",function(){return i.stop()}).on("template",function(e){return s.push(e)}).on("end",function(){throw new Error("tag "+t.raw+" not closed")});i.start()},render:function(t){for(var n=0;n",l=s.offset||0,f=void 0===s.limit?a.length:s.limit,p=s.cols;if(!p)throw new Error("illegal cols: "+p);a=a.slice(l,l+f);var h=[];a.some(function(e){var t={};t[u.variable]=e,h.push(t)});var g=h.reduce(function(r,n,s){return r.then(function(){return i=Math.floor(s/p)+1,o=s%p+1,1===o&&(1!==i&&(c+=""),c+=''),c+=''}).then(function(){return t.push(n),e.renderer.renderTemplates(u.templates,t)}).then(function(e){return t.pop(n),c+=e,c+=""})},n.resolve(""));return g.then(function(){return i>0&&(c+=""),c+=""})["catch"](function(e){throw e})}})}},{"..":2,"../src/util/assert.js":16,"any-promise":3}],36:[function(e,t){"use strict";var r=e("..");t.exports=function(e){e.registerTag("unless",{parse:function(t,r){var n=this;this.templates=[],this.elseTemplates=[];var s,i=e.parser.parseStream(r).on("start",function(){s=n.templates,n.cond=t.args}).on("tag:else",function(){return s=n.elseTemplates}).on("tag:endunless",function(){return i.stop()}).on("template",function(e){return s.push(e)}).on("end",function(){throw new Error("tag "+t.raw+" not closed")});i.start()},render:function(t){var n=r.evalExp(this.cond,t);return r.isFalsy(n)?e.renderer.renderTemplates(this.templates,t):e.renderer.renderTemplates(this.elseTemplates,t)}})}},{"..":2}]},{},[2])(2)}); \ No newline at end of file diff --git a/package.json b/package.json index b8a4dce6c..9876e41c4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "shopify-liquid", - "version": "1.3.1", + "version": "1.3.2", "description": "Liquid template engine for JavaScript, Node.js and Browser", "main": "index.js", "scripts": {