Skip to content

Commit abe7a04

Browse files
committed
Preserve commas that are not part of a brace expansion
1 parent 859e27c commit abe7a04

File tree

2 files changed

+45
-23
lines changed

2 files changed

+45
-23
lines changed

packages/ember-metal/lib/expand_properties.js

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { assert } from 'ember-metal/debug';
55
@submodule ember-metal
66
*/
77

8-
var SPLIT_REGEX = /\{|\}/;
98
var END_WITH_EACH_REGEX = /\.@each$/;
109

1110
/**
@@ -42,31 +41,46 @@ export default function expandProperties(pattern, callback) {
4241
pattern.indexOf(' ') === -1
4342
);
4443

45-
var parts = pattern.split(SPLIT_REGEX);
46-
var properties = [parts];
44+
let properties = [pattern];
4745

48-
for (let i = 0; i < parts.length; i++) {
49-
let part = parts[i];
50-
if (part.indexOf(',') >= 0) {
51-
properties = duplicateAndReplace(properties, part.split(','), i);
46+
// Iterating backward over the pattern makes dealing with indeces easier.
47+
let bookmark;
48+
let inside = false;
49+
for (let i = pattern.length; i > 0; --i) {
50+
let current = pattern[i - 1];
51+
52+
switch (current) {
53+
// Closing curly brace will be the first character of the brace expansion we encounter.
54+
// Bookmark its index so long as we're not already inside a brace expansion.
55+
case '}':
56+
if (!inside) {
57+
bookmark = i - 1;
58+
inside = true;
59+
}
60+
break;
61+
// Opening curly brace will be the last character of the brace expansion we encounter.
62+
// Apply the brace expansion so long as we've already seen a closing curly brace.
63+
case '{':
64+
if (inside) {
65+
let expansion = pattern.slice(i, bookmark).split(',');
66+
// Iterating backward allows us to push new properties w/out affecting our "cursor".
67+
for (let j = properties.length; j > 0; --j) {
68+
// Extract the unexpanded property from the array.
69+
let property = properties.splice(j - 1, 1)[0];
70+
// Iterate over the expansion, pushing the newly formed properties onto the array.
71+
for (let k = 0; k < expansion.length; ++k) {
72+
properties.push(property.slice(0, i - 1) +
73+
expansion[k] +
74+
property.slice(bookmark + 1));
75+
}
76+
}
77+
inside = false;
78+
}
79+
break;
5280
}
5381
}
5482

5583
for (let i = 0; i < properties.length; i++) {
56-
callback(properties[i].join('').replace(END_WITH_EACH_REGEX, '.[]'));
84+
callback(properties[i].replace(END_WITH_EACH_REGEX, '.[]'));
5785
}
5886
}
59-
60-
function duplicateAndReplace(properties, currentParts, index) {
61-
var all = [];
62-
63-
properties.forEach((property) => {
64-
currentParts.forEach((part) => {
65-
var current = property.slice(0);
66-
current[index] = part;
67-
all.push(current);
68-
});
69-
});
70-
71-
return all;
72-
}

packages/ember-metal/tests/expand_properties_test.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,14 @@ QUnit.test('A property with only brace expansions expands correctly', function()
7575
deepEqual(expected.sort(), foundProperties.sort());
7676
});
7777

78+
QUnit.test('A property with no braces does not expand', function() {
79+
expect(1);
80+
81+
expandProperties('a,b,c.d.e,f', addProperty);
82+
83+
deepEqual(foundProperties, ['a,b,c.d.e,f']);
84+
});
85+
7886
QUnit.test('A pattern must be a string', function() {
7987
expect(1);
8088

@@ -87,6 +95,6 @@ QUnit.test('A pattern must not contain a space', function() {
8795
expect(1);
8896

8997
expectAssertion(function() {
90-
expandProperties('a, b', addProperty);
98+
expandProperties('{a, b}', addProperty);
9199
}, /Brace expanded properties cannot contain spaces, e.g. "user.{firstName, lastName}" should be "user.{firstName,lastName}"/);
92100
});

0 commit comments

Comments
 (0)