tags: use scope.opts insteadof scope.get('liquid')

This commit is contained in:
harttle
2017-11-04 10:46:15 +08:00
parent 329aea6bd6
commit 4e132ca1c5
8 changed files with 79 additions and 73 deletions
+3 -3
View File
@@ -3,13 +3,13 @@ var app = express()
var Liquid = require('../..') var Liquid = require('../..')
var engine = Liquid({ var engine = Liquid({
root: __dirname, // for layouts and partials root: __dirname, // for layouts and partials
extname: '.liquid' extname: '.liquid'
}) })
app.engine('liquid', engine.express()) // register liquid engine app.engine('liquid', engine.express()) // register liquid engine
app.set('views', ['./partials', './views']) // specify the views directory app.set('views', ['./partials', './views']) // specify the views directory
app.set('view engine', 'liquid') // set to default app.set('view engine', 'liquid') // set to default
app.get('/', function (req, res) { app.get('/', function (req, res) {
var todos = ['fork and clone', 'make it better', 'make a pull request'] var todos = ['fork and clone', 'make it better', 'make a pull request']
+3 -4
View File
@@ -1,6 +1,5 @@
const app = require('./app.js'); const app = require('./app.js')
app.listen(3000, function () { app.listen(3000, function () {
console.log('Example app listening on port 3000!'); console.log('Example app listening on port 3000!')
}); })
+7 -9
View File
@@ -11,6 +11,9 @@ var Scope = {
return ctx return ctx
}, },
get: function (str) { get: function (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) {
@@ -168,19 +171,14 @@ 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
} }
+8 -6
View File
@@ -7,7 +7,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
@@ -15,12 +15,14 @@ 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
@@ -29,7 +31,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
@@ -42,7 +44,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
+34 -34
View File
@@ -1,44 +1,44 @@
const Liquid = require('..'); const Liquid = require('..')
const Promise = require('any-promise'); const Promise = require('any-promise')
const lexical = Liquid.lexical; const lexical = Liquid.lexical
const groupRE = new RegExp(`^(?:(${lexical.value.source})\\s*:\\s*)?(.*)$`); const groupRE = new RegExp(`^(?:(${lexical.value.source})\\s*:\\s*)?(.*)$`)
const candidatesRE = new RegExp(lexical.value.source, 'g'); const candidatesRE = new RegExp(lexical.value.source, 'g')
const assert = require('../src/util/assert.js'); const assert = require('../src/util/assert.js')
module.exports = function(liquid) { module.exports = function (liquid) {
liquid.registerTag('cycle', { liquid.registerTag('cycle', {
parse: function(tagToken, remainTokens) { parse: function (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 (scope, hash) {
}, var group = Liquid.evalValue(this.group, scope)
var fingerprint = `cycle:${group}:` + this.candidates.join(',')
render: function(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))
} }
}); })
}; }
+4 -5
View File
@@ -18,21 +18,20 @@ module.exports = function (liquid) {
render: function (scope, hash) { render: function (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 scope.opts.blocks = {}
register.blocks = {}
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) return liquid.getTemplate(filepath, scope.opts.root)
.then((templates) => { .then((templates) => {
scope.push(hash) scope.push(hash)
return liquid.renderer.renderTemplates(templates, scope) return liquid.renderer.renderTemplates(templates, scope)
}) })
.then((html) => { .then((html) => {
scope.pop() scope.pop()
register.blocks = originBlocks scope.opts.blocks = originBlocks
return html return html
}) })
} }
+4 -6
View File
@@ -14,12 +14,11 @@ module.exports = function (liquid) {
}, },
render: function (scope, hash) { render: function (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) return liquid.renderer.renderTemplates(this.tpls, scope)
// now register.blocks contains rendered blocks // now register.blocks contains rendered blocks
.then(() => liquid.getTemplate(layout, register.root)) .then(() => liquid.getTemplate(layout, scope.opts.root))
.then(templates => { .then(templates => {
// push the hash // push the hash
scope.push(hash) scope.push(hash)
@@ -49,18 +48,17 @@ module.exports = function (liquid) {
stream.start() stream.start()
}, },
render: function (scope) { render: function (scope) {
var register = scope.get('liquid') var html = scope.opts.blocks[this.block]
var html = register.blocks[this.block]
// if not defined yet // if not defined yet
if (html === undefined) { if (html === undefined) {
return liquid.renderer.renderTemplates(this.tpls, scope) return liquid.renderer.renderTemplates(this.tpls, scope)
.then((partial) => { .then((partial) => {
register.blocks[this.block] = partial scope.opts.blocks[this.block] = partial
return partial return partial
}) })
} else { } else {
// if already defined by desendents // if already defined by desendents
register.blocks[this.block] = html scope.opts.blocks[this.block] = html
return Promise.resolve(html) return Promise.resolve(html)
} }
} }
+16 -6
View File
@@ -24,13 +24,23 @@ describe('tags/layout', function () {
return expect(liquid.parseAndRender(src)).to return expect(liquid.parseAndRender(src)).to
.be.rejectedWith(/tag {%block%} not closed/) .be.rejectedWith(/tag {%block%} not closed/)
}) })
it('should handle anonymous block', function () { describe('anonymous block', function () {
mock({ it('should handle anonymous block', function () {
'/parent.html': 'X{%block%}{%endblock%}Y' mock({
'/parent.html': 'X{%block%}{%endblock%}Y'
})
var src = '{% layout "parent.html" %}{%block%}A{%endblock%}'
return expect(liquid.parseAndRender(src)).to
.eventually.equal('XAY')
})
it('should handle top level contents as anonymous block', function () {
mock({
'/parent.html': 'X{%block%}{%endblock%}Y'
})
var src = '{% layout "parent.html" %}A'
return expect(liquid.parseAndRender(src)).to
.eventually.equal('XAY')
}) })
var src = '{% layout "parent.html" %}{%block%}A{%endblock%}'
return expect(liquid.parseAndRender(src)).to
.eventually.equal('XAY')
}) })
it('should handle named blocks', function () { it('should handle named blocks', function () {
mock({ mock({