This commit is contained in:
harttle
2017-11-06 00:16:51 +08:00
parent be00f1d385
commit e8245e9c5f
3 changed files with 75 additions and 68 deletions
+73 -66
View File
@@ -920,6 +920,9 @@ var Scope = {
return ctx; return ctx;
}, },
get: function get(str) { get: function get(str) {
if (str === 'liquid') {
throw new Error('NO LONGER SUPPORTED: use scope.opts instread of scope.get("liquid")');
}
try { try {
return this.getPropertyByPath(this.scopes, str); return this.getPropertyByPath(this.scopes, str);
} catch (e) { } catch (e) {
@@ -1077,20 +1080,15 @@ function matchRightBracket(str, begin) {
} }
exports.factory = function (ctx, opts) { exports.factory = function (ctx, opts) {
opts = _.assign({ var defaultOptions = {
strict_variables: false, strict_variables: false,
strict_filters: false, strict_filters: false,
blocks: {}, blocks: {},
root: [] root: []
}, opts); };
ctx = _.assign(ctx, {
liquid: opts
});
var scope = Object.create(Scope); var scope = Object.create(Scope);
scope.opts = opts; scope.opts = _.assign(defaultOptions, opts);
scope.scopes = [ctx]; scope.scopes = [ctx || {}];
return scope; return scope;
}; };
@@ -1342,7 +1340,7 @@ function initError() {
} }
} }
function initLiquidError(message, token) { function initLiquidError(err, token) {
initError.call(this); initError.call(this);
this.input = token.input; this.input = token.input;
@@ -1350,12 +1348,12 @@ function initLiquidError(message, token) {
this.file = token.file; this.file = token.file;
var context = mkContext(token.input, token.line); var context = mkContext(token.input, token.line);
this.message = mkMessage(message, token); this.message = mkMessage(err.message, token);
this.stack = context + '\n' + (this.stack || this.message); this.stack = context + '\n' + (this.stack || this.message) + (err.stack ? '\nFrom ' + err.stack : '');
} }
function TokenizationError(message, token) { function TokenizationError(message, token) {
initLiquidError.call(this, message, token); initLiquidError.call(this, { message: message }, token);
} }
TokenizationError.prototype = Object.create(Error.prototype); TokenizationError.prototype = Object.create(Error.prototype);
TokenizationError.prototype.constructor = TokenizationError; TokenizationError.prototype.constructor = TokenizationError;
@@ -1364,7 +1362,7 @@ function ParseError(e, token) {
_.assign(this, e); _.assign(this, e);
this.originalError = e; this.originalError = e;
initLiquidError.call(this, e.message, token); initLiquidError.call(this, e, token);
} }
ParseError.prototype = Object.create(Error.prototype); ParseError.prototype = Object.create(Error.prototype);
ParseError.prototype.constructor = ParseError; ParseError.prototype.constructor = ParseError;
@@ -1377,7 +1375,7 @@ function RenderError(e, tpl) {
_.assign(this, e); _.assign(this, e);
this.originalError = e; this.originalError = e;
initLiquidError.call(this, e.message, tpl.token); initLiquidError.call(this, e, tpl.token);
} }
RenderError.prototype = Object.create(Error.prototype); RenderError.prototype = Object.create(Error.prototype);
RenderError.prototype.constructor = RenderError; RenderError.prototype.constructor = RenderError;
@@ -2035,41 +2033,41 @@ var candidatesRE = new RegExp(lexical.value.source, 'g');
var assert = require('../src/util/assert.js'); var assert = require('../src/util/assert.js');
module.exports = function (liquid) { module.exports = function (liquid) {
liquid.registerTag('cycle', { liquid.registerTag('cycle', {
parse: function parse(tagToken, remainTokens) { parse: function parse(tagToken, remainTokens) {
var match = groupRE.exec(tagToken.args); var match = groupRE.exec(tagToken.args);
assert(match, 'illegal tag: ' + tagToken.raw); assert(match, 'illegal tag: ' + tagToken.raw);
this.group = match[1] || ''; this.group = match[1] || '';
var candidates = match[2]; var candidates = match[2];
this.candidates = []; this.candidates = [];
while (match = candidatesRE.exec(candidates)) { while (match = candidatesRE.exec(candidates)) {
this.candidates.push(match[0]); this.candidates.push(match[0]);
} }
assert(this.candidates.length, 'empty candidates: ' + tagToken.raw);
},
assert(this.candidates.length, 'empty candidates: ' + tagToken.raw); render: function render(scope, hash) {
}, var group = Liquid.evalValue(this.group, scope);
var fingerprint = 'cycle:' + group + ':' + this.candidates.join(',');
render: function render(scope, hash) { var groups = scope.opts.groups = scope.opts.groups || {};
var group = Liquid.evalValue(this.group, scope); var idx = groups[fingerprint];
var fingerprint = 'cycle:' + group + ':' + this.candidates.join(',');
var register = scope.get('liquid');
var idx = register[fingerprint];
if (idx === undefined) { if (idx === undefined) {
idx = register[fingerprint] = 0; idx = groups[fingerprint] = 0;
} }
var candidate = this.candidates[idx]; var candidate = this.candidates[idx];
idx = (idx + 1) % this.candidates.length; idx = (idx + 1) % this.candidates.length;
register[fingerprint] = idx; groups[fingerprint] = idx;
return Promise.resolve(Liquid.evalValue(candidate, scope)); return Promise.resolve(Liquid.evalValue(candidate, scope));
} }
}); });
}; };
},{"..":2,"../src/util/assert.js":16,"any-promise":3}],28:[function(require,module,exports){ },{"..":2,"../src/util/assert.js":16,"any-promise":3}],28:[function(require,module,exports){
@@ -2280,19 +2278,21 @@ module.exports = function (liquid) {
render: function render(scope, hash) { render: function render(scope, hash) {
var filepath = Liquid.evalValue(this.value, scope); var filepath = Liquid.evalValue(this.value, scope);
var register = scope.get('liquid'); var originBlocks = scope.opts.blocks;
var originBlocks = register.blocks; var originBlockMode = scope.opts.blockMode;
register.blocks = {}; scope.opts.blocks = {};
scope.opts.blockMode = 'output';
if (this.with) { if (this.with) {
hash[filepath] = Liquid.evalValue(this.with, scope); hash[filepath] = Liquid.evalValue(this.with, scope);
} }
return liquid.getTemplate(filepath, register.root).then(function (templates) { return liquid.getTemplate(filepath, scope.opts.root).then(function (templates) {
scope.push(hash); scope.push(hash);
return liquid.renderer.renderTemplates(templates, scope); return liquid.renderer.renderTemplates(templates, scope);
}).then(function (html) { }).then(function (html) {
scope.pop(); scope.pop();
register.blocks = originBlocks; scope.opts.blocks = originBlocks;
scope.opts.blockMode = originBlockMode;
return html; return html;
}); });
} }
@@ -2350,6 +2350,12 @@ var Promise = require('any-promise');
var lexical = Liquid.lexical; var lexical = Liquid.lexical;
var assert = require('../src/util/assert.js'); var assert = require('../src/util/assert.js');
/*
* blockMode:
* * "store": store rendered html into blocks
* * "output": output rendered html
*/
module.exports = function (liquid) { module.exports = function (liquid) {
liquid.registerTag('layout', { liquid.registerTag('layout', {
parse: function parse(token, remainTokens) { parse: function parse(token, remainTokens) {
@@ -2361,17 +2367,18 @@ module.exports = function (liquid) {
}, },
render: function render(scope, hash) { render: function render(scope, hash) {
var layout = Liquid.evalValue(this.layout, scope); var layout = Liquid.evalValue(this.layout, scope);
var register = scope.get('liquid');
// render the remaining tokens immediately // render the remaining tokens immediately
return liquid.renderer.renderTemplates(this.tpls, scope) scope.opts.blockMode = 'store';
// now register.blocks contains rendered blocks return liquid.renderer.renderTemplates(this.tpls, scope).then(function (html) {
.then(function () { if (scope.opts.blocks[''] === undefined) {
return liquid.getTemplate(layout, register.root); scope.opts.blocks[''] = html;
}
return liquid.getTemplate(layout, scope.opts.root);
}).then(function (templates) { }).then(function (templates) {
// push the hash // push the hash
scope.push(hash); scope.push(hash);
// render the parent scope.opts.blockMode = 'output';
return liquid.renderer.renderTemplates(templates, scope); return liquid.renderer.renderTemplates(templates, scope);
}) })
// pop the hash // pop the hash
@@ -2387,7 +2394,7 @@ module.exports = function (liquid) {
var _this = this; var _this = this;
var match = /\w+/.exec(token.args); var match = /\w+/.exec(token.args);
this.block = match ? match[0] : 'anonymous'; this.block = match ? match[0] : '';
this.tpls = []; this.tpls = [];
var stream = liquid.parser.parseStream(remainTokens).on('tag:endblock', function () { var stream = liquid.parser.parseStream(remainTokens).on('tag:endblock', function () {
@@ -2402,19 +2409,19 @@ module.exports = function (liquid) {
render: function render(scope) { render: function render(scope) {
var _this2 = this; var _this2 = this;
var register = scope.get('liquid'); return Promise.resolve(scope.opts.blocks[this.block]).then(function (html) {
var html = register.blocks[this.block]; return html === undefined
// if not defined yet // render default block
if (html === undefined) { ? liquid.renderer.renderTemplates(_this2.tpls, scope)
return liquid.renderer.renderTemplates(this.tpls, scope).then(function (partial) { // use child-defined block
register.blocks[_this2.block] = partial; : html;
return partial; }).then(function (html) {
}); if (scope.opts.blockMode === 'store') {
} else { scope.opts.blocks[_this2.block] = html;
// if already defined by desendents return '';
register.blocks[this.block] = html; }
return Promise.resolve(html); return html;
} });
} }
}); });
}; };
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "liquidjs", "name": "liquidjs",
"version": "2.0.1", "version": "2.0.2",
"description": "A Liquid template engine for Node.js and browsers, with all shopify/liquid features.", "description": "A Liquid template engine for Node.js and browsers, with all shopify/liquid features.",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {