Initial commit
[yaffs-website] / node_modules / extglob / index.js
1 /*!
2  * extglob <https://github.com/jonschlinkert/extglob>
3  *
4  * Copyright (c) 2015, Jon Schlinkert.
5  * Licensed under the MIT License.
6  */
7
8 'use strict';
9
10 /**
11  * Module dependencies
12  */
13
14 var isExtglob = require('is-extglob');
15 var re, cache = {};
16
17 /**
18  * Expose `extglob`
19  */
20
21 module.exports = extglob;
22
23 /**
24  * Convert the given extglob `string` to a regex-compatible
25  * string.
26  *
27  * ```js
28  * var extglob = require('extglob');
29  * extglob('!(a?(b))');
30  * //=> '(?!a(?:b)?)[^/]*?'
31  * ```
32  *
33  * @param {String} `str` The string to convert.
34  * @param {Object} `options`
35  *   @option {Boolean} [options] `esc` If `false` special characters will not be escaped. Defaults to `true`.
36  *   @option {Boolean} [options] `regex` If `true` a regular expression is returned instead of a string.
37  * @return {String}
38  * @api public
39  */
40
41
42 function extglob(str, opts) {
43   opts = opts || {};
44   var o = {}, i = 0;
45
46   // fix common character reversals
47   // '*!(.js)' => '*.!(js)'
48   str = str.replace(/!\(([^\w*()])/g, '$1!(');
49
50   // support file extension negation
51   str = str.replace(/([*\/])\.!\([*]\)/g, function (m, ch) {
52     if (ch === '/') {
53       return escape('\\/[^.]+');
54     }
55     return escape('[^.]+');
56   });
57
58   // create a unique key for caching by
59   // combining the string and options
60   var key = str
61     + String(!!opts.regex)
62     + String(!!opts.contains)
63     + String(!!opts.escape);
64
65   if (cache.hasOwnProperty(key)) {
66     return cache[key];
67   }
68
69   if (!(re instanceof RegExp)) {
70     re = regex();
71   }
72
73   opts.negate = false;
74   var m;
75
76   while (m = re.exec(str)) {
77     var prefix = m[1];
78     var inner = m[3];
79     if (prefix === '!') {
80       opts.negate = true;
81     }
82
83     var id = '__EXTGLOB_' + (i++) + '__';
84     // use the prefix of the _last_ (outtermost) pattern
85     o[id] = wrap(inner, prefix, opts.escape);
86     str = str.split(m[0]).join(id);
87   }
88
89   var keys = Object.keys(o);
90   var len = keys.length;
91
92   // we have to loop again to allow us to convert
93   // patterns in reverse order (starting with the
94   // innermost/last pattern first)
95   while (len--) {
96     var prop = keys[len];
97     str = str.split(prop).join(o[prop]);
98   }
99
100   var result = opts.regex
101     ? toRegex(str, opts.contains, opts.negate)
102     : str;
103
104   result = result.split('.').join('\\.');
105
106   // cache the result and return it
107   return (cache[key] = result);
108 }
109
110 /**
111  * Convert `string` to a regex string.
112  *
113  * @param  {String} `str`
114  * @param  {String} `prefix` Character that determines how to wrap the string.
115  * @param  {Boolean} `esc` If `false` special characters will not be escaped. Defaults to `true`.
116  * @return {String}
117  */
118
119 function wrap(inner, prefix, esc) {
120   if (esc) inner = escape(inner);
121
122   switch (prefix) {
123     case '!':
124       return '(?!' + inner + ')[^/]' + (esc ? '%%%~' : '*?');
125     case '@':
126       return '(?:' + inner + ')';
127     case '+':
128       return '(?:' + inner + ')+';
129     case '*':
130       return '(?:' + inner + ')' + (esc ? '%%' : '*')
131     case '?':
132       return '(?:' + inner + '|)';
133     default:
134       return inner;
135   }
136 }
137
138 function escape(str) {
139   str = str.split('*').join('[^/]%%%~');
140   str = str.split('.').join('\\.');
141   return str;
142 }
143
144 /**
145  * extglob regex.
146  */
147
148 function regex() {
149   return /(\\?[@?!+*$]\\?)(\(([^()]*?)\))/;
150 }
151
152 /**
153  * Negation regex
154  */
155
156 function negate(str) {
157   return '(?!^' + str + ').*$';
158 }
159
160 /**
161  * Create the regex to do the matching. If
162  * the leading character in the `pattern` is `!`
163  * a negation regex is returned.
164  *
165  * @param {String} `pattern`
166  * @param {Boolean} `contains` Allow loose matching.
167  * @param {Boolean} `isNegated` True if the pattern is a negation pattern.
168  */
169
170 function toRegex(pattern, contains, isNegated) {
171   var prefix = contains ? '^' : '';
172   var after = contains ? '$' : '';
173   pattern = ('(?:' + pattern + ')' + after);
174   if (isNegated) {
175     pattern = prefix + negate(pattern);
176   }
177   return new RegExp(prefix + pattern);
178 }