Projekt

Obecné

Profil

Stáhnout (23.3 KB) Statistiky
| Větev: | Revize:
1 3a515b92 cagy
'use strict';
2
3
/**
4
 * Module dependencies
5
 */
6
7
var util = require('util');
8
var braces = require('braces');
9
var toRegex = require('to-regex');
10
var extend = require('extend-shallow');
11
12
/**
13
 * Local dependencies
14
 */
15
16
var compilers = require('./lib/compilers');
17
var parsers = require('./lib/parsers');
18
var cache = require('./lib/cache');
19
var utils = require('./lib/utils');
20
var MAX_LENGTH = 1024 * 64;
21
22
/**
23
 * The main function takes a list of strings and one or more
24
 * glob patterns to use for matching.
25
 *
26
 * ```js
27
 * var mm = require('micromatch');
28
 * mm(list, patterns[, options]);
29
 *
30
 * console.log(mm(['a.js', 'a.txt'], ['*.js']));
31
 * //=> [ 'a.js' ]
32
 * ```
33
 * @param {Array} `list` A list of strings to match
34
 * @param {String|Array} `patterns` One or more glob patterns to use for matching.
35
 * @param {Object} `options` See available [options](#options) for changing how matches are performed
36
 * @return {Array} Returns an array of matches
37
 * @summary false
38
 * @api public
39
 */
40
41
function micromatch(list, patterns, options) {
42
  patterns = utils.arrayify(patterns);
43
  list = utils.arrayify(list);
44
45
  var len = patterns.length;
46
  if (list.length === 0 || len === 0) {
47
    return [];
48
  }
49
50
  if (len === 1) {
51
    return micromatch.match(list, patterns[0], options);
52
  }
53
54
  var omit = [];
55
  var keep = [];
56
  var idx = -1;
57
58
  while (++idx < len) {
59
    var pattern = patterns[idx];
60
61
    if (typeof pattern === 'string' && pattern.charCodeAt(0) === 33 /* ! */) {
62
      omit.push.apply(omit, micromatch.match(list, pattern.slice(1), options));
63
    } else {
64
      keep.push.apply(keep, micromatch.match(list, pattern, options));
65
    }
66
  }
67
68
  var matches = utils.diff(keep, omit);
69
  if (!options || options.nodupes !== false) {
70
    return utils.unique(matches);
71
  }
72
73
  return matches;
74
}
75
76
/**
77
 * Similar to the main function, but `pattern` must be a string.
78
 *
79
 * ```js
80
 * var mm = require('micromatch');
81
 * mm.match(list, pattern[, options]);
82
 *
83
 * console.log(mm.match(['a.a', 'a.aa', 'a.b', 'a.c'], '*.a'));
84
 * //=> ['a.a', 'a.aa']
85
 * ```
86
 * @param {Array} `list` Array of strings to match
87
 * @param {String} `pattern` Glob pattern to use for matching.
88
 * @param {Object} `options` See available [options](#options) for changing how matches are performed
89
 * @return {Array} Returns an array of matches
90
 * @api public
91
 */
92
93
micromatch.match = function(list, pattern, options) {
94
  if (Array.isArray(pattern)) {
95
    throw new TypeError('expected pattern to be a string');
96
  }
97
98
  var unixify = utils.unixify(options);
99
  var isMatch = memoize('match', pattern, options, micromatch.matcher);
100
  var matches = [];
101
102
  list = utils.arrayify(list);
103
  var len = list.length;
104
  var idx = -1;
105
106
  while (++idx < len) {
107
    var ele = list[idx];
108
    if (ele === pattern || isMatch(ele)) {
109
      matches.push(utils.value(ele, unixify, options));
110
    }
111
  }
112
113
  // if no options were passed, uniquify results and return
114
  if (typeof options === 'undefined') {
115
    return utils.unique(matches);
116
  }
117
118
  if (matches.length === 0) {
119
    if (options.failglob === true) {
120
      throw new Error('no matches found for "' + pattern + '"');
121
    }
122
    if (options.nonull === true || options.nullglob === true) {
123
      return [options.unescape ? utils.unescape(pattern) : pattern];
124
    }
125
  }
126
127
  // if `opts.ignore` was defined, diff ignored list
128
  if (options.ignore) {
129
    matches = micromatch.not(matches, options.ignore, options);
130
  }
131
132
  return options.nodupes !== false ? utils.unique(matches) : matches;
133
};
134
135
/**
136
 * Returns true if the specified `string` matches the given glob `pattern`.
137
 *
138
 * ```js
139
 * var mm = require('micromatch');
140
 * mm.isMatch(string, pattern[, options]);
141
 *
142
 * console.log(mm.isMatch('a.a', '*.a'));
143
 * //=> true
144
 * console.log(mm.isMatch('a.b', '*.a'));
145
 * //=> false
146
 * ```
147
 * @param {String} `string` String to match
148
 * @param {String} `pattern` Glob pattern to use for matching.
149
 * @param {Object} `options` See available [options](#options) for changing how matches are performed
150
 * @return {Boolean} Returns true if the string matches the glob pattern.
151
 * @api public
152
 */
153
154
micromatch.isMatch = function(str, pattern, options) {
155
  if (typeof str !== 'string') {
156
    throw new TypeError('expected a string: "' + util.inspect(str) + '"');
157
  }
158
159
  if (isEmptyString(str) || isEmptyString(pattern)) {
160
    return false;
161
  }
162
163
  var equals = utils.equalsPattern(options);
164
  if (equals(str)) {
165
    return true;
166
  }
167
168
  var isMatch = memoize('isMatch', pattern, options, micromatch.matcher);
169
  return isMatch(str);
170
};
171
172
/**
173
 * Returns true if some of the strings in the given `list` match any of the
174
 * given glob `patterns`.
175
 *
176
 * ```js
177
 * var mm = require('micromatch');
178
 * mm.some(list, patterns[, options]);
179
 *
180
 * console.log(mm.some(['foo.js', 'bar.js'], ['*.js', '!foo.js']));
181
 * // true
182
 * console.log(mm.some(['foo.js'], ['*.js', '!foo.js']));
183
 * // false
184
 * ```
185
 * @param  {String|Array} `list` The string or array of strings to test. Returns as soon as the first match is found.
186
 * @param {String|Array} `patterns` One or more glob patterns to use for matching.
187
 * @param {Object} `options` See available [options](#options) for changing how matches are performed
188
 * @return {Boolean} Returns true if any patterns match `str`
189
 * @api public
190
 */
191
192
micromatch.some = function(list, patterns, options) {
193
  if (typeof list === 'string') {
194
    list = [list];
195
  }
196
  for (var i = 0; i < list.length; i++) {
197
    if (micromatch(list[i], patterns, options).length === 1) {
198
      return true;
199
    }
200
  }
201
  return false;
202
};
203
204
/**
205
 * Returns true if every string in the given `list` matches
206
 * any of the given glob `patterns`.
207
 *
208
 * ```js
209
 * var mm = require('micromatch');
210
 * mm.every(list, patterns[, options]);
211
 *
212
 * console.log(mm.every('foo.js', ['foo.js']));
213
 * // true
214
 * console.log(mm.every(['foo.js', 'bar.js'], ['*.js']));
215
 * // true
216
 * console.log(mm.every(['foo.js', 'bar.js'], ['*.js', '!foo.js']));
217
 * // false
218
 * console.log(mm.every(['foo.js'], ['*.js', '!foo.js']));
219
 * // false
220
 * ```
221
 * @param  {String|Array} `list` The string or array of strings to test.
222
 * @param {String|Array} `patterns` One or more glob patterns to use for matching.
223
 * @param {Object} `options` See available [options](#options) for changing how matches are performed
224
 * @return {Boolean} Returns true if any patterns match `str`
225
 * @api public
226
 */
227
228
micromatch.every = function(list, patterns, options) {
229
  if (typeof list === 'string') {
230
    list = [list];
231
  }
232
  for (var i = 0; i < list.length; i++) {
233
    if (micromatch(list[i], patterns, options).length !== 1) {
234
      return false;
235
    }
236
  }
237
  return true;
238
};
239
240
/**
241
 * Returns true if **any** of the given glob `patterns`
242
 * match the specified `string`.
243
 *
244
 * ```js
245
 * var mm = require('micromatch');
246
 * mm.any(string, patterns[, options]);
247
 *
248
 * console.log(mm.any('a.a', ['b.*', '*.a']));
249
 * //=> true
250
 * console.log(mm.any('a.a', 'b.*'));
251
 * //=> false
252
 * ```
253
 * @param  {String|Array} `str` The string to test.
254
 * @param {String|Array} `patterns` One or more glob patterns to use for matching.
255
 * @param {Object} `options` See available [options](#options) for changing how matches are performed
256
 * @return {Boolean} Returns true if any patterns match `str`
257
 * @api public
258
 */
259
260
micromatch.any = function(str, patterns, options) {
261
  if (typeof str !== 'string') {
262
    throw new TypeError('expected a string: "' + util.inspect(str) + '"');
263
  }
264
265
  if (isEmptyString(str) || isEmptyString(patterns)) {
266
    return false;
267
  }
268
269
  if (typeof patterns === 'string') {
270
    patterns = [patterns];
271
  }
272
273
  for (var i = 0; i < patterns.length; i++) {
274
    if (micromatch.isMatch(str, patterns[i], options)) {
275
      return true;
276
    }
277
  }
278
  return false;
279
};
280
281
/**
282
 * Returns true if **all** of the given `patterns` match
283
 * the specified string.
284
 *
285
 * ```js
286
 * var mm = require('micromatch');
287
 * mm.all(string, patterns[, options]);
288
 *
289
 * console.log(mm.all('foo.js', ['foo.js']));
290
 * // true
291
 *
292
 * console.log(mm.all('foo.js', ['*.js', '!foo.js']));
293
 * // false
294
 *
295
 * console.log(mm.all('foo.js', ['*.js', 'foo.js']));
296
 * // true
297
 *
298
 * console.log(mm.all('foo.js', ['*.js', 'f*', '*o*', '*o.js']));
299
 * // true
300
 * ```
301
 * @param  {String|Array} `str` The string to test.
302
 * @param {String|Array} `patterns` One or more glob patterns to use for matching.
303
 * @param {Object} `options` See available [options](#options) for changing how matches are performed
304
 * @return {Boolean} Returns true if any patterns match `str`
305
 * @api public
306
 */
307
308
micromatch.all = function(str, patterns, options) {
309
  if (typeof str !== 'string') {
310
    throw new TypeError('expected a string: "' + util.inspect(str) + '"');
311
  }
312
  if (typeof patterns === 'string') {
313
    patterns = [patterns];
314
  }
315
  for (var i = 0; i < patterns.length; i++) {
316
    if (!micromatch.isMatch(str, patterns[i], options)) {
317
      return false;
318
    }
319
  }
320
  return true;
321
};
322
323
/**
324
 * Returns a list of strings that _**do not match any**_ of the given `patterns`.
325
 *
326
 * ```js
327
 * var mm = require('micromatch');
328
 * mm.not(list, patterns[, options]);
329
 *
330
 * console.log(mm.not(['a.a', 'b.b', 'c.c'], '*.a'));
331
 * //=> ['b.b', 'c.c']
332
 * ```
333
 * @param {Array} `list` Array of strings to match.
334
 * @param {String|Array} `patterns` One or more glob pattern to use for matching.
335
 * @param {Object} `options` See available [options](#options) for changing how matches are performed
336
 * @return {Array} Returns an array of strings that **do not match** the given patterns.
337
 * @api public
338
 */
339
340
micromatch.not = function(list, patterns, options) {
341
  var opts = extend({}, options);
342
  var ignore = opts.ignore;
343
  delete opts.ignore;
344
345
  var unixify = utils.unixify(opts);
346
  list = utils.arrayify(list).map(unixify);
347
348
  var matches = utils.diff(list, micromatch(list, patterns, opts));
349
  if (ignore) {
350
    matches = utils.diff(matches, micromatch(list, ignore));
351
  }
352
353
  return opts.nodupes !== false ? utils.unique(matches) : matches;
354
};
355
356
/**
357
 * Returns true if the given `string` contains the given pattern. Similar
358
 * to [.isMatch](#isMatch) but the pattern can match any part of the string.
359
 *
360
 * ```js
361
 * var mm = require('micromatch');
362
 * mm.contains(string, pattern[, options]);
363
 *
364
 * console.log(mm.contains('aa/bb/cc', '*b'));
365
 * //=> true
366
 * console.log(mm.contains('aa/bb/cc', '*d'));
367
 * //=> false
368
 * ```
369
 * @param {String} `str` The string to match.
370
 * @param {String|Array} `patterns` Glob pattern to use for matching.
371
 * @param {Object} `options` See available [options](#options) for changing how matches are performed
372
 * @return {Boolean} Returns true if the patter matches any part of `str`.
373
 * @api public
374
 */
375
376
micromatch.contains = function(str, patterns, options) {
377
  if (typeof str !== 'string') {
378
    throw new TypeError('expected a string: "' + util.inspect(str) + '"');
379
  }
380
381
  if (typeof patterns === 'string') {
382
    if (isEmptyString(str) || isEmptyString(patterns)) {
383
      return false;
384
    }
385
386
    var equals = utils.equalsPattern(patterns, options);
387
    if (equals(str)) {
388
      return true;
389
    }
390
    var contains = utils.containsPattern(patterns, options);
391
    if (contains(str)) {
392
      return true;
393
    }
394
  }
395
396
  var opts = extend({}, options, {contains: true});
397
  return micromatch.any(str, patterns, opts);
398
};
399
400
/**
401
 * Returns true if the given pattern and options should enable
402
 * the `matchBase` option.
403
 * @return {Boolean}
404
 * @api private
405
 */
406
407
micromatch.matchBase = function(pattern, options) {
408
  if (pattern && pattern.indexOf('/') !== -1 || !options) return false;
409
  return options.basename === true || options.matchBase === true;
410
};
411
412
/**
413
 * Filter the keys of the given object with the given `glob` pattern
414
 * and `options`. Does not attempt to match nested keys. If you need this feature,
415
 * use [glob-object][] instead.
416
 *
417
 * ```js
418
 * var mm = require('micromatch');
419
 * mm.matchKeys(object, patterns[, options]);
420
 *
421
 * var obj = { aa: 'a', ab: 'b', ac: 'c' };
422
 * console.log(mm.matchKeys(obj, '*b'));
423
 * //=> { ab: 'b' }
424
 * ```
425
 * @param {Object} `object` The object with keys to filter.
426
 * @param {String|Array} `patterns` One or more glob patterns to use for matching.
427
 * @param {Object} `options` See available [options](#options) for changing how matches are performed
428
 * @return {Object} Returns an object with only keys that match the given patterns.
429
 * @api public
430
 */
431
432
micromatch.matchKeys = function(obj, patterns, options) {
433
  if (!utils.isObject(obj)) {
434
    throw new TypeError('expected the first argument to be an object');
435
  }
436
  var keys = micromatch(Object.keys(obj), patterns, options);
437
  return utils.pick(obj, keys);
438
};
439
440
/**
441
 * Returns a memoized matcher function from the given glob `pattern` and `options`.
442
 * The returned function takes a string to match as its only argument and returns
443
 * true if the string is a match.
444
 *
445
 * ```js
446
 * var mm = require('micromatch');
447
 * mm.matcher(pattern[, options]);
448
 *
449
 * var isMatch = mm.matcher('*.!(*a)');
450
 * console.log(isMatch('a.a'));
451
 * //=> false
452
 * console.log(isMatch('a.b'));
453
 * //=> true
454
 * ```
455
 * @param {String} `pattern` Glob pattern
456
 * @param {Object} `options` See available [options](#options) for changing how matches are performed.
457
 * @return {Function} Returns a matcher function.
458
 * @api public
459
 */
460
461
micromatch.matcher = function matcher(pattern, options) {
462
  if (Array.isArray(pattern)) {
463
    return compose(pattern, options, matcher);
464
  }
465
466
  // if pattern is a regex
467
  if (pattern instanceof RegExp) {
468
    return test(pattern);
469
  }
470
471
  // if pattern is invalid
472
  if (!utils.isString(pattern)) {
473
    throw new TypeError('expected pattern to be an array, string or regex');
474
  }
475
476
  // if pattern is a non-glob string
477
  if (!utils.hasSpecialChars(pattern)) {
478
    if (options && options.nocase === true) {
479
      pattern = pattern.toLowerCase();
480
    }
481
    return utils.matchPath(pattern, options);
482
  }
483
484
  // if pattern is a glob string
485
  var re = micromatch.makeRe(pattern, options);
486
487
  // if `options.matchBase` or `options.basename` is defined
488
  if (micromatch.matchBase(pattern, options)) {
489
    return utils.matchBasename(re, options);
490
  }
491
492
  function test(regex) {
493
    var equals = utils.equalsPattern(options);
494
    var unixify = utils.unixify(options);
495
496
    return function(str) {
497
      if (equals(str)) {
498
        return true;
499
      }
500
501
      if (regex.test(unixify(str))) {
502
        return true;
503
      }
504
      return false;
505
    };
506
  }
507
508
  var fn = test(re);
509
  Object.defineProperty(fn, 'result', {
510
    configurable: true,
511
    enumerable: false,
512
    value: re.result
513
  });
514
  return fn;
515
};
516
517
/**
518
 * Returns an array of matches captured by `pattern` in `string, or `null` if the pattern did not match.
519
 *
520
 * ```js
521
 * var mm = require('micromatch');
522
 * mm.capture(pattern, string[, options]);
523
 *
524
 * console.log(mm.capture('test/*.js', 'test/foo.js'));
525
 * //=> ['foo']
526
 * console.log(mm.capture('test/*.js', 'foo/bar.css'));
527
 * //=> null
528
 * ```
529
 * @param {String} `pattern` Glob pattern to use for matching.
530
 * @param {String} `string` String to match
531
 * @param {Object} `options` See available [options](#options) for changing how matches are performed
532
 * @return {Boolean} Returns an array of captures if the string matches the glob pattern, otherwise `null`.
533
 * @api public
534
 */
535
536
micromatch.capture = function(pattern, str, options) {
537
  var re = micromatch.makeRe(pattern, extend({capture: true}, options));
538
  var unixify = utils.unixify(options);
539
540
  function match() {
541
    return function(string) {
542
      var match = re.exec(unixify(string));
543
      if (!match) {
544
        return null;
545
      }
546
547
      return match.slice(1);
548
    };
549
  }
550
551
  var capture = memoize('capture', pattern, options, match);
552
  return capture(str);
553
};
554
555
/**
556
 * Create a regular expression from the given glob `pattern`.
557
 *
558
 * ```js
559
 * var mm = require('micromatch');
560
 * mm.makeRe(pattern[, options]);
561
 *
562
 * console.log(mm.makeRe('*.js'));
563
 * //=> /^(?:(\.[\\\/])?(?!\.)(?=.)[^\/]*?\.js)$/
564
 * ```
565
 * @param {String} `pattern` A glob pattern to convert to regex.
566
 * @param {Object} `options` See available [options](#options) for changing how matches are performed.
567
 * @return {RegExp} Returns a regex created from the given pattern.
568
 * @api public
569
 */
570
571
micromatch.makeRe = function(pattern, options) {
572
  if (typeof pattern !== 'string') {
573
    throw new TypeError('expected pattern to be a string');
574
  }
575
576
  if (pattern.length > MAX_LENGTH) {
577
    throw new Error('expected pattern to be less than ' + MAX_LENGTH + ' characters');
578
  }
579
580
  function makeRe() {
581
    var result = micromatch.create(pattern, options);
582
    var ast_array = [];
583
    var output = result.map(function(obj) {
584
      obj.ast.state = obj.state;
585
      ast_array.push(obj.ast);
586
      return obj.output;
587
    });
588
589
    var regex = toRegex(output.join('|'), options);
590
    Object.defineProperty(regex, 'result', {
591
      configurable: true,
592
      enumerable: false,
593
      value: ast_array
594
    });
595
    return regex;
596
  }
597
598
  return memoize('makeRe', pattern, options, makeRe);
599
};
600
601
/**
602
 * Expand the given brace `pattern`.
603
 *
604
 * ```js
605
 * var mm = require('micromatch');
606
 * console.log(mm.braces('foo/{a,b}/bar'));
607
 * //=> ['foo/(a|b)/bar']
608
 *
609
 * console.log(mm.braces('foo/{a,b}/bar', {expand: true}));
610
 * //=> ['foo/(a|b)/bar']
611
 * ```
612
 * @param {String} `pattern` String with brace pattern to expand.
613
 * @param {Object} `options` Any [options](#options) to change how expansion is performed. See the [braces][] library for all available options.
614
 * @return {Array}
615
 * @api public
616
 */
617
618
micromatch.braces = function(pattern, options) {
619
  if (typeof pattern !== 'string' && !Array.isArray(pattern)) {
620
    throw new TypeError('expected pattern to be an array or string');
621
  }
622
623
  function expand() {
624
    if (options && options.nobrace === true || !/\{.*\}/.test(pattern)) {
625
      return utils.arrayify(pattern);
626
    }
627
    return braces(pattern, options);
628
  }
629
630
  return memoize('braces', pattern, options, expand);
631
};
632
633
/**
634
 * Proxy to the [micromatch.braces](#method), for parity with
635
 * minimatch.
636
 */
637
638
micromatch.braceExpand = function(pattern, options) {
639
  var opts = extend({}, options, {expand: true});
640
  return micromatch.braces(pattern, opts);
641
};
642
643
/**
644
 * Parses the given glob `pattern` and returns an array of abstract syntax
645
 * trees (ASTs), with the compiled `output` and optional source `map` on
646
 * each AST.
647
 *
648
 * ```js
649
 * var mm = require('micromatch');
650
 * mm.create(pattern[, options]);
651
 *
652
 * console.log(mm.create('abc/*.js'));
653
 * // [{ options: { source: 'string', sourcemap: true },
654
 * //   state: {},
655
 * //   compilers:
656
 * //    { ... },
657
 * //   output: '(\\.[\\\\\\/])?abc\\/(?!\\.)(?=.)[^\\/]*?\\.js',
658
 * //   ast:
659
 * //    { type: 'root',
660
 * //      errors: [],
661
 * //      nodes:
662
 * //       [ ... ],
663
 * //      dot: false,
664
 * //      input: 'abc/*.js' },
665
 * //   parsingErrors: [],
666
 * //   map:
667
 * //    { version: 3,
668
 * //      sources: [ 'string' ],
669
 * //      names: [],
670
 * //      mappings: 'AAAA,GAAG,EAAC,kBAAC,EAAC,EAAE',
671
 * //      sourcesContent: [ 'abc/*.js' ] },
672
 * //   position: { line: 1, column: 28 },
673
 * //   content: {},
674
 * //   files: {},
675
 * //   idx: 6 }]
676
 * ```
677
 * @param {String} `pattern` Glob pattern to parse and compile.
678
 * @param {Object} `options` Any [options](#options) to change how parsing and compiling is performed.
679
 * @return {Object} Returns an object with the parsed AST, compiled string and optional source map.
680
 * @api public
681
 */
682
683
micromatch.create = function(pattern, options) {
684
  return memoize('create', pattern, options, function() {
685
    function create(str, opts) {
686
      return micromatch.compile(micromatch.parse(str, opts), opts);
687
    }
688
689
    pattern = micromatch.braces(pattern, options);
690
    var len = pattern.length;
691
    var idx = -1;
692
    var res = [];
693
694
    while (++idx < len) {
695
      res.push(create(pattern[idx], options));
696
    }
697
    return res;
698
  });
699
};
700
701
/**
702
 * Parse the given `str` with the given `options`.
703
 *
704
 * ```js
705
 * var mm = require('micromatch');
706
 * mm.parse(pattern[, options]);
707
 *
708
 * var ast = mm.parse('a/{b,c}/d');
709
 * console.log(ast);
710
 * // { type: 'root',
711
 * //   errors: [],
712
 * //   input: 'a/{b,c}/d',
713
 * //   nodes:
714
 * //    [ { type: 'bos', val: '' },
715
 * //      { type: 'text', val: 'a/' },
716
 * //      { type: 'brace',
717
 * //        nodes:
718
 * //         [ { type: 'brace.open', val: '{' },
719
 * //           { type: 'text', val: 'b,c' },
720
 * //           { type: 'brace.close', val: '}' } ] },
721
 * //      { type: 'text', val: '/d' },
722
 * //      { type: 'eos', val: '' } ] }
723
 * ```
724
 * @param {String} `str`
725
 * @param {Object} `options`
726
 * @return {Object} Returns an AST
727
 * @api public
728
 */
729
730
micromatch.parse = function(pattern, options) {
731
  if (typeof pattern !== 'string') {
732
    throw new TypeError('expected a string');
733
  }
734
735
  function parse() {
736
    var snapdragon = utils.instantiate(null, options);
737
    parsers(snapdragon, options);
738
739
    var ast = snapdragon.parse(pattern, options);
740
    utils.define(ast, 'snapdragon', snapdragon);
741
    ast.input = pattern;
742
    return ast;
743
  }
744
745
  return memoize('parse', pattern, options, parse);
746
};
747
748
/**
749
 * Compile the given `ast` or string with the given `options`.
750
 *
751
 * ```js
752
 * var mm = require('micromatch');
753
 * mm.compile(ast[, options]);
754
 *
755
 * var ast = mm.parse('a/{b,c}/d');
756
 * console.log(mm.compile(ast));
757
 * // { options: { source: 'string' },
758
 * //   state: {},
759
 * //   compilers:
760
 * //    { eos: [Function],
761
 * //      noop: [Function],
762
 * //      bos: [Function],
763
 * //      brace: [Function],
764
 * //      'brace.open': [Function],
765
 * //      text: [Function],
766
 * //      'brace.close': [Function] },
767
 * //   output: [ 'a/(b|c)/d' ],
768
 * //   ast:
769
 * //    { ... },
770
 * //   parsingErrors: [] }
771
 * ```
772
 * @param {Object|String} `ast`
773
 * @param {Object} `options`
774
 * @return {Object} Returns an object that has an `output` property with the compiled string.
775
 * @api public
776
 */
777
778
micromatch.compile = function(ast, options) {
779
  if (typeof ast === 'string') {
780
    ast = micromatch.parse(ast, options);
781
  }
782
783
  return memoize('compile', ast.input, options, function() {
784
    var snapdragon = utils.instantiate(ast, options);
785
    compilers(snapdragon, options);
786
    return snapdragon.compile(ast, options);
787
  });
788
};
789
790
/**
791
 * Clear the regex cache.
792
 *
793
 * ```js
794
 * mm.clearCache();
795
 * ```
796
 * @api public
797
 */
798
799
micromatch.clearCache = function() {
800
  micromatch.cache.caches = {};
801
};
802
803
/**
804
 * Returns true if the given value is effectively an empty string
805
 */
806
807
function isEmptyString(val) {
808
  return String(val) === '' || String(val) === './';
809
}
810
811
/**
812
 * Compose a matcher function with the given patterns.
813
 * This allows matcher functions to be compiled once and
814
 * called multiple times.
815
 */
816
817
function compose(patterns, options, matcher) {
818
  var matchers;
819
820
  return memoize('compose', String(patterns), options, function() {
821
    return function(file) {
822
      // delay composition until it's invoked the first time,
823
      // after that it won't be called again
824
      if (!matchers) {
825
        matchers = [];
826
        for (var i = 0; i < patterns.length; i++) {
827
          matchers.push(matcher(patterns[i], options));
828
        }
829
      }
830
831
      var len = matchers.length;
832
      while (len--) {
833
        if (matchers[len](file) === true) {
834
          return true;
835
        }
836
      }
837
      return false;
838
    };
839
  });
840
}
841
842
/**
843
 * Memoize a generated regex or function. A unique key is generated
844
 * from the `type` (usually method name), the `pattern`, and
845
 * user-defined options.
846
 */
847
848
function memoize(type, pattern, options, fn) {
849
  var key = utils.createKey(type + '=' + pattern, options);
850
851
  if (options && options.cache === false) {
852
    return fn(pattern, options);
853
  }
854
855
  if (cache.has(type, key)) {
856
    return cache.get(type, key);
857
  }
858
859
  var val = fn(pattern, options);
860
  cache.set(type, key, val);
861
  return val;
862
}
863
864
/**
865
 * Expose compiler, parser and cache on `micromatch`
866
 */
867
868
micromatch.compilers = compilers;
869
micromatch.parsers = parsers;
870
micromatch.caches = cache.caches;
871
872
/**
873
 * Expose `micromatch`
874
 * @type {Function}
875
 */
876
877
module.exports = micromatch;