function extglob(str, opts) {
  opts = opts || {};
  var o = {},
      i = 0; // fix common character reversals
  // '*!(.js)' => '*.!(js)'

  str = str.replace(/!\(([^\w*()])/g, '$1!('); // support file extension negation

  str = str.replace(/([*\/])\.!\([*]\)/g, function (m, ch) {
    if (ch === '/') {
      return escape('\\/[^.]+');
    }

    return escape('[^.]+');
  }); // create a unique key for caching by
  // combining the string and options

  var key = str + String(!!opts.regex) + String(!!opts.contains) + String(!!opts.escape);

  if (cache.hasOwnProperty(key)) {
    return cache[key];
  }

  if (!(re instanceof RegExp)) {
    re = regex();
  }

  opts.negate = false;
  var m;

  while (m = re.exec(str)) {
    var prefix = m[1];
    var inner = m[3];

    if (prefix === '!') {
      opts.negate = true;
    }

    var id = '__EXTGLOB_' + i++ + '__'; // use the prefix of the _last_ (outtermost) pattern

    o[id] = wrap(inner, prefix, opts.escape);
    str = str.split(m[0]).join(id);
  }

  var keys = Object.keys(o);
  var len = keys.length; // we have to loop again to allow us to convert
  // patterns in reverse order (starting with the
  // innermost/last pattern first)

  while (len--) {
    var prop = keys[len];
    str = str.split(prop).join(o[prop]);
  }

  var result = opts.regex ? toRegex(str, opts.contains, opts.negate) : str;
  result = result.split('.').join('\\.'); // cache the result and return it

  return cache[key] = result;
}
Convert the given extglob `string` to a regex-compatible
string.

```js
var extglob = require('extglob');
extglob('!(a?(b))');
//=> '(?!a(?:b)?)[^/]*?'
```

@param {String} `str` The string to convert.
@param {Object} `options`
  @option {Boolean} [options] `esc` If `false` special characters will not be escaped. Defaults to `true`.
  @option {Boolean} [options] `regex` If `true` a regular expression is returned instead of a string.
@return {String}
@api public