Security update for permissions_by_term
[yaffs-website] / node_modules / brace-expansion / index.js
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 [''];
41
42   var parts = [];
43   var m = balanced('{', '}', str);
44
45   if (!m)
46     return str.split(',');
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 [];
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];
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 = /^(.*,)+(.+)?$/.test(m.body);
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
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 = '';
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);
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);
196     }
197   }
198
199   return expansions;
200 }
201