| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391 | 'use strict';const utils = require('./utils');const {  CHAR_ASTERISK,             /* * */  CHAR_AT,                   /* @ */  CHAR_BACKWARD_SLASH,       /* \ */  CHAR_COMMA,                /* , */  CHAR_DOT,                  /* . */  CHAR_EXCLAMATION_MARK,     /* ! */  CHAR_FORWARD_SLASH,        /* / */  CHAR_LEFT_CURLY_BRACE,     /* { */  CHAR_LEFT_PARENTHESES,     /* ( */  CHAR_LEFT_SQUARE_BRACKET,  /* [ */  CHAR_PLUS,                 /* + */  CHAR_QUESTION_MARK,        /* ? */  CHAR_RIGHT_CURLY_BRACE,    /* } */  CHAR_RIGHT_PARENTHESES,    /* ) */  CHAR_RIGHT_SQUARE_BRACKET  /* ] */} = require('./constants');const isPathSeparator = code => {  return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH;};const depth = token => {  if (token.isPrefix !== true) {    token.depth = token.isGlobstar ? Infinity : 1;  }};/** * Quickly scans a glob pattern and returns an object with a handful of * useful properties, like `isGlob`, `path` (the leading non-glob, if it exists), * `glob` (the actual pattern), `negated` (true if the path starts with `!` but not * with `!(`) and `negatedExtglob` (true if the path starts with `!(`). * * ```js * const pm = require('picomatch'); * console.log(pm.scan('foo/bar/*.js')); * { isGlob: true, input: 'foo/bar/*.js', base: 'foo/bar', glob: '*.js' } * ``` * @param {String} `str` * @param {Object} `options` * @return {Object} Returns an object with tokens and regex source string. * @api public */const scan = (input, options) => {  const opts = options || {};  const length = input.length - 1;  const scanToEnd = opts.parts === true || opts.scanToEnd === true;  const slashes = [];  const tokens = [];  const parts = [];  let str = input;  let index = -1;  let start = 0;  let lastIndex = 0;  let isBrace = false;  let isBracket = false;  let isGlob = false;  let isExtglob = false;  let isGlobstar = false;  let braceEscaped = false;  let backslashes = false;  let negated = false;  let negatedExtglob = false;  let finished = false;  let braces = 0;  let prev;  let code;  let token = { value: '', depth: 0, isGlob: false };  const eos = () => index >= length;  const peek = () => str.charCodeAt(index + 1);  const advance = () => {    prev = code;    return str.charCodeAt(++index);  };  while (index < length) {    code = advance();    let next;    if (code === CHAR_BACKWARD_SLASH) {      backslashes = token.backslashes = true;      code = advance();      if (code === CHAR_LEFT_CURLY_BRACE) {        braceEscaped = true;      }      continue;    }    if (braceEscaped === true || code === CHAR_LEFT_CURLY_BRACE) {      braces++;      while (eos() !== true && (code = advance())) {        if (code === CHAR_BACKWARD_SLASH) {          backslashes = token.backslashes = true;          advance();          continue;        }        if (code === CHAR_LEFT_CURLY_BRACE) {          braces++;          continue;        }        if (braceEscaped !== true && code === CHAR_DOT && (code = advance()) === CHAR_DOT) {          isBrace = token.isBrace = true;          isGlob = token.isGlob = true;          finished = true;          if (scanToEnd === true) {            continue;          }          break;        }        if (braceEscaped !== true && code === CHAR_COMMA) {          isBrace = token.isBrace = true;          isGlob = token.isGlob = true;          finished = true;          if (scanToEnd === true) {            continue;          }          break;        }        if (code === CHAR_RIGHT_CURLY_BRACE) {          braces--;          if (braces === 0) {            braceEscaped = false;            isBrace = token.isBrace = true;            finished = true;            break;          }        }      }      if (scanToEnd === true) {        continue;      }      break;    }    if (code === CHAR_FORWARD_SLASH) {      slashes.push(index);      tokens.push(token);      token = { value: '', depth: 0, isGlob: false };      if (finished === true) continue;      if (prev === CHAR_DOT && index === (start + 1)) {        start += 2;        continue;      }      lastIndex = index + 1;      continue;    }    if (opts.noext !== true) {      const isExtglobChar = code === CHAR_PLUS        || code === CHAR_AT        || code === CHAR_ASTERISK        || code === CHAR_QUESTION_MARK        || code === CHAR_EXCLAMATION_MARK;      if (isExtglobChar === true && peek() === CHAR_LEFT_PARENTHESES) {        isGlob = token.isGlob = true;        isExtglob = token.isExtglob = true;        finished = true;        if (code === CHAR_EXCLAMATION_MARK && index === start) {          negatedExtglob = true;        }        if (scanToEnd === true) {          while (eos() !== true && (code = advance())) {            if (code === CHAR_BACKWARD_SLASH) {              backslashes = token.backslashes = true;              code = advance();              continue;            }            if (code === CHAR_RIGHT_PARENTHESES) {              isGlob = token.isGlob = true;              finished = true;              break;            }          }          continue;        }        break;      }    }    if (code === CHAR_ASTERISK) {      if (prev === CHAR_ASTERISK) isGlobstar = token.isGlobstar = true;      isGlob = token.isGlob = true;      finished = true;      if (scanToEnd === true) {        continue;      }      break;    }    if (code === CHAR_QUESTION_MARK) {      isGlob = token.isGlob = true;      finished = true;      if (scanToEnd === true) {        continue;      }      break;    }    if (code === CHAR_LEFT_SQUARE_BRACKET) {      while (eos() !== true && (next = advance())) {        if (next === CHAR_BACKWARD_SLASH) {          backslashes = token.backslashes = true;          advance();          continue;        }        if (next === CHAR_RIGHT_SQUARE_BRACKET) {          isBracket = token.isBracket = true;          isGlob = token.isGlob = true;          finished = true;          break;        }      }      if (scanToEnd === true) {        continue;      }      break;    }    if (opts.nonegate !== true && code === CHAR_EXCLAMATION_MARK && index === start) {      negated = token.negated = true;      start++;      continue;    }    if (opts.noparen !== true && code === CHAR_LEFT_PARENTHESES) {      isGlob = token.isGlob = true;      if (scanToEnd === true) {        while (eos() !== true && (code = advance())) {          if (code === CHAR_LEFT_PARENTHESES) {            backslashes = token.backslashes = true;            code = advance();            continue;          }          if (code === CHAR_RIGHT_PARENTHESES) {            finished = true;            break;          }        }        continue;      }      break;    }    if (isGlob === true) {      finished = true;      if (scanToEnd === true) {        continue;      }      break;    }  }  if (opts.noext === true) {    isExtglob = false;    isGlob = false;  }  let base = str;  let prefix = '';  let glob = '';  if (start > 0) {    prefix = str.slice(0, start);    str = str.slice(start);    lastIndex -= start;  }  if (base && isGlob === true && lastIndex > 0) {    base = str.slice(0, lastIndex);    glob = str.slice(lastIndex);  } else if (isGlob === true) {    base = '';    glob = str;  } else {    base = str;  }  if (base && base !== '' && base !== '/' && base !== str) {    if (isPathSeparator(base.charCodeAt(base.length - 1))) {      base = base.slice(0, -1);    }  }  if (opts.unescape === true) {    if (glob) glob = utils.removeBackslashes(glob);    if (base && backslashes === true) {      base = utils.removeBackslashes(base);    }  }  const state = {    prefix,    input,    start,    base,    glob,    isBrace,    isBracket,    isGlob,    isExtglob,    isGlobstar,    negated,    negatedExtglob  };  if (opts.tokens === true) {    state.maxDepth = 0;    if (!isPathSeparator(code)) {      tokens.push(token);    }    state.tokens = tokens;  }  if (opts.parts === true || opts.tokens === true) {    let prevIndex;    for (let idx = 0; idx < slashes.length; idx++) {      const n = prevIndex ? prevIndex + 1 : start;      const i = slashes[idx];      const value = input.slice(n, i);      if (opts.tokens) {        if (idx === 0 && start !== 0) {          tokens[idx].isPrefix = true;          tokens[idx].value = prefix;        } else {          tokens[idx].value = value;        }        depth(tokens[idx]);        state.maxDepth += tokens[idx].depth;      }      if (idx !== 0 || value !== '') {        parts.push(value);      }      prevIndex = i;    }    if (prevIndex && prevIndex + 1 < input.length) {      const value = input.slice(prevIndex + 1);      parts.push(value);      if (opts.tokens) {        tokens[tokens.length - 1].value = value;        depth(tokens[tokens.length - 1]);        state.maxDepth += tokens[tokens.length - 1].depth;      }    }    state.slashes = slashes;    state.parts = parts;  }  return state;};module.exports = scan;
 |