[6a3a178] | 1 | module.exports = function (glob, opts) {
|
---|
| 2 | if (typeof glob !== 'string') {
|
---|
| 3 | throw new TypeError('Expected a string');
|
---|
| 4 | }
|
---|
| 5 |
|
---|
| 6 | var str = String(glob);
|
---|
| 7 |
|
---|
| 8 | // The regexp we are building, as a string.
|
---|
| 9 | var reStr = "";
|
---|
| 10 |
|
---|
| 11 | // Whether we are matching so called "extended" globs (like bash) and should
|
---|
| 12 | // support single character matching, matching ranges of characters, group
|
---|
| 13 | // matching, etc.
|
---|
| 14 | var extended = opts ? !!opts.extended : false;
|
---|
| 15 |
|
---|
| 16 | // When globstar is _false_ (default), '/foo/*' is translated a regexp like
|
---|
| 17 | // '^\/foo\/.*$' which will match any string beginning with '/foo/'
|
---|
| 18 | // When globstar is _true_, '/foo/*' is translated to regexp like
|
---|
| 19 | // '^\/foo\/[^/]*$' which will match any string beginning with '/foo/' BUT
|
---|
| 20 | // which does not have a '/' to the right of it.
|
---|
| 21 | // E.g. with '/foo/*' these will match: '/foo/bar', '/foo/bar.txt' but
|
---|
| 22 | // these will not '/foo/bar/baz', '/foo/bar/baz.txt'
|
---|
| 23 | // Lastely, when globstar is _true_, '/foo/**' is equivelant to '/foo/*' when
|
---|
| 24 | // globstar is _false_
|
---|
| 25 | var globstar = opts ? !!opts.globstar : false;
|
---|
| 26 |
|
---|
| 27 | // If we are doing extended matching, this boolean is true when we are inside
|
---|
| 28 | // a group (eg {*.html,*.js}), and false otherwise.
|
---|
| 29 | var inGroup = false;
|
---|
| 30 |
|
---|
| 31 | // RegExp flags (eg "i" ) to pass in to RegExp constructor.
|
---|
| 32 | var flags = opts && typeof( opts.flags ) === "string" ? opts.flags : "";
|
---|
| 33 |
|
---|
| 34 | var c;
|
---|
| 35 | for (var i = 0, len = str.length; i < len; i++) {
|
---|
| 36 | c = str[i];
|
---|
| 37 |
|
---|
| 38 | switch (c) {
|
---|
| 39 | case "/":
|
---|
| 40 | case "$":
|
---|
| 41 | case "^":
|
---|
| 42 | case "+":
|
---|
| 43 | case ".":
|
---|
| 44 | case "(":
|
---|
| 45 | case ")":
|
---|
| 46 | case "=":
|
---|
| 47 | case "!":
|
---|
| 48 | case "|":
|
---|
| 49 | reStr += "\\" + c;
|
---|
| 50 | break;
|
---|
| 51 |
|
---|
| 52 | case "?":
|
---|
| 53 | if (extended) {
|
---|
| 54 | reStr += ".";
|
---|
| 55 | break;
|
---|
| 56 | }
|
---|
| 57 |
|
---|
| 58 | case "[":
|
---|
| 59 | case "]":
|
---|
| 60 | if (extended) {
|
---|
| 61 | reStr += c;
|
---|
| 62 | break;
|
---|
| 63 | }
|
---|
| 64 |
|
---|
| 65 | case "{":
|
---|
| 66 | if (extended) {
|
---|
| 67 | inGroup = true;
|
---|
| 68 | reStr += "(";
|
---|
| 69 | break;
|
---|
| 70 | }
|
---|
| 71 |
|
---|
| 72 | case "}":
|
---|
| 73 | if (extended) {
|
---|
| 74 | inGroup = false;
|
---|
| 75 | reStr += ")";
|
---|
| 76 | break;
|
---|
| 77 | }
|
---|
| 78 |
|
---|
| 79 | case ",":
|
---|
| 80 | if (inGroup) {
|
---|
| 81 | reStr += "|";
|
---|
| 82 | break;
|
---|
| 83 | }
|
---|
| 84 | reStr += "\\" + c;
|
---|
| 85 | break;
|
---|
| 86 |
|
---|
| 87 | case "*":
|
---|
| 88 | // Move over all consecutive "*"'s.
|
---|
| 89 | // Also store the previous and next characters
|
---|
| 90 | var prevChar = str[i - 1];
|
---|
| 91 | var starCount = 1;
|
---|
| 92 | while(str[i + 1] === "*") {
|
---|
| 93 | starCount++;
|
---|
| 94 | i++;
|
---|
| 95 | }
|
---|
| 96 | var nextChar = str[i + 1];
|
---|
| 97 |
|
---|
| 98 | if (!globstar) {
|
---|
| 99 | // globstar is disabled, so treat any number of "*" as one
|
---|
| 100 | reStr += ".*";
|
---|
| 101 | } else {
|
---|
| 102 | // globstar is enabled, so determine if this is a globstar segment
|
---|
| 103 | var isGlobstar = starCount > 1 // multiple "*"'s
|
---|
| 104 | && (prevChar === "/" || prevChar === undefined) // from the start of the segment
|
---|
| 105 | && (nextChar === "/" || nextChar === undefined) // to the end of the segment
|
---|
| 106 |
|
---|
| 107 | if (isGlobstar) {
|
---|
| 108 | // it's a globstar, so match zero or more path segments
|
---|
| 109 | reStr += "((?:[^/]*(?:\/|$))*)";
|
---|
| 110 | i++; // move over the "/"
|
---|
| 111 | } else {
|
---|
| 112 | // it's not a globstar, so only match one path segment
|
---|
| 113 | reStr += "([^/]*)";
|
---|
| 114 | }
|
---|
| 115 | }
|
---|
| 116 | break;
|
---|
| 117 |
|
---|
| 118 | default:
|
---|
| 119 | reStr += c;
|
---|
| 120 | }
|
---|
| 121 | }
|
---|
| 122 |
|
---|
| 123 | // When regexp 'g' flag is specified don't
|
---|
| 124 | // constrain the regular expression with ^ & $
|
---|
| 125 | if (!flags || !~flags.indexOf('g')) {
|
---|
| 126 | reStr = "^" + reStr + "$";
|
---|
| 127 | }
|
---|
| 128 |
|
---|
| 129 | return new RegExp(reStr, flags);
|
---|
| 130 | };
|
---|