Skip to content
This repository has been archived by the owner on Apr 11, 2018. It is now read-only.

Allow set tag to use bracket notation for object properties #388

Merged
merged 1 commit into from
Jan 10, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 51 additions & 8 deletions lib/tags/set.js
Original file line number Diff line number Diff line change
Expand Up @@ -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. <code data-language="js">=, +=, *=, /=, -=</code>
* @param {*} value Valid variable output.
Expand All @@ -23,25 +30,61 @@ 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;
}

return true;
});

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);
});

Expand Down
21 changes: 19 additions & 2 deletions tests/tags/set.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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' },
Expand All @@ -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);
Expand Down