Initial commit
[yaffs-website] / node_modules / micromatch / lib / expand.js
1 /*!
2  * micromatch <https://github.com/jonschlinkert/micromatch>
3  *
4  * Copyright (c) 2014-2015, Jon Schlinkert.
5  * Licensed under the MIT License.
6  */
7
8 'use strict';
9
10 var utils = require('./utils');
11 var Glob = require('./glob');
12
13 /**
14  * Expose `expand`
15  */
16
17 module.exports = expand;
18
19 /**
20  * Expand a glob pattern to resolve braces and
21  * similar patterns before converting to regex.
22  *
23  * @param  {String|Array} `pattern`
24  * @param  {Array} `files`
25  * @param  {Options} `opts`
26  * @return {Array}
27  */
28
29 function expand(pattern, options) {
30   if (typeof pattern !== 'string') {
31     throw new TypeError('micromatch.expand(): argument should be a string.');
32   }
33
34   var glob = new Glob(pattern, options || {});
35   var opts = glob.options;
36
37   if (!utils.isGlob(pattern)) {
38     glob.pattern = glob.pattern.replace(/([\/.])/g, '\\$1');
39     return glob;
40   }
41
42   glob.pattern = glob.pattern.replace(/(\+)(?!\()/g, '\\$1');
43   glob.pattern = glob.pattern.split('$').join('\\$');
44
45   if (typeof opts.braces !== 'boolean' && typeof opts.nobraces !== 'boolean') {
46     opts.braces = true;
47   }
48
49   if (glob.pattern === '.*') {
50     return {
51       pattern: '\\.' + star,
52       tokens: tok,
53       options: opts
54     };
55   }
56
57   if (glob.pattern === '*') {
58     return {
59       pattern: oneStar(opts.dot),
60       tokens: tok,
61       options: opts
62     };
63   }
64
65   // parse the glob pattern into tokens
66   glob.parse();
67   var tok = glob.tokens;
68   tok.is.negated = opts.negated;
69
70   // dotfile handling
71   if ((opts.dotfiles === true || tok.is.dotfile) && opts.dot !== false) {
72     opts.dotfiles = true;
73     opts.dot = true;
74   }
75
76   if ((opts.dotdirs === true || tok.is.dotdir) && opts.dot !== false) {
77     opts.dotdirs = true;
78     opts.dot = true;
79   }
80
81   // check for braces with a dotfile pattern
82   if (/[{,]\./.test(glob.pattern)) {
83     opts.makeRe = false;
84     opts.dot = true;
85   }
86
87   if (opts.nonegate !== true) {
88     opts.negated = glob.negated;
89   }
90
91   // if the leading character is a dot or a slash, escape it
92   if (glob.pattern.charAt(0) === '.' && glob.pattern.charAt(1) !== '/') {
93     glob.pattern = '\\' + glob.pattern;
94   }
95
96   /**
97    * Extended globs
98    */
99
100   // expand braces, e.g `{1..5}`
101   glob.track('before braces');
102   if (tok.is.braces) {
103     glob.braces();
104   }
105   glob.track('after braces');
106
107   // expand extglobs, e.g `foo/!(a|b)`
108   glob.track('before extglob');
109   if (tok.is.extglob) {
110     glob.extglob();
111   }
112   glob.track('after extglob');
113
114   // expand brackets, e.g `[[:alpha:]]`
115   glob.track('before brackets');
116   if (tok.is.brackets) {
117     glob.brackets();
118   }
119   glob.track('after brackets');
120
121   // special patterns
122   glob._replace('[!', '[^');
123   glob._replace('(?', '(%~');
124   glob._replace(/\[\]/, '\\[\\]');
125   glob._replace('/[', '/' + (opts.dot ? dotfiles : nodot) + '[', true);
126   glob._replace('/?', '/' + (opts.dot ? dotfiles : nodot) + '[^/]', true);
127   glob._replace('/.', '/(?=.)\\.', true);
128
129   // windows drives
130   glob._replace(/^(\w):([\\\/]+?)/gi, '(?=.)$1:$2', true);
131
132   // negate slashes in exclusion ranges
133   if (glob.pattern.indexOf('[^') !== -1) {
134     glob.pattern = negateSlash(glob.pattern);
135   }
136
137   if (opts.globstar !== false && glob.pattern === '**') {
138     glob.pattern = globstar(opts.dot);
139
140   } else {
141     glob.pattern = balance(glob.pattern, '[', ']');
142     glob.escape(glob.pattern);
143
144     // if the pattern has `**`
145     if (tok.is.globstar) {
146       glob.pattern = collapse(glob.pattern, '/**');
147       glob.pattern = collapse(glob.pattern, '**/');
148       glob._replace('/**/', '(?:/' + globstar(opts.dot) + '/|/)', true);
149       glob._replace(/\*{2,}/g, '**');
150
151       // 'foo/*'
152       glob._replace(/(\w+)\*(?!\/)/g, '$1[^/]*?', true);
153       glob._replace(/\*\*\/\*(\w)/g, globstar(opts.dot) + '\\/' + (opts.dot ? dotfiles : nodot) + '[^/]*?$1', true);
154
155       if (opts.dot !== true) {
156         glob._replace(/\*\*\/(.)/g, '(?:**\\/|)$1');
157       }
158
159       // 'foo/**' or '{**,*}', but not 'foo**'
160       if (tok.path.dirname !== '' || /,\*\*|\*\*,/.test(glob.orig)) {
161         glob._replace('**', globstar(opts.dot), true);
162       }
163     }
164
165     // ends with /*
166     glob._replace(/\/\*$/, '\\/' + oneStar(opts.dot), true);
167     // ends with *, no slashes
168     glob._replace(/(?!\/)\*$/, star, true);
169     // has 'n*.' (partial wildcard w/ file extension)
170     glob._replace(/([^\/]+)\*/, '$1' + oneStar(true), true);
171     // has '*'
172     glob._replace('*', oneStar(opts.dot), true);
173     glob._replace('?.', '?\\.', true);
174     glob._replace('?:', '?:', true);
175
176     glob._replace(/\?+/g, function(match) {
177       var len = match.length;
178       if (len === 1) {
179         return qmark;
180       }
181       return qmark + '{' + len + '}';
182     });
183
184     // escape '.abc' => '\\.abc'
185     glob._replace(/\.([*\w]+)/g, '\\.$1');
186     // fix '[^\\\\/]'
187     glob._replace(/\[\^[\\\/]+\]/g, qmark);
188     // '///' => '\/'
189     glob._replace(/\/+/g, '\\/');
190     // '\\\\\\' => '\\'
191     glob._replace(/\\{2,}/g, '\\');
192   }
193
194   // unescape previously escaped patterns
195   glob.unescape(glob.pattern);
196   glob._replace('__UNESC_STAR__', '*');
197
198   // escape dots that follow qmarks
199   glob._replace('?.', '?\\.');
200
201   // remove unnecessary slashes in character classes
202   glob._replace('[^\\/]', qmark);
203
204   if (glob.pattern.length > 1) {
205     if (/^[\[?*]/.test(glob.pattern)) {
206       // only prepend the string if we don't want to match dotfiles
207       glob.pattern = (opts.dot ? dotfiles : nodot) + glob.pattern;
208     }
209   }
210
211   return glob;
212 }
213
214 /**
215  * Collapse repeated character sequences.
216  *
217  * ```js
218  * collapse('a/../../../b', '../');
219  * //=> 'a/../b'
220  * ```
221  *
222  * @param  {String} `str`
223  * @param  {String} `ch` Character sequence to collapse
224  * @return {String}
225  */
226
227 function collapse(str, ch) {
228   var res = str.split(ch);
229   var isFirst = res[0] === '';
230   var isLast = res[res.length - 1] === '';
231   res = res.filter(Boolean);
232   if (isFirst) res.unshift('');
233   if (isLast) res.push('');
234   return res.join(ch);
235 }
236
237 /**
238  * Negate slashes in exclusion ranges, per glob spec:
239  *
240  * ```js
241  * negateSlash('[^foo]');
242  * //=> '[^\\/foo]'
243  * ```
244  *
245  * @param  {String} `str` glob pattern
246  * @return {String}
247  */
248
249 function negateSlash(str) {
250   return str.replace(/\[\^([^\]]*?)\]/g, function(match, inner) {
251     if (inner.indexOf('/') === -1) {
252       inner = '\\/' + inner;
253     }
254     return '[^' + inner + ']';
255   });
256 }
257
258 /**
259  * Escape imbalanced braces/bracket. This is a very
260  * basic, naive implementation that only does enough
261  * to serve the purpose.
262  */
263
264 function balance(str, a, b) {
265   var aarr = str.split(a);
266   var alen = aarr.join('').length;
267   var blen = str.split(b).join('').length;
268
269   if (alen !== blen) {
270     str = aarr.join('\\' + a);
271     return str.split(b).join('\\' + b);
272   }
273   return str;
274 }
275
276 /**
277  * Special patterns to be converted to regex.
278  * Heuristics are used to simplify patterns
279  * and speed up processing.
280  */
281
282 /* eslint no-multi-spaces: 0 */
283 var qmark       = '[^/]';
284 var star        = qmark + '*?';
285 var nodot       = '(?!\\.)(?=.)';
286 var dotfileGlob = '(?:\\/|^)\\.{1,2}($|\\/)';
287 var dotfiles    = '(?!' + dotfileGlob + ')(?=.)';
288 var twoStarDot  = '(?:(?!' + dotfileGlob + ').)*?';
289
290 /**
291  * Create a regex for `*`.
292  *
293  * If `dot` is true, or the pattern does not begin with
294  * a leading star, then return the simpler regex.
295  */
296
297 function oneStar(dotfile) {
298   return dotfile ? '(?!' + dotfileGlob + ')(?=.)' + star : (nodot + star);
299 }
300
301 function globstar(dotfile) {
302   if (dotfile) { return twoStarDot; }
303   return '(?:(?!(?:\\/|^)\\.).)*?';
304 }