1 | var concatMap = require('concat-map'); |
||
2 | var balanced = require('balanced-match'); |
||
3 | |||
4 | module.exports = expandTop; |
||
5 | |||
6 | var escSlash = '\0SLASH'+Math.random()+'\0'; |
||
7 | var escOpen = '\0OPEN'+Math.random()+'\0'; |
||
8 | var escClose = '\0CLOSE'+Math.random()+'\0'; |
||
9 | var escComma = '\0COMMA'+Math.random()+'\0'; |
||
10 | var escPeriod = '\0PERIOD'+Math.random()+'\0'; |
||
11 | |||
12 | function numeric(str) { |
||
13 | return parseInt(str, 10) == str |
||
14 | ? parseInt(str, 10) |
||
15 | : str.charCodeAt(0); |
||
16 | } |
||
17 | |||
18 | function escapeBraces(str) { |
||
19 | return str.split('\\\\').join(escSlash) |
||
20 | .split('\\{').join(escOpen) |
||
21 | .split('\\}').join(escClose) |
||
22 | .split('\\,').join(escComma) |
||
23 | .split('\\.').join(escPeriod); |
||
24 | } |
||
25 | |||
26 | function unescapeBraces(str) { |
||
27 | return str.split(escSlash).join('\\') |
||
28 | .split(escOpen).join('{') |
||
29 | .split(escClose).join('}') |
||
30 | .split(escComma).join(',') |
||
31 | .split(escPeriod).join('.'); |
||
32 | } |
||
33 | |||
34 | |||
35 | // Basically just str.split(","), but handling cases |
||
36 | // where we have nested braced sections, which should be |
||
37 | // treated as individual members, like {a,{b,c},d} |
||
38 | function parseCommaParts(str) { |
||
39 | if (!str) |
||
40 | return ['']; |
||
0 ignored issues
–
show
|
|||
41 | |||
42 | var parts = []; |
||
43 | var m = balanced('{', '}', str); |
||
44 | |||
45 | if (!m) |
||
46 | return str.split(','); |
||
0 ignored issues
–
show
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.
Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later. Consider: if (a > 0)
b = 42;
If you or someone else later decides to put another statement in, only the first statement will be executed. if (a > 0)
console.log("a > 0");
b = 42;
In this case the statement if (a > 0) {
console.log("a > 0");
b = 42;
}
ensures that the proper code will be executed conditionally no matter how many statements are added or removed. ![]() |
|||
47 | |||
48 | var pre = m.pre; |
||
49 | var body = m.body; |
||
50 | var post = m.post; |
||
51 | var p = pre.split(','); |
||
52 | |||
53 | p[p.length-1] += '{' + body + '}'; |
||
54 | var postParts = parseCommaParts(post); |
||
55 | if (post.length) { |
||
56 | p[p.length-1] += postParts.shift(); |
||
57 | p.push.apply(p, postParts); |
||
58 | } |
||
59 | |||
60 | parts.push.apply(parts, p); |
||
61 | |||
62 | return parts; |
||
63 | } |
||
64 | |||
65 | function expandTop(str) { |
||
66 | if (!str) |
||
67 | return []; |
||
0 ignored issues
–
show
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.
Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later. Consider: if (a > 0)
b = 42;
If you or someone else later decides to put another statement in, only the first statement will be executed. if (a > 0)
console.log("a > 0");
b = 42;
In this case the statement if (a > 0) {
console.log("a > 0");
b = 42;
}
ensures that the proper code will be executed conditionally no matter how many statements are added or removed. ![]() |
|||
68 | |||
69 | // I don't know why Bash 4.3 does this, but it does. |
||
70 | // Anything starting with {} will have the first two bytes preserved |
||
71 | // but *only* at the top level, so {},a}b will not expand to anything, |
||
72 | // but a{},b}c will be expanded to [a}c,abc]. |
||
73 | // One could argue that this is a bug in Bash, but since the goal of |
||
74 | // this module is to match Bash's rules, we escape a leading {} |
||
75 | if (str.substr(0, 2) === '{}') { |
||
76 | str = '\\{\\}' + str.substr(2); |
||
77 | } |
||
78 | |||
79 | return expand(escapeBraces(str), true).map(unescapeBraces); |
||
80 | } |
||
81 | |||
82 | function identity(e) { |
||
83 | return e; |
||
84 | } |
||
85 | |||
86 | function embrace(str) { |
||
87 | return '{' + str + '}'; |
||
88 | } |
||
89 | function isPadded(el) { |
||
90 | return /^-?0\d/.test(el); |
||
91 | } |
||
92 | |||
93 | function lte(i, y) { |
||
94 | return i <= y; |
||
95 | } |
||
96 | function gte(i, y) { |
||
97 | return i >= y; |
||
98 | } |
||
99 | |||
100 | function expand(str, isTop) { |
||
101 | var expansions = []; |
||
102 | |||
103 | var m = balanced('{', '}', str); |
||
104 | if (!m || /\$$/.test(m.pre)) return [str]; |
||
0 ignored issues
–
show
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.
Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later. Consider: if (a > 0)
b = 42;
If you or someone else later decides to put another statement in, only the first statement will be executed. if (a > 0)
console.log("a > 0");
b = 42;
In this case the statement if (a > 0) {
console.log("a > 0");
b = 42;
}
ensures that the proper code will be executed conditionally no matter how many statements are added or removed. ![]() |
|||
105 | |||
106 | var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body); |
||
107 | var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body); |
||
108 | var isSequence = isNumericSequence || isAlphaSequence; |
||
109 | var isOptions = m.body.indexOf(',') >= 0; |
||
110 | if (!isSequence && !isOptions) { |
||
111 | // {a},b} |
||
112 | if (m.post.match(/,.*\}/)) { |
||
113 | str = m.pre + '{' + m.body + escClose + m.post; |
||
114 | return expand(str); |
||
115 | } |
||
116 | return [str]; |
||
117 | } |
||
118 | |||
119 | var n; |
||
120 | if (isSequence) { |
||
121 | n = m.body.split(/\.\./); |
||
122 | } else { |
||
123 | n = parseCommaParts(m.body); |
||
124 | if (n.length === 1) { |
||
125 | // x{{a,b}}y ==> x{a}y x{b}y |
||
126 | n = expand(n[0], false).map(embrace); |
||
127 | if (n.length === 1) { |
||
128 | var post = m.post.length |
||
129 | ? expand(m.post, false) |
||
130 | : ['']; |
||
131 | return post.map(function(p) { |
||
132 | return m.pre + n[0] + p; |
||
133 | }); |
||
134 | } |
||
135 | } |
||
136 | } |
||
137 | |||
138 | // at this point, n is the parts, and we know it's not a comma set |
||
139 | // with a single entry. |
||
140 | |||
141 | // no need to expand pre, since it is guaranteed to be free of brace-sets |
||
142 | var pre = m.pre; |
||
143 | var post = m.post.length |
||
0 ignored issues
–
show
Comprehensibility
Naming
Best Practice
introduced
by
The variable
post already seems to be declared on line 128 . Consider using another variable name or omitting the var keyword.
This check looks for variables that are declared in multiple lines. There may be several reasons for this. In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs. If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared. ![]() |
|||
144 | ? expand(m.post, false) |
||
145 | : ['']; |
||
146 | |||
147 | var N; |
||
148 | |||
149 | if (isSequence) { |
||
150 | var x = numeric(n[0]); |
||
151 | var y = numeric(n[1]); |
||
152 | var width = Math.max(n[0].length, n[1].length) |
||
153 | var incr = n.length == 3 |
||
154 | ? Math.abs(numeric(n[2])) |
||
155 | : 1; |
||
156 | var test = lte; |
||
157 | var reverse = y < x; |
||
158 | if (reverse) { |
||
159 | incr *= -1; |
||
160 | test = gte; |
||
161 | } |
||
162 | var pad = n.some(isPadded); |
||
163 | |||
164 | N = []; |
||
165 | |||
166 | for (var i = x; test(i, y); i += incr) { |
||
167 | var c; |
||
168 | if (isAlphaSequence) { |
||
169 | c = String.fromCharCode(i); |
||
170 | if (c === '\\') |
||
171 | c = ''; |
||
0 ignored issues
–
show
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.
Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later. Consider: if (a > 0)
b = 42;
If you or someone else later decides to put another statement in, only the first statement will be executed. if (a > 0)
console.log("a > 0");
b = 42;
In this case the statement if (a > 0) {
console.log("a > 0");
b = 42;
}
ensures that the proper code will be executed conditionally no matter how many statements are added or removed. ![]() |
|||
172 | } else { |
||
173 | c = String(i); |
||
174 | if (pad) { |
||
175 | var need = width - c.length; |
||
176 | if (need > 0) { |
||
177 | var z = new Array(need + 1).join('0'); |
||
178 | if (i < 0) |
||
179 | c = '-' + z + c.slice(1); |
||
0 ignored issues
–
show
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.
Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later. Consider: if (a > 0)
b = 42;
If you or someone else later decides to put another statement in, only the first statement will be executed. if (a > 0)
console.log("a > 0");
b = 42;
In this case the statement if (a > 0) {
console.log("a > 0");
b = 42;
}
ensures that the proper code will be executed conditionally no matter how many statements are added or removed. ![]() |
|||
180 | else |
||
181 | c = z + c; |
||
182 | } |
||
183 | } |
||
184 | } |
||
185 | N.push(c); |
||
186 | } |
||
187 | } else { |
||
188 | N = concatMap(n, function(el) { return expand(el, false) }); |
||
189 | } |
||
190 | |||
191 | for (var j = 0; j < N.length; j++) { |
||
192 | for (var k = 0; k < post.length; k++) { |
||
193 | var expansion = pre + N[j] + post[k]; |
||
194 | if (!isTop || isSequence || expansion) |
||
195 | expansions.push(expansion); |
||
0 ignored issues
–
show
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.
Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later. Consider: if (a > 0)
b = 42;
If you or someone else later decides to put another statement in, only the first statement will be executed. if (a > 0)
console.log("a > 0");
b = 42;
In this case the statement if (a > 0) {
console.log("a > 0");
b = 42;
}
ensures that the proper code will be executed conditionally no matter how many statements are added or removed. ![]() |
|||
196 | } |
||
197 | } |
||
198 | |||
199 | return expansions; |
||
200 | } |
||
201 | |||
202 |
Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.
Consider:
If you or someone else later decides to put another statement in, only the first statement will be executed.
In this case the statement
b = 42
will always be executed, while the logging statement will be executed conditionally.ensures that the proper code will be executed conditionally no matter how many statements are added or removed.