text: 'use strict';
  
  var brackets = require('expand-brackets');
  
  /**
   * Extglob compilers
   */
  
  module.exports = function (extglob) {
      function star() {
          if (typeof extglob.options.star === 'function') {
              return extglob.options.star.apply(this, arguments);
          }
          if (typeof extglob.options.star === 'string') {
              return extglob.options.star;
          }
          return '.*?';
      }
  
      /**
       * Use `expand-brackets` compilers
       */
  
      extglob.use(brackets.compilers);
      extglob.compiler
  
      /**
       * Escaped: "\\*"
       */
  
          .set('escape', function (node) {
              return this.emit(node.val, node);
          })
  
          /**
           * Dot: "."
           */
  
          .set('dot', function (node) {
              return this.emit('\\' + node.val, node);
          })
  
          /**
           * Question mark: "?"
           */
  
          .set('qmark', function (node) {
              var val = '[^\\\\/.]';
              var prev = this.prev();
  
              if (node.parsed.slice(-1) === '(') {
                  var ch = node.rest.charAt(0);
                  if (ch !== '!' && ch !== '=' && ch !== ':') {
                      return this.emit(val, node);
                  }
                  return this.emit(node.val, node);
              }
  
              if (prev.type === 'text' && prev.val) {
                  return this.emit(val, node);
              }
  
              if (node.val.length > 1) {
                  val += '{' + node.val.length + '}';
              }
              return this.emit(val, node);
          })
  
          /**
           * Plus: "+"
           */
  
          .set('plus', function (node) {
              var prev = node.parsed.slice(-1);
              if (prev === ']' || prev === ')') {
                  return this.emit(node.val, node);
              }
              var ch = this.output.slice(-1);
              if (!this.output || (/[?*+]/.test(ch) && node.parent.type !== 'bracket')) {
                  return this.emit('\\+', node);
              }
              if (/\w/.test(ch) && !node.inside) {
                  return this.emit('+\\+?', node);
              }
              return this.emit('+', node);
          })
  
          /**
           * Star: "*"
           */
  
          .set('star', function (node) {
              var prev = this.prev();
              var prefix = prev.type !== 'text' && prev.type !== 'escape'
                  ? '(?!\\.)'
                  : '';
  
              return this.emit(prefix + star.call(this, node), node);
          })
  
          /**
           * Parens
           */
  
          .set('paren', function (node) {
              return this.mapVisit(node.nodes);
          })
          .set('paren.open', function (node) {
              var capture = this.options.capture ? '(' : '';
  
              switch (node.parent.prefix) {
                  case '!':
                  case '^':
                      return this.emit(capture + '(?:(?!(?:', node);
                  case '*':
                  case '+':
                  case '?':
                  case '@':
                      return this.emit(capture + '(?:', node);
                  default: {
                      var val = node.val;
                      if (this.options.bash === true) {
                          val = '\\' + val;
                      } else if (!this.options.capture && val === '(' && node.parent.rest[0] !== '?') {
                          val += '?:';
                      }
  
                      return this.emit(val, node);
                  }
              }
          })
          .set('paren.close', function (node) {
              var capture = this.options.capture ? ')' : '';
  
              switch (node.prefix) {
                  case '!':
                  case '^':
                      var prefix = /^(\)|$)/.test(node.rest) ? '$' : '';
                      var str = star.call(this, node);
  
                      // if the extglob has a slash explicitly defined, we know the user wants
                      // to match slashes, so we need to ensure the "star" regex allows for it
                      if (node.parent.hasSlash && !this.options.star && this.options.slash !== false) {
                          str = '.*?';
                      }
  
                      return this.emit(prefix + ('))' + str + ')') + capture, node);
                  case '*':
                  case '+':
                  case '?':
                      return this.emit(')' + node.prefix + capture, node);
                  case '@':
                      return this.emit(')' + capture, node);
                  default: {
                      var val = (this.options.bash === true ? '\\' : '') + ')';
                      return this.emit(val, node);
                  }
              }
          })
  
          /**
           * Text
           */
  
          .set('text', function (node) {
              var val = node.val.replace(/[\[\]]/g, '\\$&');
              return this.emit(val, node);
          });
  };
  