fix read/write variable in parent's scope, fix #39

This commit is contained in:
harttle
2017-08-26 17:57:43 +08:00
parent 942a3224a1
commit 21af8c4d7a
5 changed files with 57 additions and 28 deletions
+12 -1
View File
@@ -20,7 +20,8 @@ var Scope = {
}
},
set: function (k, v) {
setPropertyByPath(this.scopes[this.scopes.length - 1], k, v)
var scope = this.findScopeFor(k)
setPropertyByPath(scope, k, v)
return this
},
push: function (ctx) {
@@ -30,6 +31,16 @@ var Scope = {
pop: function () {
return this.scopes.pop()
},
findScopeFor: function (key) {
var i = this.scopes.length - 1
while (i >= 0 && !(key in this.scopes[i])) {
i--
}
if (i < 0) {
i = this.scopes.length - 1
}
return this.scopes[i]
},
unshift: function (ctx) {
assert(ctx, `trying to push ${ctx} into scopes`)
return this.scopes.unshift(ctx)
+19 -21
View File
@@ -1,22 +1,20 @@
const Liquid = require('..');
const lexical = Liquid.lexical;
const Promise = require('any-promise');
const re = new RegExp(`(${lexical.identifier.source})\\s*=(.*)`);
const assert = require('../src/util/assert.js');
const Liquid = require('..')
const lexical = Liquid.lexical
const Promise = require('any-promise')
const re = new RegExp(`(${lexical.identifier.source})\\s*=(.*)`)
const assert = require('../src/util/assert.js')
module.exports = function(liquid) {
liquid.registerTag('assign', {
parse: function(token){
var match = token.args.match(re);
assert(match, `illegal token ${token.raw}`);
this.key = match[1];
this.value = match[2];
},
render: function(scope) {
scope.set(this.key, liquid.evalOutput(this.value, scope));
return Promise.resolve('');
}
});
};
module.exports = function (liquid) {
liquid.registerTag('assign', {
parse: function (token) {
var match = token.args.match(re)
assert(match, `illegal token ${token.raw}`)
this.key = match[1]
this.value = match[2]
},
render: function (scope) {
scope.set(this.key, liquid.evalOutput(this.value, scope))
return Promise.resolve('')
}
})
}
+3 -3
View File
@@ -74,9 +74,9 @@ module.exports = function (liquid) {
var html = ''
return mapSeries(contexts, (context) => {
scope.push(context)
return liquid.renderer
.renderTemplates(this.templates, scope)
return Promise.resolve()
.then(() => scope.push(context))
.then(() => liquid.renderer.renderTemplates(this.templates, scope))
.then(partial => (html += partial))
.catch(e => {
if (e instanceof RenderBreakError) {
+10 -3
View File
@@ -116,9 +116,16 @@ describe('scope', function () {
expect(scope.get('posts[category.diary[0]].name'), 'A Nice Day')
})
it('should create parents if needed', function () {
scope.set('foo.bar.coo', 'COO')
expect(scope.get('foo.bar.coo'), 'COO')
it('should create in parent scope if needed', function () {
scope.push({})
scope.set('bar.coo', 'COO')
expect(scope.get('bar.coo')).to.equal('COO')
})
it("should set parents' corresponding value", function () {
scope.push({})
scope.set('foo', 'bar')
scope.pop()
expect(scope.get('foo')).to.equal('bar')
})
})
describe('strict_variables', function () {
+13
View File
@@ -33,6 +33,19 @@ describe('tags/for', function () {
.to.eventually.equal('foo-coo-')
})
describe('scope', function () {
it('should read super scope', function () {
var src = '{%for a in (1..2)%}{{num}}{%endfor%}'
return expect(liquid.parseAndRender(src, {num: 1}))
.to.eventually.equal('11')
})
it('should write super scope', function () {
var src = '{%for a in (1..2)%}{{num}}{%assign num = 2%}{%endfor%}'
return expect(liquid.parseAndRender(src, {num: 1}))
.to.eventually.equal('12')
})
})
describe('illegal', function () {
it('should reject when for not closed', function () {
var src = '{%for c in alpha%}{{c}}'