diff --git a/lib/tags/set.js b/lib/tags/set.js index 7b5ac8b1..539990b5 100644 --- a/lib/tags/set.js +++ b/lib/tags/set.js @@ -14,6 +14,13 @@ * {% set bar += index|default(3) %} * // => 3 * + * @example + * // foods = {}; + * // food = 'chili'; + * {% set foods[food] = "con queso" %} + * {{ foods.chili }} + * // => con queso + * * @param {literal} varname The variable name to assign the value to. * @param {literal} assignement Any valid JavaScript assignement. =, +=, *=, /=, -= * @param {*} value Valid variable output. @@ -23,14 +30,46 @@ exports.compile = function (compiler, args) { }; exports.parse = function (str, line, parser, types) { - var nameSet; + var nameSet = '', + propertyName = ''; + parser.on(types.VAR, function (token) { - if (!this.out.length) { - nameSet = token.match; - this.out.push( - // Prevent the set from spilling into global scope - '_ctx.' + nameSet - ); + if (propertyName) { + // Tell the parser where to find the variable + propertyName += '_ctx.' + token.match; + return; + } + + if (!parser.out.length) { + nameSet += token.match; + return; + } + + return true; + }); + + parser.on(types.BRACKETOPEN, function (token) { + if (!propertyName && !this.out.length) { + propertyName = token.match; + return; + } + + return true; + }); + + parser.on(types.STRING, function (token) { + if (propertyName && !this.out.length) { + propertyName += token.match; + return; + } + + return true; + }); + + parser.on(types.BRACKETCLOSE, function (token) { + if (propertyName && !this.out.length) { + nameSet += propertyName + token.match; + propertyName = ''; return; } @@ -38,10 +77,14 @@ exports.parse = function (str, line, parser, types) { }); parser.on(types.ASSIGNMENT, function (token) { - if (this.out.length !== 1 || !nameSet) { + if (this.out.length || !nameSet) { throw new Error('Unexpected assignment "' + token.match + '" on line ' + line + '.'); } + this.out.push( + // Prevent the set from spilling into global scope + '_ctx.' + nameSet + ); this.out.push(token.match); }); diff --git a/tests/tags/set.test.js b/tests/tags/set.test.js index f94ac9c0..b1d656c6 100644 --- a/tests/tags/set.test.js +++ b/tests/tags/set.test.js @@ -3,7 +3,17 @@ var swig = require('../../lib/swig'), _ = require('lodash'), Swig = swig.Swig; -var cases = [ +var leftCases = [ + 'foo[bar]', + 'foo[\'bar\']', + 'foo["bar"]', + 'foo[\'bar.baz\']', + 'foo["bar.baz"]', + 'foo[\'bar=baz\']', + 'foo["bar=baz"]' +]; + +var rightCases = [ { code: '= 1', result: '1' }, { code: '= "burritos"', result: 'burritos' }, { code: '= 1 + 3', result: '4' }, @@ -18,7 +28,14 @@ var cases = [ describe('Tag: set', function () { - _.each(cases, function (c) { + _.each(leftCases, function (c) { + var s = '{% set bar = "bar" %}{% set ' + c + ' = "con queso" %}'; + it(s, function () { + expect(swig.render(s + '{{ ' + c + ' }}', { locals: { foo: {} }})).to.equal('con queso'); + }); + }); + + _.each(rightCases, function (c) { var s = '{% set foo ' + c.code + ' %}'; it(s, function () { expect(swig.render(s + '{{ foo }}', { locals: { foo: 1 }})).to.equal(c.result);