code:
'use strict';

const constants = require('./constants');
const utils = require('./utils');

/**
 * Constants
 */

const {
  MAX_LENGTH,
  POSIX_REGEX_SOURCE,
  REGEX_NON_SPECIAL_CHARS,
  REGEX_SPECIAL_CHARS_BACKREF,
  REPLACEMENTS
} = constants;

/**
 * Helpers
 */

const expandRange = (args, options) => {
  if (typeof options.expandRange === 'function') {
    return options.expandRange(...args, options);
  }

  args.sort();
  const value = `[${args.join('-')}]`;

  try {
    /* eslint-disable-next-line no-new */
    new RegExp(value);
  } catch (ex) {
    return args.map(v => utils.escapeRegex(v)).join('..');
  }

  return value;
};

/**
 * Create the message for a syntax error
 */

const syntaxError = (type, char) => {
  return `Missing ${type}: "${char}" - use "\\\\${char}" to match literal characters`;
};

/**
 * Parse the given input string.
 * @param {String} input
 * @param {Object} options
 * @return {Object}
 */

const parse = (input, options) => {
  if (typeof input !== 'string') {
    throw new TypeError('Expected a string');
  }

  input = REPLACEMENTS[input] || input;

  const opts = { ...options };
  const max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH;

  let len = input.length;
  if (len > max) {
    throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`);
  }

  const bos = { type: 'bos', value: '', output: opts.prepend || '' };
  const tokens = [bos];

  const capture = opts.capture ? '' : '?:';
  const win32 = utils.isWindows(options);

  // create constants based on platform, for windows or posix
  const PLATFORM_CHARS = constants.globChars(win32);
  const EXTGLOB_CHARS = constants.extglobChars(PLATFORM_CHARS);

  const {
    DOT_LITERAL,
    PLUS_LITERAL,
    SLASH_LITERAL,
    ONE_CHAR,
    DOTS_SLASH,
    NO_DOT,
    NO_DOT_SLASH,
    NO_DOTS_SLASH,
    QMARK,
    QMARK_NO_DOT,
    STAR,
    START_ANCHOR
  } = PLATFORM_CHARS;

  const globstar = opts => {
    return `(${capture}(?:(?!${START_ANCHOR}${opts.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`;
  };

  const nodot = opts.dot ? '' : NO_DOT;
  const qmarkNoDot = opts.dot ? QMARK : QMARK_NO_DOT;
  let star = opts.bash === true ? globstar(opts) : STAR;

  if (opts.capture) {
    star = `(${star})`;
  }

  // minimatch options support
  if (typeof opts.noext === 'boolean') {
    opts.noextglob = opts.noext;
  }

  const state = {
    input,
    index: -1,
    start: 0,
    dot: opts.dot === true,
    consumed: '',
    output: '',
    prefix: '',
    backtrack: false,
    negated: false,
    brackets: 0,
    braces: 0,
    parens: 0,
    quotes: 0,
    globstar: false,
    tokens
  };

  input = utils.removePrefix(input, state);
  len = input.length;

  const extglobs = [];
  const braces = [];
  const stack = [];
  let prev = bos;
  let value;

  /**
   * Tokenizing helpers
   */

  const eos = () => state.index === len - 1;
  const peek = state.peek = (n = 1) => input[state.index + n];
  const advance = state.advance = () => input[++state.index] || '';
  const remaining = () => input.slice(state.index + 1);
  const consume = (value = '', num = 0) => {
    state.consumed += value;
    state.index += num;
  };

  const append = token => {
    state.output += token.output != null ? token.output : token.value;
    consume(token.value);
  };

  const negate = () => {
    let count = 1;

    while (peek() === '!' && (peek(2) !== '(' || peek(3) === '?')) {
      advance();
      state.start++;
      count++;
    }

    if (count % 2 === 0) {
      return false;
    }

    state.negated = true;
    state.start++;
    return true;
  };

  const increment = type => {
    state[type]++;
    stack.push(type);
  };

  const decrement = type => {
    state[type]--;
    stack.pop();
  };

  /**
   * Push tokens onto the tokens array. This helper speeds up
   * tokenizing by 1) helping us avoid backtracking as much as possible,
   * and 2) helping us avoid creating extra tokens when consecutive
   * characters are plain text. This improves performance and simplifies
   * lookbehinds.
   */

  const push = tok => {
    if (prev.type === 'globstar') {
      const isBrace = state.braces > 0 && (tok.type === 'comma' || tok.type === 'brace');
      const isExtglob = tok.extglob === true || (extglobs.length && (tok.type === 'pipe' || tok.type === 'paren'));

      if (tok.type !== 'slash' && tok.type !== 'paren' && !isBrace && !isExtglob) {
        state.output = state.output.slice(0, -prev.output.length);
        prev.type = 'star';
        prev.value = '*';
        prev.output = star;
        state.output += prev.output;
      }
    }

    if (extglobs.length && tok.type !== 'paren') {
      extglobs[extglobs.length - 1].inner += tok.value;
    }

    if (tok.value || tok.output) append(tok);
    if (prev && prev.type === 'text' && tok.type === 'text') {
      prev.value += tok.value;
      prev.output = (prev.output || '') + tok.value;
      return;
    }

    tok.prev = prev;
    tokens.push(tok);
    prev = tok;
  };

  const extglobOpen = (type, value) => {
    const token = { ...EXTGLOB_CHARS[value], conditions: 1, inner: '' };

    token.prev = prev;
    token.parens = state.parens;
    token.output = state.output;
    const output = (opts.capture ? '(' : '') + token.open;

    increment('parens');
    push({ type, value, output: state.output ? '' : ONE_CHAR });
    push({ type: 'paren', extglob: true, value: advance(), output });
    extglobs.push(token);
  };

  const extglobClose = token => {
    let output = token.close + (opts.capture ? ')' : '');
    let rest;

    if (token.type === 'negate') {
      let extglobStar = star;

      if (token.inner && token.inner.length > 1 && token.inner.includes('/')) {
        extglobStar = globstar(opts);
      }

      if (extglobStar !== star || eos() || /^\)+$/.test(remaining())) {
        output = token.close = `)$))${extglobStar}`;
      }

      if (token.inner.includes('*') && (rest = remaining()) && /^\.[^\\/.]+$/.test(rest)) {
        // Any non-magical string (`.ts`) or even nested expression (`.{ts,tsx}`) can follow after the closing parenthesis.
        // In this case, we need to parse the string and use it in the output of the original pattern.
        // Suitable patterns: `/!(*.d).ts`, `/!(*.d).{ts,tsx}`, `**/!(*-dbg).@(js)`.
        //
        // Disabling the `fastpaths` option due to a problem with parsing strings as `.ts` in the pattern like `**/!(*.d).ts`.
        const expression = parse(rest, { ...options, fastpaths: false }).output;

        output = token.close = `)${expression})${extglobStar})`;
      }

      if (token.prev.type === 'bos') {
        state.negatedExtglob = true;
      }
    }

    push({ type: 'paren', extglob: true, value, output });
    decrement('parens');
  };

  /**
   * Fast paths
   */

  if (opts.fastpaths !== false && !/(^[*!]|[/()[\]{}"])/.test(input)) {
    let backslashes = false;

    let output = input.replace(REGEX_SPECIAL_CHARS_BACKREF, (m, esc, chars, first, rest, index) => {
      if (first === '\\') {
        backslashes = true;
        return m;
      }

      if (first === '?') {
        if (esc) {
          return esc + first + (rest ? QMARK.repeat(rest.length) : '');
        }
        if (index === 0) {
          return qmarkNoDot + (rest ? QMARK.repeat(rest.length) : '');
        }
        return QMARK.repeat(chars.length);
      }

      if (first === '.') {
        return DOT_LITERAL.repeat(chars.length);
      }

      if (first === '*') {
        if (esc) {
          return esc + first + (rest ? star : '');
        }
        return star;
      }
      return esc ? m : `\\${m}`;
    });

    if (backslashes === true) {
      if (opts.unescape === true) {
        output = output.replace(/\\/g, '');
      } else {
        output = output.replace(/\\+/g, m => {
          return m.length % 2 === 0 ? '\\\\' : (m ? '\\' : '');
        });
      }
    }

    if (output === input && opts.contains === true) {
      state.output = input;
      return state;
    }

    state.output = utils.wrapOutput(output, state, options);
    return state;
  }

  /**
   * Tokenize input until we reach end-of-string
   */

  while (!eos()) {
    value = advance();

    if (value === '\u0000') {
      continue;
    }

    /**
     * Escaped characters
     */

    if (value === '\\') {
      const next = peek();

      if (next === '/' && opts.bash !== true) {
        continue;
      }

      if (next === '.' || next === ';') {
        continue;
      }

      if (!next) {
        value += '\\';
        push({ type: 'text', value });
        continue;
      }

      // collapse slashes to reduce potential for exploits
      const match = /^\\+/.exec(remaining());
      let slashes = 0;

      if (match && match[0].length > 2) {
        slashes = match[0].length;
        state.index += slashes;
        if (slashes % 2 !== 0) {
          value += '\\';
        }
      }

      if (opts.unescape === true) {
        value = advance();
      } else {
        value += advance();
      }

      if (state.brackets === 0) {
        push({ type: 'text', value });
        continue;
      }
    }

    /**
     * If we're inside a regex character class, continue
     * until we reach the closing bracket.
     */

    if (state.brackets > 0 && (value !== ']' || prev.value === '[' || prev.value === '[^')) {
      if (opts.posix !== false && value === ':') {
        const inner = prev.value.slice(1);
        if (inner.includes('[')) {
          prev.posix = true;

          if (inner.includes(':')) {
            const idx = prev.value.lastIndexOf('[');
            const pre = prev.value.slice(0, idx);
            const rest = prev.value.slice(idx + 2);
            const posix = POSIX_REGEX_SOURCE[rest];
            if (posix) {
              prev.value = pre + posix;
              state.backtrack = true;
              advance();

              if (!bos.output && tokens.indexOf(prev) === 1) {
                bos.output = ONE_CHAR;
              }
              continue;
            }
          }
        }
      }

      if ((value === '[' && peek() !== ':') || (value === '-' && peek() === ']')) {
        value = `\\${value}`;
      }

      if (value === ']' && (prev.value === '[' || prev.value === '[^')) {
        value = `\\${value}`;
      }

      if (opts.posix === true && value === '!' && prev.value === '[') {
        value = '^';
      }

      prev.value += value;
      append({ value });
      continue;
    }

    /**
     * If we're inside a quoted string, continue
     * until we reach the closing double quote.
     */

    if (state.quotes === 1 && value !== '"') {
      value = utils.escapeRegex(value);
      prev.value += value;
      append({ value });
      continue;
    }

    /**
     * Double quotes
     */

    if (value === '"') {
      state.quotes = state.quotes === 1 ? 0 : 1;
      if (opts.keepQuotes === true) {
        push({ type: 'text', value });
      }
      continue;
    }

    /**
     * Parentheses
     */

    if (value === '(') {
      increment('parens');
      push({ type: 'paren', value });
      continue;
    }

    if (value === ')') {
      if (state.parens === 0 && opts.strictBrackets === true) {
        throw new SyntaxError(syntaxError('opening', '('));
      }

      const extglob = extglobs[extglobs.length - 1];
      if (extglob && state.parens === extglob.parens + 1) {
        extglobClose(extglobs.pop());
        continue;
      }

      push({ type: 'paren', value, output: state.parens ? ')' : '\\)' });
      decrement('parens');
      continue;
    }

    /**
     * Square brackets
     */

    if (value === '[') {
      if (opts.nobracket === true || !remaining().includes(']')) {
        if (opts.nobracket !== true && opts.strictBrackets === true) {
          throw new SyntaxError(syntaxError('closing', ']'));
        }

        value = `\\${value}`;
      } else {
        increment('brackets');
      }

      push({ type: 'bracket', value });
      continue;
    }

    if (value === ']') {
      if (opts.nobracket === true || (prev && prev.type === 'bracket' && prev.value.length === 1)) {
        push({ type: 'text', value, output: `\\${value}` });
        continue;
      }

      if (state.brackets === 0) {
        if (opts.strictBrackets === true) {
          throw new SyntaxError(syntaxError('opening', '['));
        }

        push({ type: 'text', value, output: `\\${value}` });
        continue;
      }

      decrement('brackets');

      const prevValue = prev.value.slice(1);
      if (prev.posix !== true && prevValue[0] === '^' && !prevValue.includes('/')) {
        value = `/${value}`;
      }

      prev.value += value;
      append({ value });

      // when literal brackets are explicitly disabled
      // assume we should match with a regex character class
      if (opts.literalBrackets === false || utils.hasRegexChars(prevValue)) {
        continue;
      }

      const escaped = utils.escapeRegex(prev.value);
      state.output = state.output.slice(0, -prev.value.length);

      // when literal brackets are explicitly enabled
      // assume we should escape the brackets to match literal characters
      if (opts.literalBrackets === true) {
        state.output += escaped;
        prev.value = escaped;
        continue;
      }

      // when the user specifies nothing, try to match both
      prev.value = `(${capture}${escaped}|${prev.value})`;
      state.output += prev.value;
      continue;
    }

    /**
     * Braces
     */

    if (value === '{' && opts.nobrace !== true) {
      increment('braces');

      const open = {
        type: 'brace',
        value,
        output: '(',
        outputIndex: state.output.length,
        tokensIndex: state.tokens.length
      };

      braces.push(open);
      push(open);
      continue;
    }

    if (value === '}') {
      const brace = braces[braces.length - 1];

      if (opts.nobrace === true || !brace) {
        push({ type: 'text', value, output: value });
        continue;
      }

      let output = ')';

      if (brace.dots === true) {
        const arr = tokens.slice();
        const range = [];

        for (let i = arr.length - 1; i >= 0; i--) {
          tokens.pop();
          if (arr[i].type === 'brace') {
            break;
          }
          if (arr[i].type !== 'dots') {
            range.unshift(arr[i].value);
          }
        }

        output = expandRange(range, opts);
        state.backtrack = true;
      }

      if (brace.comma !== true && brace.dots !== true) {
        const out = state.output.slice(0, brace.outputIndex);
        const toks = state.tokens.slice(brace.tokensIndex);
        brace.value = brace.output = '\\{';
        value = output = '\\}';
        state.output = out;
        for (const t of toks) {
          state.output += (t.output || t.value);
        }
      }

      push({ type: 'brace', value, output });
      decrement('braces');
      braces.pop();
      continue;
    }

    /**
     * Pipes
     */

    if (value === '|') {
      if (extglobs.length > 0) {
        extglobs[extglobs.length - 1].conditions++;
      }
      push({ type: 'text', value });
      continue;
    }

    /**
     * Commas
     */

    if (value === ',') {
      let output = value;

      const brace = braces[braces.length - 1];
      if (brace && stack[stack.length - 1] === 'braces') {
        brace.comma = true;
        output = '|';
      }

      push({ type: 'comma', value, output });
      continue;
    }

    /**
     * Slashes
     */

    if (value === '/') {
      // if the beginning of the glob is "./", advance the start
      // to the current index, and don't add the "./" characters
      // to the state. This greatly simplifies lookbehinds when
      // checking for BOS characters like "!" and "." (not "./")
      if (prev.type === 'dot' && state.index === state.start + 1) {
        state.start = state.index + 1;
        state.consumed = '';
        state.output = '';
        tokens.pop();
        prev = bos; // reset "prev" to the first token
        continue;
      }

      push({ type: 'slash', value, output: SLASH_LITERAL });
      continue;
    }

    /**
     * Dots
     */

    if (value === '.') {
      if (state.braces > 0 && prev.type === 'dot') {
        if (prev.value === '.') prev.output = DOT_LITERAL;
        const brace = braces[braces.length - 1];
        prev.type = 'dots';
        prev.output += value;
        prev.value += value;
        brace.dots = true;
        continue;
      }

      if ((state.braces + state.parens) === 0 && prev.type !== 'bos' && prev.type !== 'slash') {
        push({ type: 'text', value, output: DOT_LITERAL });
        continue;
      }

      push({ type: 'dot', value, output: DOT_LITERAL });
      continue;
    }

    /**
     * Question marks
     */

    if (value === '?') {
      const isGroup = prev && prev.value === '(';
      if (!isGroup && opts.noextglob !== true && peek() === '(' && peek(2) !== '?') {
        extglobOpen('qmark', value);
        continue;
      }

      if (prev && prev.type === 'paren') {
        const next = peek();
        let output = value;

        if (next === '<' && !utils.supportsLookbehinds()) {
          throw new Error('Node.js v10 or higher is required for regex lookbehinds');
        }

        if ((prev.value === '(' && !/[!=<:]/.test(next)) || (next === '<' && !/<([!=]|\w+>)/.test(remaining()))) {
          output = `\\${value}`;
        }

        push({ type: 'text', value, output });
        continue;
      }

      if (opts.dot !== true && (prev.type === 'slash' || prev.type === 'bos')) {
        push({ type: 'qmark', value, output: QMARK_NO_DOT });
        continue;
      }

      push({ type: 'qmark', value, output: QMARK });
      continue;
    }

    /**
     * Exclamation
     */

    if (value === '!') {
      if (opts.noextglob !== true && peek() === '(') {
        if (peek(2) !== '?' || !/[!=<:]/.test(peek(3))) {
          extglobOpen('negate', value);
          continue;
        }
      }

      if (opts.nonegate !== true && state.index === 0) {
        negate();
        continue;
      }
    }

    /**
     * Plus
     */

    if (value === '+') {
      if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') {
        extglobOpen('plus', value);
        continue;
      }

      if ((prev && prev.value === '(') || opts.regex === false) {
        push({ type: 'plus', value, output: PLUS_LITERAL });
        continue;
      }

      if ((prev && (prev.type === 'bracket' || prev.type === 'paren' || prev.type === 'brace')) || state.parens > 0) {
        push({ type: 'plus', value });
        continue;
      }

      push({ type: 'plus', value: PLUS_LITERAL });
      continue;
    }

    /**
     * Plain text
     */

    if (value === '@') {
      if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') {
        push({ type: 'at', extglob: true, value, output: '' });
        continue;
      }

      push({ type: 'text', value });
      continue;
    }

    /**
     * Plain text
     */

    if (value !== '*') {
      if (value === '$' || value === '^') {
        value = `\\${value}`;
      }

      const match = REGEX_NON_SPECIAL_CHARS.exec(remaining());
      if (match) {
        value += match[0];
        state.index += match[0].length;
      }

      push({ type: 'text', value });
      continue;
    }

    /**
     * Stars
     */

    if (prev && (prev.type === 'globstar' || prev.star === true)) {
      prev.type = 'star';
      prev.star = true;
      prev.value += value;
      prev.output = star;
      state.backtrack = true;
      state.globstar = true;
      consume(value);
      continue;
    }

    let rest = remaining();
    if (opts.noextglob !== true && /^\([^?]/.test(rest)) {
      extglobOpen('star', value);
      continue;
    }

    if (prev.type === 'star') {
      if (opts.noglobstar === true) {
        consume(value);
        continue;
      }

      const prior = prev.prev;
      const before = prior.prev;
      const isStart = prior.type === 'slash' || prior.type === 'bos';
      const afterStar = before && (before.type === 'star' || before.type === 'globstar');

      if (opts.bash === true && (!isStart || (rest[0] && rest[0] !== '/'))) {
        push({ type: 'star', value, output: '' });
        continue;
      }

      const isBrace = state.braces > 0 && (prior.type === 'comma' || prior.type === 'brace');
      const isExtglob = extglobs.length && (prior.type === 'pipe' || prior.type === 'paren');
      if (!isStart && prior.type !== 'paren' && !isBrace && !isExtglob) {
        push({ type: 'star', value, output: '' });
        continue;
      }

      // strip consecutive `/**/`
      while (rest.slice(0, 3) === '/**') {
        const after = input[state.index + 4];
        if (after && after !== '/') {
          break;
        }
        rest = rest.slice(3);
        consume('/**', 3);
      }

      if (prior.type === 'bos' && eos()) {
        prev.type = 'globstar';
        prev.value += value;
        prev.output = globstar(opts);
        state.output = prev.output;
        state.globstar = true;
        consume(value);
        continue;
      }

      if (prior.type === 'slash' && prior.prev.type !== 'bos' && !afterStar && eos()) {
        state.output = state.output.slice(0, -(prior.output + prev.output).length);
        prior.output = `(?:${prior.output}`;

        prev.type = 'globstar';
        prev.output = globstar(opts) + (opts.strictSlashes ? ')' : '|$)');
        prev.value += value;
        state.globstar = true;
        state.output += prior.output + prev.output;
        consume(value);
        continue;
      }

      if (prior.type === 'slash' && prior.prev.type !== 'bos' && rest[0] === '/') {
        const end = rest[1] !== void 0 ? '|$' : '';

        state.output = state.output.slice(0, -(prior.output + prev.output).length);
        prior.output = `(?:${prior.output}`;

        prev.type = 'globstar';
        prev.output = `${globstar(opts)}${SLASH_LITERAL}|${SLASH_LITERAL}${end})`;
        prev.value += value;

        state.output += prior.output + prev.output;
        state.globstar = true;

        consume(value + advance());

        push({ type: 'slash', value: '/', output: '' });
        continue;
      }

      if (prior.type === 'bos' && rest[0] === '/') {
        prev.type = 'globstar';
        prev.value += value;
        prev.output = `(?:^|${SLASH_LITERAL}|${globstar(opts)}${SLASH_LITERAL})`;
        state.output = prev.output;
        state.globstar = true;
        consume(value + advance());
        push({ type: 'slash', value: '/', output: '' });
        continue;
      }

      // remove single star from output
      state.output = state.output.slice(0, -prev.output.length);

      // reset previous token to globstar
      prev.type = 'globstar';
      prev.output = globstar(opts);
      prev.value += value;

      // reset output with globstar
      state.output += prev.output;
      state.globstar = true;
      consume(value);
      continue;
    }

    const token = { type: 'star', value, output: star };

    if (opts.bash === true) {
      token.output = '.*?';
      if (prev.type === 'bos' || prev.type === 'slash') {
        token.output = nodot + token.output;
      }
      push(token);
      continue;
    }

    if (prev && (prev.type === 'bracket' || prev.type === 'paren') && opts.regex === true) {
      token.output = value;
      push(token);
      continue;
    }

    if (state.index === state.start || prev.type === 'slash' || prev.type === 'dot') {
      if (prev.type === 'dot') {
        state.output += NO_DOT_SLASH;
        prev.output += NO_DOT_SLASH;

      } else if (opts.dot === true) {
        state.output += NO_DOTS_SLASH;
        prev.output += NO_DOTS_SLASH;

      } else {
        state.output += nodot;
        prev.output += nodot;
      }

      if (peek() !== '*') {
        state.output += ONE_CHAR;
        prev.output += ONE_CHAR;
      }
    }

    push(token);
  }

  while (state.brackets > 0) {
    if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', ']'));
    state.output = utils.escapeLast(state.output, '[');
    decrement('brackets');
  }

  while (state.parens > 0) {
    if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', ')'));
    state.output = utils.escapeLast(state.output, '(');
    decrement('parens');
  }

  while (state.braces > 0) {
    if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', '}'));
    state.output = utils.escapeLast(state.output, '{');
    decrement('braces');
  }

  if (opts.strictSlashes !== true && (prev.type === 'star' || prev.type === 'bracket')) {
    push({ type: 'maybe_slash', value: '', output: `${SLASH_LITERAL}?` });
  }

  // rebuild the output if we had to backtrack at any point
  if (state.backtrack === true) {
    state.output = '';

    for (const token of state.tokens) {
      state.output += token.output != null ? token.output : token.value;

      if (token.suffix) {
        state.output += token.suffix;
      }
    }
  }

  return state;
};

/**
 * Fast paths for creating regular expressions for common glob patterns.
 * This can significantly speed up processing and has very little downside
 * impact when none of the fast paths match.
 */

parse.fastpaths = (input, options) => {
  const opts = { ...options };
  const max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH;
  const len = input.length;
  if (len > max) {
    throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`);
  }

  input = REPLACEMENTS[input] || input;
  const win32 = utils.isWindows(options);

  // create constants based on platform, for windows or posix
  const {
    DOT_LITERAL,
    SLASH_LITERAL,
    ONE_CHAR,
    DOTS_SLASH,
    NO_DOT,
    NO_DOTS,
    NO_DOTS_SLASH,
    STAR,
    START_ANCHOR
  } = constants.globChars(win32);

  const nodot = opts.dot ? NO_DOTS : NO_DOT;
  const slashDot = opts.dot ? NO_DOTS_SLASH : NO_DOT;
  const capture = opts.capture ? '' : '?:';
  const state = { negated: false, prefix: '' };
  let star = opts.bash === true ? '.*?' : STAR;

  if (opts.capture) {
    star = `(${star})`;
  }

  const globstar = opts => {
    if (opts.noglobstar === true) return star;
    return `(${capture}(?:(?!${START_ANCHOR}${opts.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`;
  };

  const create = str => {
    switch (str) {
      case '*':
        return `${nodot}${ONE_CHAR}${star}`;

      case '.*':
        return `${DOT_LITERAL}${ONE_CHAR}${star}`;

      case '*.*':
        return `${nodot}${star}${DOT_LITERAL}${ONE_CHAR}${star}`;

      case '*/*':
        return `${nodot}${star}${SLASH_LITERAL}${ONE_CHAR}${slashDot}${star}`;

      case '**':
        return nodot + globstar(opts);

      case '**/*':
        return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${slashDot}${ONE_CHAR}${star}`;

      case '**/*.*':
        return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${slashDot}${star}${DOT_LITERAL}${ONE_CHAR}${star}`;

      case '**/.*':
        return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${DOT_LITERAL}${ONE_CHAR}${star}`;

      default: {
        const match = /^(.*?)\.(\w+)$/.exec(str);
        if (!match) return;

        const source = create(match[1]);
        if (!source) return;

        return source + DOT_LITERAL + match[2];
      }
    }
  };

  const output = utils.removePrefix(input, state);
  let source = create(output);

  if (source && opts.strictSlashes !== true) {
    source += `${SLASH_LITERAL}?`;
  }

  return source;
};

module.exports = parse;


code:
'use strict';

const path = require('path');
const scan = require('./scan');
const parse = require('./parse');
const utils = require('./utils');
const constants = require('./constants');
const isObject = val => val && typeof val === 'object' && !Array.isArray(val);

/**
 * Creates a matcher function from one or more glob patterns. The
 * returned function takes a string to match as its first argument,
 * and returns true if the string is a match. The returned matcher
 * function also takes a boolean as the second argument that, when true,
 * returns an object with additional information.
 *
 * ```js
 * const picomatch = require('picomatch');
 * // picomatch(glob[, options]);
 *
 * const isMatch = picomatch('*.!(*a)');
 * console.log(isMatch('a.a')); //=> false
 * console.log(isMatch('a.b')); //=> true
 * ```
 * @name picomatch
 * @param {String|Array} `globs` One or more glob patterns.
 * @param {Object=} `options`
 * @return {Function=} Returns a matcher function.
 * @api public
 */

const picomatch = (glob, options, returnState = false) => {
  if (Array.isArray(glob)) {
    const fns = glob.map(input => picomatch(input, options, returnState));
    const arrayMatcher = str => {
      for (const isMatch of fns) {
        const state = isMatch(str);
        if (state) return state;
      }
      return false;
    };
    return arrayMatcher;
  }

  const isState = isObject(glob) && glob.tokens && glob.input;

  if (glob === '' || (typeof glob !== 'string' && !isState)) {
    throw new TypeError('Expected pattern to be a non-empty string');
  }

  const opts = options || {};
  const posix = utils.isWindows(options);
  const regex = isState
    ? picomatch.compileRe(glob, options)
    : picomatch.makeRe(glob, options, false, true);

  const state = regex.state;
  delete regex.state;

  let isIgnored = () => false;
  if (opts.ignore) {
    const ignoreOpts = { ...options, ignore: null, onMatch: null, onResult: null };
    isIgnored = picomatch(opts.ignore, ignoreOpts, returnState);
  }

  const matcher = (input, returnObject = false) => {
    const { isMatch, match, output } = picomatch.test(input, regex, options, { glob, posix });
    const result = { glob, state, regex, posix, input, output, match, isMatch };

    if (typeof opts.onResult === 'function') {
      opts.onResult(result);
    }

    if (isMatch === false) {
      result.isMatch = false;
      return returnObject ? result : false;
    }

    if (isIgnored(input)) {
      if (typeof opts.onIgnore === 'function') {
        opts.onIgnore(result);
      }
      result.isMatch = false;
      return returnObject ? result : false;
    }

    if (typeof opts.onMatch === 'function') {
      opts.onMatch(result);
    }
    return returnObject ? result : true;
  };

  if (returnState) {
    matcher.state = state;
  }

  return matcher;
};

/**
 * Test `input` with the given `regex`. This is used by the main
 * `picomatch()` function to test the input string.
 *
 * ```js
 * const picomatch = require('picomatch');
 * // picomatch.test(input, regex[, options]);
 *
 * console.log(picomatch.test('foo/bar', /^(?:([^/]*?)\/([^/]*?))$/));
 * // { isMatch: true, match: [ 'foo/', 'foo', 'bar' ], output: 'foo/bar' }
 * ```
 * @param {String} `input` String to test.
 * @param {RegExp} `regex`
 * @return {Object} Returns an object with matching info.
 * @api public
 */

picomatch.test = (input, regex, options, { glob, posix } = {}) => {
  if (typeof input !== 'string') {
    throw new TypeError('Expected input to be a string');
  }

  if (input === '') {
    return { isMatch: false, output: '' };
  }

  const opts = options || {};
  const format = opts.format || (posix ? utils.toPosixSlashes : null);
  let match = input === glob;
  let output = (match && format) ? format(input) : input;

  if (match === false) {
    output = format ? format(input) : input;
    match = output === glob;
  }

  if (match === false || opts.capture === true) {
    if (opts.matchBase === true || opts.basename === true) {
      match = picomatch.matchBase(input, regex, options, posix);
    } else {
      match = regex.exec(output);
    }
  }

  return { isMatch: Boolean(match), match, output };
};

/**
 * Match the basename of a filepath.
 *
 * ```js
 * const picomatch = require('picomatch');
 * // picomatch.matchBase(input, glob[, options]);
 * console.log(picomatch.matchBase('foo/bar.js', '*.js'); // true
 * ```
 * @param {String} `input` String to test.
 * @param {RegExp|String} `glob` Glob pattern or regex created by [.makeRe](#makeRe).
 * @return {Boolean}
 * @api public
 */

picomatch.matchBase = (input, glob, options, posix = utils.isWindows(options)) => {
  const regex = glob instanceof RegExp ? glob : picomatch.makeRe(glob, options);
  return regex.test(path.basename(input));
};

/**
 * Returns true if **any** of the given glob `patterns` match the specified `string`.
 *
 * ```js
 * const picomatch = require('picomatch');
 * // picomatch.isMatch(string, patterns[, options]);
 *
 * console.log(picomatch.isMatch('a.a', ['b.*', '*.a'])); //=> true
 * console.log(picomatch.isMatch('a.a', 'b.*')); //=> false
 * ```
 * @param {String|Array} str The string to test.
 * @param {String|Array} patterns One or more glob patterns to use for matching.
 * @param {Object} [options] See available [options](#options).
 * @return {Boolean} Returns true if any patterns match `str`
 * @api public
 */

picomatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str);

/**
 * Parse a glob pattern to create the source string for a regular
 * expression.
 *
 * ```js
 * const picomatch = require('picomatch');
 * const result = picomatch.parse(pattern[, options]);
 * ```
 * @param {String} `pattern`
 * @param {Object} `options`
 * @return {Object} Returns an object with useful properties and output to be used as a regex source string.
 * @api public
 */

picomatch.parse = (pattern, options) => {
  if (Array.isArray(pattern)) return pattern.map(p => picomatch.parse(p, options));
  return parse(pattern, { ...options, fastpaths: false });
};

/**
 * Scan a glob pattern to separate the pattern into segments.
 *
 * ```js
 * const picomatch = require('picomatch');
 * // picomatch.scan(input[, options]);
 *
 * const result = picomatch.scan('!./foo/*.js');
 * console.log(result);
 * { prefix: '!./',
 *   input: '!./foo/*.js',
 *   start: 3,
 *   base: 'foo',
 *   glob: '*.js',
 *   isBrace: false,
 *   isBracket: false,
 *   isGlob: true,
 *   isExtglob: false,
 *   isGlobstar: false,
 *   negated: true }
 * ```
 * @param {String} `input` Glob pattern to scan.
 * @param {Object} `options`
 * @return {Object} Returns an object with
 * @api public
 */

picomatch.scan = (input, options) => scan(input, options);

/**
 * Compile a regular expression from the `state` object returned by the
 * [parse()](#parse) method.
 *
 * @param {Object} `state`
 * @param {Object} `options`
 * @param {Boolean} `returnOutput` Intended for implementors, this argument allows you to return the raw output from the parser.
 * @param {Boolean} `returnState` Adds the state to a `state` property on the returned regex. Useful for implementors and debugging.
 * @return {RegExp}
 * @api public
 */

picomatch.compileRe = (state, options, returnOutput = false, returnState = false) => {
  if (returnOutput === true) {
    return state.output;
  }

  const opts = options || {};
  const prepend = opts.contains ? '' : '^';
  const append = opts.contains ? '' : '$';

  let source = `${prepend}(?:${state.output})${append}`;
  if (state && state.negated === true) {
    source = `^(?!${source}).*$`;
  }

  const regex = picomatch.toRegex(source, options);
  if (returnState === true) {
    regex.state = state;
  }

  return regex;
};

/**
 * Create a regular expression from a parsed glob pattern.
 *
 * ```js
 * const picomatch = require('picomatch');
 * const state = picomatch.parse('*.js');
 * // picomatch.compileRe(state[, options]);
 *
 * console.log(picomatch.compileRe(state));
 * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/
 * ```
 * @param {String} `state` The object returned from the `.parse` method.
 * @param {Object} `options`
 * @param {Boolean} `returnOutput` Implementors may use this argument to return the compiled output, instead of a regular expression. This is not exposed on the options to prevent end-users from mutating the result.
 * @param {Boolean} `returnState` Implementors may use this argument to return the state from the parsed glob with the returned regular expression.
 * @return {RegExp} Returns a regex created from the given pattern.
 * @api public
 */

picomatch.makeRe = (input, options = {}, returnOutput = false, returnState = false) => {
  if (!input || typeof input !== 'string') {
    throw new TypeError('Expected a non-empty string');
  }

  let parsed = { negated: false, fastpaths: true };

  if (options.fastpaths !== false && (input[0] === '.' || input[0] === '*')) {
    parsed.output = parse.fastpaths(input, options);
  }

  if (!parsed.output) {
    parsed = parse(input, options);
  }

  return picomatch.compileRe(parsed, options, returnOutput, returnState);
};

/**
 * Create a regular expression from the given regex source string.
 *
 * ```js
 * const picomatch = require('picomatch');
 * // picomatch.toRegex(source[, options]);
 *
 * const { output } = picomatch.parse('*.js');
 * console.log(picomatch.toRegex(output));
 * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/
 * ```
 * @param {String} `source` Regular expression source string.
 * @param {Object} `options`
 * @return {RegExp}
 * @api public
 */

picomatch.toRegex = (source, options) => {
  try {
    const opts = options || {};
    return new RegExp(source, opts.flags || (opts.nocase ? 'i' : ''));
  } catch (err) {
    if (options && options.debug === true) throw err;
    return /$^/;
  }
};

/**
 * Picomatch constants.
 * @return {Object}
 */

picomatch.constants = constants;

/**
 * Expose "picomatch"
 */

module.exports = picomatch;

license: mit


code:
'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;


code:
'use strict';

const path = require('path');
const win32 = process.platform === 'win32';
const {
  REGEX_BACKSLASH,
  REGEX_REMOVE_BACKSLASH,
  REGEX_SPECIAL_CHARS,
  REGEX_SPECIAL_CHARS_GLOBAL
} = require('./constants');

exports.isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val);
exports.hasRegexChars = str => REGEX_SPECIAL_CHARS.test(str);
exports.isRegexChar = str => str.length === 1 && exports.hasRegexChars(str);
exports.escapeRegex = str => str.replace(REGEX_SPECIAL_CHARS_GLOBAL, '\\$1');
exports.toPosixSlashes = str => str.replace(REGEX_BACKSLASH, '/');

exports.removeBackslashes = str => {
  return str.replace(REGEX_REMOVE_BACKSLASH, match => {
    return match === '\\' ? '' : match;
  });
};

exports.supportsLookbehinds = () => {
  const segs = process.version.slice(1).split('.').map(Number);
  if (segs.length === 3 && segs[0] >= 9 || (segs[0] === 8 && segs[1] >= 10)) {
    return true;
  }
  return false;
};

exports.isWindows = options => {
  if (options && typeof options.windows === 'boolean') {
    return options.windows;
  }
  return win32 === true || path.sep === '\\';
};

exports.escapeLast = (input, char, lastIdx) => {
  const idx = input.lastIndexOf(char, lastIdx);
  if (idx === -1) return input;
  if (input[idx - 1] === '\\') return exports.escapeLast(input, char, idx - 1);
  return `${input.slice(0, idx)}\\${input.slice(idx)}`;
};

exports.removePrefix = (input, state = {}) => {
  let output = input;
  if (output.startsWith('./')) {
    output = output.slice(2);
    state.prefix = './';
  }
  return output;
};

exports.wrapOutput = (input, state = {}, options = {}) => {
  const prepend = options.contains ? '' : '^';
  const append = options.contains ? '' : '$';

  let output = `${prepend}(?:${input})${append}`;
  if (state.negated === true) {
    output = `(?:^(?!${output}).*$)`;
  }
  return output;
};


picomatch

description: Blazing fast and accurate glob matcher written in JavaScript, with no dependencies and full support for standard and extended Bash glob features, including braces, extglobs, POSIX brackets, and regular expressions.

repository: micromatch/picomatch

license: MIT

lint: eslint --cache --cache-location node_modules/.cache/.eslintcache --report-unused-disable-directives --ignore-path .gitignore .

mocha: mocha --reporter dot

test: npm run lint && npm run mocha

test:ci: npm run test:cover

test:cover: nyc npm run mocha

keywords: glob match picomatch

reporter: html lcov text-summary

method: preWrite

layout: empty

list: braces micromatch

reflinks: braces expand-brackets extglob fill-range micromatch minimatch nanomatch picomatch


code:
#!/usr/bin/env node

'use strict';

var os = require('os');
var pidtree = require('..');

// The method startsWith is not defined on string objects in node 0.10
// eslint-disable-next-line no-extend-native
String.prototype.startsWith = function(suffix) {
  return this.substring(0, suffix.length) === suffix;
};

function help() {
  var help =
    '  Usage\n' +
    '  $ pidtree <ppid>\n' +
    '\n' +
    'Options\n' +
    '  --list                     To print the pids as a list.\n' +
    '\n' +
    'Examples\n' +
    '  $ pidtree\n' +
    '  $ pidtree --list\n' +
    '  $ pidtree 1\n' +
    '  $ pidtree 1 --list\n';
  console.log(help);
}

function list(ppid) {
  pidtree(ppid === undefined ? -1 : ppid, function(err, list) {
    if (err) {
      console.error(err.message);
      return;
    }

    console.log(list.join(os.EOL));
  });
}

function tree(ppid) {
  pidtree(ppid, {advanced: true}, function(err, list) {
    if (err) {
      console.error(err.message);
      return;
    }

    var parents = {}; // Hash Map of parents
    var tree = {}; // Adiacency Hash Map
    while (list.length > 0) {
      var element = list.pop();
      if (tree[element.ppid]) {
        tree[element.ppid].push(element.pid);
      } else {
        tree[element.ppid] = [element.pid];
      }

      if (ppid === -1) {
        parents[element.pid] = element.ppid;
      }
    }

    var roots = [ppid];
    if (ppid === -1) {
      // Get all the roots
      roots = Object.keys(tree).filter(function(node) {
        return parents[node] === undefined;
      });
    }

    roots.forEach(function(root) {
      print(tree, root);
    });
  });

  function print(tree, start) {
    function printBranch(node, branch) {
      var isGraphHead = branch.length === 0;
      var children = tree[node] || [];

      var branchHead = '';
      if (!isGraphHead) {
        branchHead = children.length > 0 ? '┬ ' : '─ ';
      }

      console.log(branch + branchHead + node);

      var baseBranch = branch;
      if (!isGraphHead) {
        var isChildOfLastBranch = branch.slice(-2) === '└─';
        baseBranch = branch.slice(0, -2) + (isChildOfLastBranch ? '  ' : '| ');
      }

      var nextBranch = baseBranch + '├─';
      var lastBranch = baseBranch + '└─';
      children.forEach(function(child, index) {
        printBranch(
          child,
          children.length - 1 === index ? lastBranch : nextBranch
        );
      });
    }

    printBranch(start, '');
  }
}

function run() {
  var flag;
  var ppid;
  for (var i = 2; i < process.argv.length; i++) {
    if (process.argv[i].startsWith('--')) {
      flag = process.argv[i];
    } else {
      ppid = process.argv[i];
    }
  }

  if (ppid === undefined) {
    ppid = -1;
  }

  if (flag === '--list') list(ppid);
  else if (flag === undefined) tree(ppid);
  else help();
}

run();


code:
declare namespace PidTree {
  export interface Options {
    /**
     * Include the provided PID in the list. Ignored if -1 is passed as PID.
     * @default false
     */
    root?: boolean;
  }

  export interface AdvancedResult {
    /**
     * PID of the parent.
     */
    ppid: number;
    /**
     * PID
     */
    pid: number;
  }

  export type Result = number;
}

/**
 * Get the list of children pids of the given pid.
 * @param  pid A PID. If -1 will return all the pids.
 * @param  callback Called when the list is ready.
 */
declare function pidtree(
  pid: string | number,
  callback: (error: Error | undefined, result: PidTree.Result[]) => void
): void;

/**
 * Get the list of children pids of the given pid.
 * @param  pid A PID. If -1 will return all the pids.
 * @param  options Options object.
 * @param  callback Called when the list is ready.
 */
declare function pidtree(
  pid: string | number,
  options: PidTree.Options,
  callback: (error: Error | undefined, result: PidTree.Result[]) => void
): void;

/**
 * Get the list of children pids of the given pid.
 * @param  pid A PID. If -1 will return all the pids.
 * @param  options Options object.
 * @param  callback Called when the list is ready.
 */
declare function pidtree(
  pid: string | number,
  options: PidTree.Options & {advanced: true},
  callback: (error: Error | undefined, result: PidTree.AdvancedResult[]) => void
): void;

/**
 * Get the list of children pids of the given pid.
 * @param  pid A PID. If -1 will return all the pids.
 * @param  [options] Optional options object.
 * @returns A promise containing the list.
 */
declare function pidtree(
  pid: string | number,
  options?: PidTree.Options
): Promise<PidTree.Result[]>;

/**
 * Get the list of children pids of the given pid.
 * @param  pid A PID. If -1 will return all the pids.
 * @param  options Options object.
 * @returns A promise containing the list.
 */
declare function pidtree(
  pid: string | number,
  options: PidTree.Options & {advanced: true}
): Promise<PidTree.AdvancedResult[]>;

export = pidtree;


code:
'use strict';

function pify(fn, arg1, arg2) {
  return new Promise(function(resolve, reject) {
    fn(arg1, arg2, function(err, data) {
      if (err) return reject(err);
      resolve(data);
    });
  });
}

// Node versions prior to 4.0.0 do not define have `startsWith`.
/* istanbul ignore if */
if (!String.prototype.startsWith) {
  // eslint-disable-next-line no-extend-native
  String.prototype.startsWith = function(suffix) {
    return this.substring(0, suffix.length) === suffix;
  };
}

var pidtree = require('./lib/pidtree');

/**
 * Get the list of children pids of the given pid.
 * @public
 * @param  {Number|String} pid A PID. If -1 will return all the pids.
 * @param  {Object} [options] Optional options object.
 * @param  {Boolean} [options.root=false] Include the provided PID in the list.
 * @param  {Boolean} [options.advanced=false] Returns a list of objects in the
 * format {pid: X, ppid: Y}.
 * @param  {Function} [callback=undefined] Called when the list is ready. If not
 * provided a promise is returned instead.
 * @returns  {Promise.<Object[]>} Only when the callback is not provided.
 */
function list(pid, options, callback) {
  if (typeof options === 'function') {
    callback = options;
    options = undefined;
  }

  if (typeof callback === 'function') {
    pidtree(pid, options, callback);
    return;
  }

  return pify(pidtree, pid, options);
}

module.exports = list;


code:
'use strict';

var spawn = require('child_process').spawn;

function stripStderr(stderr) {
  if (!stderr) return;
  stderr = stderr.trim();
  // Strip bogus screen size error.
  // See https://github.com/microsoft/vscode/issues/98590
  var regex = /your \d+x\d+ screen size is bogus\. expect trouble/gi;
  stderr = stderr.replace(regex, '');

  return stderr.trim();
}

/**
 * Spawn a binary and read its stdout.
 * @param  {String} cmd The name of the binary to spawn.
 * @param  {String[]} args The arguments for the binary.
 * @param  {Object} [options] Optional option for the spawn function.
 * @param  {Function} done(err, stdout)
 */
function run(cmd, args, options, done) {
  if (typeof options === 'function') {
    done = options;
    options = undefined;
  }

  var executed = false;
  var ch = spawn(cmd, args, options);
  var stdout = '';
  var stderr = '';

  ch.stdout.on('data', function(d) {
    stdout += d.toString();
  });

  ch.stderr.on('data', function(d) {
    stderr += d.toString();
  });

  ch.on('error', function(err) {
    if (executed) return;
    executed = true;
    done(new Error(err));
  });

  ch.on('close', function(code) {
    if (executed) return;
    executed = true;

    stderr = stripStderr(stderr);
    if (stderr) {
      return done(new Error(stderr));
    }

    done(null, stdout, code);
  });
}

module.exports = run;


code:
'use strict';

var os = require('os');

var platformToMethod = {
  darwin: 'ps',
  sunos: 'ps',
  freebsd: 'ps',
  netbsd: 'ps',
  win: 'wmic',
  linux: 'ps',
  aix: 'ps',
};

var methodToRequireFn = {
  ps: () => require("./ps"),
  wmic: () => require("./wmic")
};

var platform = os.platform();
if (platform.startsWith('win')) {
  platform = 'win';
}

var method = platformToMethod[platform];

/**
 * Gets the list of all the pids of the system.
 * @param  {Function} callback Called when the list is ready.
 */
function get(callback) {
  if (method === undefined) {
    callback(
      new Error(
        os.platform() +
          ' is not supported yet, please open an issue (https://github.com/simonepri/pidtree)'
      )
    );
  }

  var list = methodToRequireFn[method]();
  list(callback);
}

module.exports = get;


code:
'use strict';

var getAll = require('./get');

/**
 * Get the list of children and grandchildren pids of the given PID.
 * @param  {Number|String} PID A PID. If -1 will return all the pids.
 * @param  {Object} [options] Optional options object.
 * @param  {Boolean} [options.root=false] Include the provided PID in the list.
 * @param  {Boolean} [options.advanced=false] Returns a list of objects in the
 * format {pid: X, ppid: Y}.
 * @param  {Function} callback(err, list) Called when the list is ready.
 */
function list(PID, options, callback) {
  if (typeof options === 'function') {
    callback = options;
    options = {};
  }

  if (typeof options !== 'object') {
    options = {};
  }

  PID = parseInt(PID, 10);
  if (isNaN(PID) || PID < -1) {
    callback(new TypeError('The pid provided is invalid'));
    return;
  }

  getAll(function(err, list) {
    if (err) {
      callback(err);
      return;
    }

    // If the user wants the whole list just return it
    if (PID === -1) {
      for (var i = 0; i < list.length; i++) {
        list[i] = options.advanced
          ? {ppid: list[i][0], pid: list[i][1]}
          : (list[i] = list[i][1]);
      }

      callback(null, list);
      return;
    }

    var root;
    for (var l = 0; l < list.length; l++) {
      if (list[l][1] === PID) {
        root = options.advanced ? {ppid: list[l][0], pid: PID} : PID;
        break;
      }

      if (list[l][0] === PID) {
        root = options.advanced ? {pid: PID} : PID; // Special pids like 0 on *nix
      }
    }

    if (!root) {
      callback(new Error('No matching pid found'));
      return;
    }

    // Build the adiacency Hash Map (pid -> [children of pid])
    var tree = {};
    while (list.length > 0) {
      var element = list.pop();
      if (tree[element[0]]) {
        tree[element[0]].push(element[1]);
      } else {
        tree[element[0]] = [element[1]];
      }
    }

    // Starting by the PID provided by the user, traverse the tree using the
    // adiacency Hash Map until the whole subtree is visited.
    // Each pid encountered while visiting is added to the pids array.
    var idx = 0;
    var pids = [root];
    while (idx < pids.length) {
      var curpid = options.advanced ? pids[idx++].pid : pids[idx++];
      if (!tree[curpid]) continue;
      var length = tree[curpid].length;
      for (var j = 0; j < length; j++) {
        pids.push(
          options.advanced
            ? {ppid: curpid, pid: tree[curpid][j]}
            : tree[curpid][j]
        );
      }

      delete tree[curpid];
    }

    if (!options.root) {
      pids.shift(); // Remove root
    }

    callback(null, pids);
  });
}

module.exports = list;


code:
'use strict';

var os = require('os');
var bin = require('./bin');

/**
 * Gets the list of all the pids of the system through the ps command.
 * @param  {Function} callback(err, list)
 */
function ps(callback) {
  var args = ['-A', '-o', 'ppid,pid'];

  bin('ps', args, function(err, stdout, code) {
    if (err) return callback(err);
    if (code !== 0) {
      return callback(new Error('pidtree ps command exited with code ' + code));
    }

    // Example of stdout
    //
    // PPID   PID
    //    1   430
    //  430   432
    //    1   727
    //    1  7166

    try {
      stdout = stdout.split(os.EOL);

      var list = [];
      for (var i = 1; i < stdout.length; i++) {
        stdout[i] = stdout[i].trim();
        if (!stdout[i]) continue;
        stdout[i] = stdout[i].split(/\s+/);
        stdout[i][0] = parseInt(stdout[i][0], 10); // PPID
        stdout[i][1] = parseInt(stdout[i][1], 10); // PID
        list.push(stdout[i]);
      }

      callback(null, list);
    } catch (error) {
      callback(error);
    }
  });
}

module.exports = ps;


code:
'use strict';

var os = require('os');
var bin = require('./bin');

/**
 * Gets the list of all the pids of the system through the wmic command.
 * @param  {Function} callback(err, list)
 */
function wmic(callback) {
  var args = ['PROCESS', 'get', 'ParentProcessId,ProcessId'];
  var options = {windowsHide: true, windowsVerbatimArguments: true};
  bin('wmic', args, options, function(err, stdout, code) {
    if (err) {
      callback(err);
      return;
    }

    if (code !== 0) {
      callback(new Error('pidtree wmic command exited with code ' + code));
      return;
    }

    // Example of stdout
    //
    // ParentProcessId  ProcessId
    // 0                777

    try {
      stdout = stdout.split(os.EOL);

      var list = [];
      for (var i = 1; i < stdout.length; i++) {
        stdout[i] = stdout[i].trim();
        if (!stdout[i]) continue;
        stdout[i] = stdout[i].split(/\s+/);
        stdout[i][0] = parseInt(stdout[i][0], 10); // PPID
        stdout[i][1] = parseInt(stdout[i][1], 10); // PID
        list.push(stdout[i]);
      }

      callback(null, list);
    } catch (error) {
      callback(error);
    }
  });
}

module.exports = wmic;


pidtree

description: Cross platform children list of a PID

author: Simone Primarosa <simonepri@outlook.com> (https://github.com/simonepri)

keywords: ps-tree ps tree ppid pid pidtree pgrep list all system process processes

start: node ./bin/pidtree.js

update: npm-check -u

release: np

lint: xo

test: nyc ava -m "!*benchmark*"

test:windows: ava -m "!*benchmark*"

types: tsd

bench: ava -m "*benchmark*"

reporter: lcovonly text


code:
  pidtree

  🚸 Cross platform children list of a PID.

    Coded with ❤ by Simone Primarosa.

## Synopsis

This package is really similar to [ps-tree][gh:ps-tree] but is faster, safer and
provides sub-children results.
Furthermore ps-tree is [unmaintained][gh:ps-tree-um].

Uuh, and a fancy [CLI](#cli) is also available!

## Usage

```js
var pidtree = require('pidtree')

// Get childs of current process
pidtree(process.pid, function (err, pids) {
  console.log(pids)
  // => []
})

// Include the given pid in the result array
pidtree(process.pid, {root: true}, function (err, pids) {
  console.log(pids)
  // => [727]
})

// Get all the processes of the System (-1 is a special value of this package)
pidtree(-1, function (err, pids) {
  console.log(pids)
  // => [530, 42, ..., 41241]
})

// Include PPID in the results
pidtree(1, {advanced: true}, function (err, pids) {
  console.log(pids)
  // => [{ppid: 1, pid: 530}, {ppid: 1, pid: 42}, ..., {ppid: 1, pid: 41241}]
})

// If no callback is given it returns a promise instead
const pids = await pidtree(1)
console.log(pids)
// => [141, 42, ..., 15242]
```

## Compatibility

| Linux | FreeBSD | NetBSD | SunOS | macOS | Win | AIX |
| --- | --- | --- | --- | --- | --- | --- |
| ✅ | ❓ | ❓ | ❓ | ✅ | ✅ | ❓ |

✅ = Working
❓ = Not tested but should work

Please if your platform is not supported [file an issue][new issue].

## CLI

Show a tree of the processes inside your system inside your terminal.

```bash
npx pidtree $PPID
```
Just replace `$PPID` with one of the pids inside your system.

Or don't pass anything if you want all the pids inside your system.

```bash
npx pidtree
```

To display the output as a list, similar to the one produced from `pgrep -P $PID`,
pass the `--list` flag.

```bash
npx pidtree --list
```

## API

## pidtree(pid, [options], [callback]) ⇒ [Promise.<Array.<Object>>]
Get the list of children pids of the given pid.

**Kind**: global function
**Returns**: Promise.<Array.<Object>> - Only when the callback is not provided.
**Access**: public

| Param | Type | Default | Description |
| --- | --- | --- | --- |
| pid | Number \| String |  | A pid. If -1 will return all the pids. |
| [options] | Object |  | Optional options object. |
| [options.root] | Boolean | false | Include the provided pid in the list. Ignored if -1 is passed as pid. |
| [callback] | function |  | Called when the list is ready. If not provided a promise is returned instead. |

## Related

- [pidusage][gh:pidusage] -
Cross-platform process cpu % and memory usage of a PID

## Authors

- **Simone Primarosa** - [simonepri][github:simonepri]

See also the list of [contributors][contributors] who participated in this project.

## License

This project is licensed under the MIT License - see the [license][license] file for details.

[new issue]: https://github.com/simonepri/pidtree/issues/new
[license]: https://github.com/simonepri/pidtree/tree/master/license
[contributors]: https://github.com/simonepri/pidtree/contributors

[github:simonepri]: https://github.com/simonepri

[gh:pidusage]: https://github.com/soyuka/pidusage
[gh:ps-tree]: https://github.com/indexzero/ps-tree
[gh:ps-tree-um]: https://github.com/indexzero/ps-tree/issues/30


code:
declare const pkgDir: {
	/**
	Find the root directory of a Node.js project or npm package.

	@param cwd - Directory to start from. Default: `process.cwd()`.
	@returns The project root path or `undefined` if it couldn't be found.

	@example
	```
	// /
	// └── Users
	//     └── sindresorhus
	//         └── foo
	//             ├── package.json
	//             └── bar
	//                 ├── baz
	//                 └── example.js

	// example.js
	import pkgDir = require('pkg-dir');

	(async () => {
		const rootDir = await pkgDir(__dirname);

		console.log(rootDir);
		//=> '/Users/sindresorhus/foo'
	})();
	```
	*/
	(cwd?: string): Promise<string | undefined>;

	/**
	Synchronously find the root directory of a Node.js project or npm package.

	@param cwd - Directory to start from. Default: `process.cwd()`.
	@returns The project root path or `undefined` if it couldn't be found.
	*/
	sync(cwd?: string): string | undefined;

	// TODO: Remove this for the next major release
	default: typeof pkgDir;
};

export = pkgDir;


code:
'use strict';
const path = require('path');
const findUp = require('find-up');

const pkgDir = async cwd => {
	const filePath = await findUp('package.json', {cwd});
	return filePath && path.dirname(filePath);
};

module.exports = pkgDir;
// TODO: Remove this for the next major release
module.exports.default = pkgDir;

module.exports.sync = cwd => {
	const filePath = findUp.sync('package.json', {cwd});
	return filePath && path.dirname(filePath);
};


code:
import {Options as LocatePathOptions} from 'locate-path';

declare const stop: unique symbol;

declare namespace findUp {
	interface Options extends LocatePathOptions {}

	type StopSymbol = typeof stop;

	type Match = string | StopSymbol | undefined;
}

declare const findUp: {
	/**
	Find a file or directory by walking up parent directories.

	@param name - Name of the file or directory to find. Can be multiple.
	@returns The first path found (by respecting the order of `name`s) or `undefined` if none could be found.

	@example
	```
	// /
	// └── Users
	//     └── sindresorhus
	//         ├── unicorn.png
	//         └── foo
	//             └── bar
	//                 ├── baz
	//                 └── example.js

	// example.js
	import findUp = require('find-up');

	(async () => {
		console.log(await findUp('unicorn.png'));
		//=> '/Users/sindresorhus/unicorn.png'

		console.log(await findUp(['rainbow.png', 'unicorn.png']));
		//=> '/Users/sindresorhus/unicorn.png'
	})();
	```
	*/
	(name: string | string[], options?: findUp.Options): Promise<string | undefined>;

	/**
	Find a file or directory by walking up parent directories.

	@param matcher - Called for each directory in the search. Return a path or `findUp.stop` to stop the search.
	@returns The first path found or `undefined` if none could be found.

	@example
	```
	import path = require('path');
	import findUp = require('find-up');

	(async () => {
		console.log(await findUp(async directory => {
			const hasUnicorns = await findUp.exists(path.join(directory, 'unicorn.png'));
			return hasUnicorns && directory;
		}, {type: 'directory'}));
		//=> '/Users/sindresorhus'
	})();
	```
	*/
	(matcher: (directory: string) => (findUp.Match | Promise<findUp.Match>), options?: findUp.Options): Promise<string | undefined>;

	sync: {
		/**
		Synchronously find a file or directory by walking up parent directories.

		@param name - Name of the file or directory to find. Can be multiple.
		@returns The first path found (by respecting the order of `name`s) or `undefined` if none could be found.
		*/
		(name: string | string[], options?: findUp.Options): string | undefined;

		/**
		Synchronously find a file or directory by walking up parent directories.

		@param matcher - Called for each directory in the search. Return a path or `findUp.stop` to stop the search.
		@returns The first path found or `undefined` if none could be found.

		@example
		```
		import path = require('path');
		import findUp = require('find-up');

		console.log(findUp.sync(directory => {
			const hasUnicorns = findUp.sync.exists(path.join(directory, 'unicorn.png'));
			return hasUnicorns && directory;
		}, {type: 'directory'}));
		//=> '/Users/sindresorhus'
		```
		*/
		(matcher: (directory: string) => findUp.Match, options?: findUp.Options): string | undefined;

		/**
		Synchronously check if a path exists.

		@param path - Path to the file or directory.
		@returns Whether the path exists.

		@example
		```
		import findUp = require('find-up');

		console.log(findUp.sync.exists('/Users/sindresorhus/unicorn.png'));
		//=> true
		```
		*/
		exists(path: string): boolean;
	}

	/**
	Check if a path exists.

	@param path - Path to a file or directory.
	@returns Whether the path exists.

	@example
	```
	import findUp = require('find-up');

	(async () => {
		console.log(await findUp.exists('/Users/sindresorhus/unicorn.png'));
		//=> true
	})();
	```
	*/
	exists(path: string): Promise<boolean>;

	/**
	Return this in a `matcher` function to stop the search and force `findUp` to immediately return `undefined`.
	*/
	readonly stop: findUp.StopSymbol;
};

export = findUp;


code:
'use strict';
const path = require('path');
const locatePath = require('locate-path');
const pathExists = require('path-exists');

const stop = Symbol('findUp.stop');

module.exports = async (name, options = {}) => {
	let directory = path.resolve(options.cwd || '');
	const {root} = path.parse(directory);
	const paths = [].concat(name);

	const runMatcher = async locateOptions => {
		if (typeof name !== 'function') {
			return locatePath(paths, locateOptions);
		}

		const foundPath = await name(locateOptions.cwd);
		if (typeof foundPath === 'string') {
			return locatePath([foundPath], locateOptions);
		}

		return foundPath;
	};

	// eslint-disable-next-line no-constant-condition
	while (true) {
		// eslint-disable-next-line no-await-in-loop
		const foundPath = await runMatcher({...options, cwd: directory});

		if (foundPath === stop) {
			return;
		}

		if (foundPath) {
			return path.resolve(directory, foundPath);
		}

		if (directory === root) {
			return;
		}

		directory = path.dirname(directory);
	}
};

module.exports.sync = (name, options = {}) => {
	let directory = path.resolve(options.cwd || '');
	const {root} = path.parse(directory);
	const paths = [].concat(name);

	const runMatcher = locateOptions => {
		if (typeof name !== 'function') {
			return locatePath.sync(paths, locateOptions);
		}

		const foundPath = name(locateOptions.cwd);
		if (typeof foundPath === 'string') {
			return locatePath.sync([foundPath], locateOptions);
		}

		return foundPath;
	};

	// eslint-disable-next-line no-constant-condition
	while (true) {
		const foundPath = runMatcher({...options, cwd: directory});

		if (foundPath === stop) {
			return;
		}

		if (foundPath) {
			return path.resolve(directory, foundPath);
		}

		if (directory === root) {
			return;
		}

		directory = path.dirname(directory);
	}
};

module.exports.exists = pathExists;

module.exports.sync.exists = pathExists.sync;

module.exports.stop = stop;


find-up

description: Find a file or directory by walking up parent directories

repository: sindresorhus/find-up

test: xo && ava && tsd

keywords: find up find-up findup look-up look file search match package resolve parent parents folder directory walk walking path


code:
# find-up [![Build Status](https://travis-ci.org/sindresorhus/find-up.svg?branch=master)](https://travis-ci.org/sindresorhus/find-up)

> Find a file or directory by walking up parent directories

## Install

```
$ npm install find-up
```

## Usage

```
/
└── Users
    └── sindresorhus
        ├── unicorn.png
        └── foo
            └── bar
                ├── baz
                └── example.js
```

`example.js`

```js
const path = require('path');
const findUp = require('find-up');

(async () => {
	console.log(await findUp('unicorn.png'));
	//=> '/Users/sindresorhus/unicorn.png'

	console.log(await findUp(['rainbow.png', 'unicorn.png']));
	//=> '/Users/sindresorhus/unicorn.png'

	console.log(await findUp(async directory => {
		const hasUnicorns = await findUp.exists(path.join(directory, 'unicorn.png'));
		return hasUnicorns && directory;
	}, {type: 'directory'}));
	//=> '/Users/sindresorhus'
})();
```

## API

### findUp(name, options?)
### findUp(matcher, options?)

Returns a `Promise` for either the path or `undefined` if it couldn't be found.

### findUp([...name], options?)

Returns a `Promise` for either the first path found (by respecting the order of the array) or `undefined` if none could be found.

### findUp.sync(name, options?)
### findUp.sync(matcher, options?)

Returns a path or `undefined` if it couldn't be found.

### findUp.sync([...name], options?)

Returns the first path found (by respecting the order of the array) or `undefined` if none could be found.

#### name

Type: `string`

Name of the file or directory to find.

#### matcher

Type: `Function`

A function that will be called with each directory until it returns a `string` with the path, which stops the search, or the root directory has been reached and nothing was found. Useful if you want to match files with certain patterns, set of permissions, or other advanced use-cases.

When using async mode, the `matcher` may optionally be an async or promise-returning function that returns the path.

#### options

Type: `object`

##### cwd

Type: `string`

Default: `process.cwd()`

Directory to start from.

##### type

Type: `string`

Default: `'file'`

Values: `'file'` `'directory'`

The type of paths that can match.

##### allowSymlinks

Type: `boolean`

Default: `true`

Allow symbolic links to match if they point to the chosen path type.

### findUp.exists(path)

Returns a `Promise<boolean>` of whether the path exists.

### findUp.sync.exists(path)

Returns a `boolean` of whether the path exists.

#### path

Type: `string`

Path to a file or directory.

### findUp.stop

A [`Symbol`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) that can be returned by a `matcher` function to stop the search and cause `findUp` to immediately return `undefined`. Useful as a performance optimization in case the current working directory is deeply nested in the filesystem.

```js
const path = require('path');
const findUp = require('find-up');

(async () => {
	await findUp(directory => {
		return path.basename(directory) === 'work' ? findUp.stop : 'logo.png';
	});
})();
```

## Related

- [find-up-cli](https://github.com/sindresorhus/find-up-cli) - CLI for this module
- [pkg-up](https://github.com/sindresorhus/pkg-up) - Find the closest package.json file
- [pkg-dir](https://github.com/sindresorhus/pkg-dir) - Find the root directory of an npm package
- [resolve-from](https://github.com/sindresorhus/resolve-from) - Resolve the path of a module like `require.resolve()` but from a given path

---

		Get professional support for 'find-up' with a Tidelift subscription

		Tidelift helps make open source sustainable for maintainers while giving companies
assurances about security, maintenance, and licensing for their dependencies.


code:
declare namespace locatePath {
	interface Options {
		/**
		Current working directory.

		@default process.cwd()
		*/
		readonly cwd?: string;

		/**
		Type of path to match.

		@default 'file'
		*/
		readonly type?: 'file' | 'directory';

		/**
		Allow symbolic links to match if they point to the requested path type.

		@default true
		*/
		readonly allowSymlinks?: boolean;
	}

	interface AsyncOptions extends Options {
		/**
		Number of concurrently pending promises. Minimum: `1`.

		@default Infinity
		*/
		readonly concurrency?: number;

		/**
		Preserve `paths` order when searching.

		Disable this to improve performance if you don't care about the order.

		@default true
		*/
		readonly preserveOrder?: boolean;
	}
}

declare const locatePath: {
	/**
	Get the first path that exists on disk of multiple paths.

	@param paths - Paths to check.
	@returns The first path that exists or `undefined` if none exists.

	@example
	```
	import locatePath = require('locate-path');

	const files = [
		'unicorn.png',
		'rainbow.png', // Only this one actually exists on disk
		'pony.png'
	];

	(async () => {
		console(await locatePath(files));
		//=> 'rainbow'
	})();
	```
	*/
	(paths: Iterable<string>, options?: locatePath.AsyncOptions): Promise<
		string | undefined
	>;

	/**
	Synchronously get the first path that exists on disk of multiple paths.

	@param paths - Paths to check.
	@returns The first path that exists or `undefined` if none exists.
	*/
	sync(
		paths: Iterable<string>,
		options?: locatePath.Options
	): string | undefined;
};

export = locatePath;


code:
'use strict';
const path = require('path');
const fs = require('fs');
const {promisify} = require('util');
const pLocate = require('p-locate');

const fsStat = promisify(fs.stat);
const fsLStat = promisify(fs.lstat);

const typeMappings = {
	directory: 'isDirectory',
	file: 'isFile'
};

function checkType({type}) {
	if (type in typeMappings) {
		return;
	}

	throw new Error(`Invalid type specified: ${type}`);
}

const matchType = (type, stat) => type === undefined || stat[typeMappings[type]]();

module.exports = async (paths, options) => {
	options = {
		cwd: process.cwd(),
		type: 'file',
		allowSymlinks: true,
		...options
	};
	checkType(options);
	const statFn = options.allowSymlinks ? fsStat : fsLStat;

	return pLocate(paths, async path_ => {
		try {
			const stat = await statFn(path.resolve(options.cwd, path_));
			return matchType(options.type, stat);
		} catch (_) {
			return false;
		}
	}, options);
};

module.exports.sync = (paths, options) => {
	options = {
		cwd: process.cwd(),
		allowSymlinks: true,
		type: 'file',
		...options
	};
	checkType(options);
	const statFn = options.allowSymlinks ? fs.statSync : fs.lstatSync;

	for (const path_ of paths) {
		try {
			const stat = statFn(path.resolve(options.cwd, path_));

			if (matchType(options.type, stat)) {
				return path_;
			}
		} catch (_) {
		}
	}
};


locate-path

description: Get the first path that exists on disk of multiple paths

repository: sindresorhus/locate-path

keywords: locate path paths file files exists find finder search searcher array iterable iterator


code:
# locate-path [![Build Status](https://travis-ci.org/sindresorhus/locate-path.svg?branch=master)](https://travis-ci.org/sindresorhus/locate-path)

> Get the first path that exists on disk of multiple paths

## Install

```
$ npm install locate-path
```

## Usage

Here we find the first file that exists on disk, in array order.

```js
const locatePath = require('locate-path');

const files = [
	'unicorn.png',
	'rainbow.png', // Only this one actually exists on disk
	'pony.png'
];

(async () => {
	console(await locatePath(files));
	//=> 'rainbow'
})();
```

## API

### locatePath(paths, [options])

Returns a `Promise<string>` for the first path that exists or `undefined` if none exists.

#### paths

Type: `Iterable<string>`

Paths to check.

#### options

Type: `Object`

##### concurrency

Type: `number`

Default: `Infinity`

Minimum: `1`

Number of concurrently pending promises.

##### preserveOrder

Type: `boolean`

Default: `true`

Preserve `paths` order when searching.

Disable this to improve performance if you don't care about the order.

##### cwd

Type: `string`

Default: `process.cwd()`

Current working directory.

##### type

Type: `string`

Default: `file`

Values: `file` `directory`

The type of paths that can match.

##### allowSymlinks

Type: `boolean`

Default: `true`

Allow symbolic links to match if they point to the chosen path type.

### locatePath.sync(paths, [options])

Returns the first path that exists or `undefined` if none exists.

#### paths

Type: `Iterable<string>`

Paths to check.

#### options

Type: `Object`

##### cwd

Same as above.

##### type

Same as above.

##### allowSymlinks

Same as above.

## Related

- [path-exists](https://github.com/sindresorhus/path-exists) - Check if a path exists

## License

MIT © [Sindre Sorhus](https://sindresorhus.com)


code:
export interface Limit {
	/**
	@param fn - Promise-returning/async function.
	@param arguments - Any arguments to pass through to `fn`. Support for passing arguments on to the `fn` is provided in order to be able to avoid creating unnecessary closures. You probably don't need this optimization unless you're pushing a lot of functions.
	@returns The promise returned by calling `fn(...arguments)`.
	*/
	<Arguments extends unknown[], ReturnType>(
		fn: (...arguments: Arguments) => PromiseLike<ReturnType> | ReturnType,
		...arguments: Arguments
	): Promise<ReturnType>;

	/**
	The number of promises that are currently running.
	*/
	readonly activeCount: number;

	/**
	The number of promises that are waiting to run (i.e. their internal `fn` was not called yet).
	*/
	readonly pendingCount: number;

	/**
	Discard pending promises that are waiting to run.

	This might be useful if you want to teardown the queue at the end of your program's lifecycle or discard any function calls referencing an intermediary state of your app.

	Note: This does not cancel promises that are already running.
	*/
	clearQueue(): void;
}

/**
Run multiple promise-returning & async functions with limited concurrency.

@param concurrency - Concurrency limit. Minimum: `1`.
@returns A `limit` function.
*/
export default function pLimit(concurrency: number): Limit;


code:
'use strict';
const pTry = require('p-try');

const pLimit = concurrency => {
	if (!((Number.isInteger(concurrency) || concurrency === Infinity) && concurrency > 0)) {
		return Promise.reject(new TypeError('Expected `concurrency` to be a number from 1 and up'));
	}

	const queue = [];
	let activeCount = 0;

	const next = () => {
		activeCount--;

		if (queue.length > 0) {
			queue.shift()();
		}
	};

	const run = (fn, resolve, ...args) => {
		activeCount++;

		const result = pTry(fn, ...args);

		resolve(result);

		result.then(next, next);
	};

	const enqueue = (fn, resolve, ...args) => {
		if (activeCount < concurrency) {
			run(fn, resolve, ...args);
		} else {
			queue.push(run.bind(null, fn, resolve, ...args));
		}
	};

	const generator = (fn, ...args) => new Promise(resolve => enqueue(fn, resolve, ...args));
	Object.defineProperties(generator, {
		activeCount: {
			get: () => activeCount
		},
		pendingCount: {
			get: () => queue.length
		},
		clearQueue: {
			value: () => {
				queue.length = 0;
			}
		}
	});

	return generator;
};

module.exports = pLimit;
module.exports.default = pLimit;


p-limit

description: Run multiple promise-returning & async functions with limited concurrency

repository: sindresorhus/p-limit

test: xo && ava && tsd-check

keywords: promise limit limited concurrency throttle throat rate batch ratelimit task queue async await promises bluebird


code:
# p-limit [![Build Status](https://travis-ci.org/sindresorhus/p-limit.svg?branch=master)](https://travis-ci.org/sindresorhus/p-limit)

> Run multiple promise-returning & async functions with limited concurrency

## Install

```
$ npm install p-limit
```

## Usage

```js
const pLimit = require('p-limit');

const limit = pLimit(1);

const input = [
	limit(() => fetchSomething('foo')),
	limit(() => fetchSomething('bar')),
	limit(() => doSomething())
];

(async () => {
	// Only one promise is run at once
	const result = await Promise.all(input);
	console.log(result);
})();
```

## API

### pLimit(concurrency)

Returns a `limit` function.

#### concurrency

Type: `number`\
Minimum: `1`\
Default: `Infinity`

Concurrency limit.

### limit(fn, ...args)

Returns the promise returned by calling `fn(...args)`.

#### fn

Type: `Function`

Promise-returning/async function.

#### args

Any arguments to pass through to `fn`.

Support for passing arguments on to the `fn` is provided in order to be able to avoid creating unnecessary closures. You probably don't need this optimization unless you're pushing a *lot* of functions.

### limit.activeCount

The number of promises that are currently running.

### limit.pendingCount

The number of promises that are waiting to run (i.e. their internal `fn` was not called yet).

### limit.clearQueue()

Discard pending promises that are waiting to run.

This might be useful if you want to teardown the queue at the end of your program's lifecycle or discard any function calls referencing an intermediary state of your app.

Note: This does not cancel promises that are already running.

## FAQ

### How is this different from the [`p-queue`](https://github.com/sindresorhus/p-queue) package?

This package is only about limiting the number of concurrent executions, while `p-queue` is a fully featured queue implementation with lots of different options, introspection, and ability to pause the queue.

## Related

- [p-queue](https://github.com/sindresorhus/p-queue) - Promise queue with concurrency control
- [p-throttle](https://github.com/sindresorhus/p-throttle) - Throttle promise-returning & async functions
- [p-debounce](https://github.com/sindresorhus/p-debounce) - Debounce promise-returning & async functions
- [p-all](https://github.com/sindresorhus/p-all) - Run promise-returning & async functions concurrently with optional limited concurrency
- [More…](https://github.com/sindresorhus/promise-fun)

---

		Get professional support for this package with a Tidelift subscription

		Tidelift helps make open source sustainable for maintainers while giving companies
assurances about security, maintenance, and licensing for their dependencies.


code:
declare namespace pLocate {
	interface Options {
		/**
		Number of concurrently pending promises returned by `tester`. Minimum: `1`.

		@default Infinity
		*/
		readonly concurrency?: number;

		/**
		Preserve `input` order when searching.

		Disable this to improve performance if you don't care about the order.

		@default true
		*/
		readonly preserveOrder?: boolean;
	}
}

declare const pLocate: {
	/**
	Get the first fulfilled promise that satisfies the provided testing function.

	@param input - An iterable of promises/values to test.
	@param tester - This function will receive resolved values from `input` and is expected to return a `Promise<boolean>` or `boolean`.
	@returns A `Promise` that is fulfilled when `tester` resolves to `true` or the iterable is done, or rejects if any of the promises reject. The fulfilled value is the current iterable value or `undefined` if `tester` never resolved to `true`.

	@example
	```
	import pathExists = require('path-exists');
	import pLocate = require('p-locate');

	const files = [
		'unicorn.png',
		'rainbow.png', // Only this one actually exists on disk
		'pony.png'
	];

	(async () => {
		const foundPath = await pLocate(files, file => pathExists(file));

		console.log(foundPath);
		//=> 'rainbow'
	})();
	```
	*/
	<ValueType>(
		input: Iterable<PromiseLike<ValueType> | ValueType>,
		tester: (element: ValueType) => PromiseLike<boolean> | boolean,
		options?: pLocate.Options
	): Promise<ValueType | undefined>;

	// TODO: Remove this for the next major release, refactor the whole definition to:
	// declare function pLocate<ValueType>(
	// 	input: Iterable<PromiseLike<ValueType> | ValueType>,
	// 	tester: (element: ValueType) => PromiseLike<boolean> | boolean,
	// 	options?: pLocate.Options
	// ): Promise<ValueType | undefined>;
	// export = pLocate;
	default: typeof pLocate;
};

export = pLocate;


code:
'use strict';
const pLimit = require('p-limit');

class EndError extends Error {
	constructor(value) {
		super();
		this.value = value;
	}
}

// The input can also be a promise, so we await it
const testElement = async (element, tester) => tester(await element);

// The input can also be a promise, so we `Promise.all()` them both
const finder = async element => {
	const values = await Promise.all(element);
	if (values[1] === true) {
		throw new EndError(values[0]);
	}

	return false;
};

const pLocate = async (iterable, tester, options) => {
	options = {
		concurrency: Infinity,
		preserveOrder: true,
		...options
	};

	const limit = pLimit(options.concurrency);

	// Start all the promises concurrently with optional limit
	const items = [...iterable].map(element => [element, limit(testElement, element, tester)]);

	// Check the promises either serially or concurrently
	const checkLimit = pLimit(options.preserveOrder ? 1 : Infinity);

	try {
		await Promise.all(items.map(element => checkLimit(finder, element)));
	} catch (error) {
		if (error instanceof EndError) {
			return error.value;
		}

		throw error;
	}
};

module.exports = pLocate;
// TODO: Remove this for the next major release
module.exports.default = pLocate;


p-locate

description: Get the first fulfilled promise that satisfies the provided testing function

repository: sindresorhus/p-locate

keywords: promise locate find finder search searcher test array collection iterable iterator race fulfilled fastest async await promises bluebird


code:
# p-locate [![Build Status](https://travis-ci.org/sindresorhus/p-locate.svg?branch=master)](https://travis-ci.org/sindresorhus/p-locate)

> Get the first fulfilled promise that satisfies the provided testing function

Think of it like an async version of [`Array#find`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/find).

## Install

```
$ npm install p-locate
```

## Usage

Here we find the first file that exists on disk, in array order.

```js
const pathExists = require('path-exists');
const pLocate = require('p-locate');

const files = [
	'unicorn.png',
	'rainbow.png', // Only this one actually exists on disk
	'pony.png'
];

(async () => {
	const foundPath = await pLocate(files, file => pathExists(file));

	console.log(foundPath);
	//=> 'rainbow'
})();
```

*The above is just an example. Use [`locate-path`](https://github.com/sindresorhus/locate-path) if you need this.*

## API

### pLocate(input, tester, [options])

Returns a `Promise` that is fulfilled when `tester` resolves to `true` or the iterable is done, or rejects if any of the promises reject. The fulfilled value is the current iterable value or `undefined` if `tester` never resolved to `true`.

#### input

Type: `Iterable<Promise | unknown>`

An iterable of promises/values to test.

#### tester(element)

Type: `Function`

This function will receive resolved values from `input` and is expected to return a `Promise<boolean>` or `boolean`.

#### options

Type: `Object`

##### concurrency

Type: `number`

Default: `Infinity`

Minimum: `1`

Number of concurrently pending promises returned by `tester`.

##### preserveOrder

Type: `boolean`

Default: `true`

Preserve `input` order when searching.

Disable this to improve performance if you don't care about the order.

## Related

- [p-map](https://github.com/sindresorhus/p-map) - Map over promises concurrently
- [p-filter](https://github.com/sindresorhus/p-filter) - Filter promises concurrently
- [p-any](https://github.com/sindresorhus/p-any) - Wait for any promise to be fulfilled
- [More…](https://github.com/sindresorhus/promise-fun)

## License

MIT © [Sindre Sorhus](https://sindresorhus.com)


pkg-dir

description: Find the root directory of a Node.js project or npm package

repository: sindresorhus/pkg-dir

keywords: package json root npm entry find up find-up findup look-up look file search match resolve parent parents folder directory dir walk walking path


code:
# pkg-dir [![Build Status](https://travis-ci.org/sindresorhus/pkg-dir.svg?branch=master)](https://travis-ci.org/sindresorhus/pkg-dir)

> Find the root directory of a Node.js project or npm package

## Install

```
$ npm install pkg-dir
```

## Usage

```
/
└── Users
    └── sindresorhus
        └── foo
            ├── package.json
            └── bar
                ├── baz
                └── example.js
```

```js
// example.js
const pkgDir = require('pkg-dir');

(async () => {
	const rootDir = await pkgDir(__dirname);

	console.log(rootDir);
	//=> '/Users/sindresorhus/foo'
})();
```

## API

### pkgDir([cwd])

Returns a `Promise` for either the project root path or `undefined` if it couldn't be found.

### pkgDir.sync([cwd])

Returns the project root path or `undefined` if it couldn't be found.

#### cwd

Type: `string`<br>
Default: `process.cwd()`

Directory to start from.

## Related

- [pkg-dir-cli](https://github.com/sindresorhus/pkg-dir-cli) - CLI for this module
- [pkg-up](https://github.com/sindresorhus/pkg-up) - Find the closest package.json file
- [find-up](https://github.com/sindresorhus/find-up) - Find a file by walking up parent directories

## License

MIT © [Sindre Sorhus](https://sindresorhus.com)


code:
# node-portfinder [![CI](https://github.com/http-party/node-portfinder/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/http-party/node-portfinder/actions/workflows/ci.yml)

## Installation

``` bash
  $ npm install portfinder
```

## Usage
The `portfinder` module has a simple interface:

``` js
  var portfinder = require('portfinder');

  portfinder.getPort(function (err, port) {
    //
    // `port` is guaranteed to be a free port
    // in this scope.
    //
  });
```

Or with promise (if `Promise`s are supported) :

``` js
  const portfinder = require('portfinder');

  portfinder.getPortPromise()
    .then((port) => {
        //
        // `port` is guaranteed to be a free port
        // in this scope.
        //
    })
    .catch((err) => {
        //
        // Could not get a free port, `err` contains the reason.
        //
    });
```

If `portfinder.getPortPromise()` is called on a Node version without Promise (<4), it will throw an Error unless [Bluebird](http://bluebirdjs.com/docs/getting-started.html) or any Promise pollyfill is used.

### Ports search scope

By default `portfinder` will start searching from `8000` and scan until maximum port number (`65535`) is reached.

You can change this globally by setting:

```js
portfinder.setBasePort(3000);    // default: 8000
portfinder.setHighestPort(3333); // default: 65535
```

or by passing optional options object on each invocation:

```js
portfinder.getPort({
    port: 3000,    // minimum port
    stopPort: 3333 // maximum port
}, callback);
```

## Run Tests
``` bash
  $ npm test
```

#### Author: [Charlie Robbins][0]
#### Author/Maintainer: [Erik Trom][1]
#### License: MIT/X11
[0]: http://nodejitsu.com
[1]: https://github.com/eriktrom


code:
/**
 * portfinder.js typescript definitions.
 *
 * (C) 2011, Charlie Robbins
 */

type PortfinderCallback = (err: Error, port: number) => void;

interface PortFinderOptions {
  /**
   * Host to find available port on.
   */
  host?: string;
  /**
   * search start port (equals to port when not provided)
   * This exists because getPort and getPortPromise mutates port state in
   * recursive calls and doesn't have a way to retrieve begininng port while
   * searching.
   */
  startPort?: number;
  /**
   * Minimum port (takes precedence over `basePort`).
   */
  port?: number;
  /**
   * Maximum port
   */
  stopPort?: number;
}

/**
 * The lowest port to begin any port search from.
 */
export let basePort: number;

/**
 * Set the lowest port to begin any port search from.
 */
export function setBasePort(port: number): void;

/**
 * The highest port to end any port search from.
 */
export let highestPort: number;

/**
 * Set the higheset port to end any port search from.
 */
export function setHighestPort(port: number): void;

/**
 * Responds with a unbound port on the current machine.
 */
export function getPort(callback: PortfinderCallback): void;
export function getPort(options: PortFinderOptions, callback: PortfinderCallback): void;

export function getPorts(count: number, options: PortFinderOptions, callback: (err: Error, ports: Array<number>) => void): void;

/**
 * Responds a promise of an unbound port on the current machine.
 */
export function getPortPromise(options?: PortFinderOptions): Promise<number>;