| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386 | 'use strict';var regexNot = require('regex-not');var toRegex = require('to-regex');/** * Characters to use in negation regex (we want to "not" match * characters that are matched by other parsers) */var cached;var NOT_REGEX = '[\\[!*+?$^"\'.\\\\/]+';var not = createTextRegex(NOT_REGEX);/** * Nanomatch parsers */module.exports = function(nanomatch, options) {  var parser = nanomatch.parser;  var opts = parser.options;  parser.state = {    slashes: 0,    paths: []  };  parser.ast.state = parser.state;  parser    /**     * Beginning-of-string     */    .capture('prefix', function() {      if (this.parsed) return;      var m = this.match(/^\.[\\/]/);      if (!m) return;      this.state.strictOpen = !!this.options.strictOpen;      this.state.addPrefix = true;    })    /**     * Escape: "\\."     */    .capture('escape', function() {      if (this.isInside('bracket')) return;      var pos = this.position();      var m = this.match(/^(?:\\(.)|([$^]))/);      if (!m) return;      return pos({        type: 'escape',        val: m[2] || m[1]      });    })    /**     * Quoted strings     */    .capture('quoted', function() {      var pos = this.position();      var m = this.match(/^["']/);      if (!m) return;      var quote = m[0];      if (this.input.indexOf(quote) === -1) {        return pos({          type: 'escape',          val: quote        });      }      var tok = advanceTo(this.input, quote);      this.consume(tok.len);      return pos({        type: 'quoted',        val: tok.esc      });    })    /**     * Negations: "!"     */    .capture('not', function() {      var parsed = this.parsed;      var pos = this.position();      var m = this.match(this.notRegex || /^!+/);      if (!m) return;      var val = m[0];      var isNegated = (val.length % 2) === 1;      if (parsed === '' && !isNegated) {        val = '';      }      // if nothing has been parsed, we know `!` is at the start,      // so we need to wrap the result in a negation regex      if (parsed === '' && isNegated && this.options.nonegate !== true) {        this.bos.val = '(?!^(?:';        this.append = ')$).*';        val = '';      }      return pos({        type: 'not',        val: val      });    })    /**     * Dot: "."     */    .capture('dot', function() {      var parsed = this.parsed;      var pos = this.position();      var m = this.match(/^\.+/);      if (!m) return;      var val = m[0];      this.state.dot = val === '.' && (parsed === '' || parsed.slice(-1) === '/');      return pos({        type: 'dot',        dotfiles: this.state.dot,        val: val      });    })    /**     * Plus: "+"     */    .capture('plus', /^\+(?!\()/)    /**     * Question mark: "?"     */    .capture('qmark', function() {      var parsed = this.parsed;      var pos = this.position();      var m = this.match(/^\?+(?!\()/);      if (!m) return;      this.state.metachar = true;      this.state.qmark = true;      return pos({        type: 'qmark',        parsed: parsed,        val: m[0]      });    })    /**     * Globstar: "**"     */    .capture('globstar', function() {      var parsed = this.parsed;      var pos = this.position();      var m = this.match(/^\*{2}(?![*(])(?=[,)/]|$)/);      if (!m) return;      var type = opts.noglobstar !== true ? 'globstar' : 'star';      var node = pos({type: type, parsed: parsed});      this.state.metachar = true;      while (this.input.slice(0, 4) === '/**/') {        this.input = this.input.slice(3);      }      node.isInside = {        brace: this.isInside('brace'),        paren: this.isInside('paren')      };      if (type === 'globstar') {        this.state.globstar = true;        node.val = '**';      } else {        this.state.star = true;        node.val = '*';      }      return node;    })    /**     * Star: "*"     */    .capture('star', function() {      var pos = this.position();      var starRe = /^(?:\*(?![*(])|[*]{3,}(?!\()|[*]{2}(?![(/]|$)|\*(?=\*\())/;      var m = this.match(starRe);      if (!m) return;      this.state.metachar = true;      this.state.star = true;      return pos({        type: 'star',        val: m[0]      });    })    /**     * Slash: "/"     */    .capture('slash', function() {      var pos = this.position();      var m = this.match(/^\//);      if (!m) return;      this.state.slashes++;      return pos({        type: 'slash',        val: m[0]      });    })    /**     * Backslash: "\\"     */    .capture('backslash', function() {      var pos = this.position();      var m = this.match(/^\\(?![*+?(){}[\]'"])/);      if (!m) return;      var val = m[0];      if (this.isInside('bracket')) {        val = '\\';      } else if (val.length > 1) {        val = '\\\\';      }      return pos({        type: 'backslash',        val: val      });    })    /**     * Square: "[.]"     */    .capture('square', function() {      if (this.isInside('bracket')) return;      var pos = this.position();      var m = this.match(/^\[([^!^\\])\]/);      if (!m) return;      return pos({        type: 'square',        val: m[1]      });    })    /**     * Brackets: "[...]" (basic, this can be overridden by other parsers)     */    .capture('bracket', function() {      var pos = this.position();      var m = this.match(/^(?:\[([!^]?)([^\]]+|\]-)(\]|[^*+?]+)|\[)/);      if (!m) return;      var val = m[0];      var negated = m[1] ? '^' : '';      var inner = (m[2] || '').replace(/\\\\+/, '\\\\');      var close = m[3] || '';      if (m[2] && inner.length < m[2].length) {        val = val.replace(/\\\\+/, '\\\\');      }      var esc = this.input.slice(0, 2);      if (inner === '' && esc === '\\]') {        inner += esc;        this.consume(2);        var str = this.input;        var idx = -1;        var ch;        while ((ch = str[++idx])) {          this.consume(1);          if (ch === ']') {            close = ch;            break;          }          inner += ch;        }      }      return pos({        type: 'bracket',        val: val,        escaped: close !== ']',        negated: negated,        inner: inner,        close: close      });    })    /**     * Text     */    .capture('text', function() {      if (this.isInside('bracket')) return;      var pos = this.position();      var m = this.match(not);      if (!m || !m[0]) return;      return pos({        type: 'text',        val: m[0]      });    });  /**   * Allow custom parsers to be passed on options   */  if (options && typeof options.parsers === 'function') {    options.parsers(nanomatch.parser);  }};/** * Advance to the next non-escaped character */function advanceTo(input, endChar) {  var ch = input.charAt(0);  var tok = { len: 1, val: '', esc: '' };  var idx = 0;  function advance() {    if (ch !== '\\') {      tok.esc += '\\' + ch;      tok.val += ch;    }    ch = input.charAt(++idx);    tok.len++;    if (ch === '\\') {      advance();      advance();    }  }  while (ch && ch !== endChar) {    advance();  }  return tok;}/** * Create text regex */function createTextRegex(pattern) {  if (cached) return cached;  var opts = {contains: true, strictClose: false};  var not = regexNot.create(pattern, opts);  var re = toRegex('^(?:[*]\\((?=.)|' + not + ')', opts);  return (cached = re);}/** * Expose negation string */module.exports.not = NOT_REGEX;
 |