| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 | module.exports = function (glob, opts) {  if (typeof glob !== 'string') {    throw new TypeError('Expected a string');  }  var str = String(glob);  // The regexp we are building, as a string.  var reStr = "";  // Whether we are matching so called "extended" globs (like bash) and should  // support single character matching, matching ranges of characters, group  // matching, etc.  var extended = opts ? !!opts.extended : false;  // When globstar is _false_ (default), '/foo/*' is translated a regexp like  // '^\/foo\/.*$' which will match any string beginning with '/foo/'  // When globstar is _true_, '/foo/*' is translated to regexp like  // '^\/foo\/[^/]*$' which will match any string beginning with '/foo/' BUT  // which does not have a '/' to the right of it.  // E.g. with '/foo/*' these will match: '/foo/bar', '/foo/bar.txt' but  // these will not '/foo/bar/baz', '/foo/bar/baz.txt'  // Lastely, when globstar is _true_, '/foo/**' is equivelant to '/foo/*' when  // globstar is _false_  var globstar = opts ? !!opts.globstar : false;  // If we are doing extended matching, this boolean is true when we are inside  // a group (eg {*.html,*.js}), and false otherwise.  var inGroup = false;  // RegExp flags (eg "i" ) to pass in to RegExp constructor.  var flags = opts && typeof( opts.flags ) === "string" ? opts.flags : "";  var c;  for (var i = 0, len = str.length; i < len; i++) {    c = str[i];    switch (c) {    case "\\":    case "/":    case "$":    case "^":    case "+":    case ".":    case "(":    case ")":    case "=":    case "!":    case "|":      reStr += "\\" + c;      break;    case "?":      if (extended) {        reStr += ".";	    break;      }    case "[":    case "]":      if (extended) {        reStr += c;	    break;      }    case "{":      if (extended) {        inGroup = true;	    reStr += "(";	    break;      }    case "}":      if (extended) {        inGroup = false;	    reStr += ")";	    break;      }    case ",":      if (inGroup) {        reStr += "|";	    break;      }      reStr += "\\" + c;      break;    case "*":      // Move over all consecutive "*"'s.      // Also store the previous and next characters      var prevChar = str[i - 1];      var starCount = 1;      while(str[i + 1] === "*") {        starCount++;        i++;      }      var nextChar = str[i + 1];      if (!globstar) {        // globstar is disabled, so treat any number of "*" as one        reStr += ".*";      } else {        // globstar is enabled, so determine if this is a globstar segment        var isGlobstar = starCount > 1                      // multiple "*"'s          && (prevChar === "/" || prevChar === undefined)   // from the start of the segment          && (nextChar === "/" || nextChar === undefined)   // to the end of the segment        if (isGlobstar) {          // it's a globstar, so match zero or more path segments          reStr += "(?:[^/]*(?:\/|$))*";          i++; // move over the "/"        } else {          // it's not a globstar, so only match one path segment          reStr += "[^/]*";        }      }      break;    default:      reStr += c;    }  }  // When regexp 'g' flag is specified don't  // constrain the regular expression with ^ & $  if (!flags || !~flags.indexOf('g')) {    reStr = "^" + reStr + "$";  }  return new RegExp(reStr, flags);};
 |