| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618 | // A simple implementation of make-arrayfunction makeArray (subject) {  return Array.isArray(subject)    ? subject    : [subject]}const EMPTY = ''const SPACE = ' 'const ESCAPE = '\\'const REGEX_TEST_BLANK_LINE = /^\s+$/const REGEX_INVALID_TRAILING_BACKSLASH = /(?:[^\\]|^)\\$/const REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION = /^\\!/const REGEX_REPLACE_LEADING_EXCAPED_HASH = /^\\#/const REGEX_SPLITALL_CRLF = /\r?\n/g// /foo,// ./foo,// ../foo,// .// ..const REGEX_TEST_INVALID_PATH = /^\.*\/|^\.+$/const SLASH = '/'// Do not use ternary expression here, since "istanbul ignore next" is buggylet TMP_KEY_IGNORE = 'node-ignore'/* istanbul ignore else */if (typeof Symbol !== 'undefined') {  TMP_KEY_IGNORE = Symbol.for('node-ignore')}const KEY_IGNORE = TMP_KEY_IGNOREconst define = (object, key, value) =>  Object.defineProperty(object, key, {value})const REGEX_REGEXP_RANGE = /([0-z])-([0-z])/gconst RETURN_FALSE = () => false// Sanitize the range of a regular expression// The cases are complicated, see test cases for detailsconst sanitizeRange = range => range.replace(  REGEX_REGEXP_RANGE,  (match, from, to) => from.charCodeAt(0) <= to.charCodeAt(0)    ? match    // Invalid range (out of order) which is ok for gitignore rules but    //   fatal for JavaScript regular expression, so eliminate it.    : EMPTY)// See fixtures #59const cleanRangeBackSlash = slashes => {  const {length} = slashes  return slashes.slice(0, length - length % 2)}// > If the pattern ends with a slash,// > it is removed for the purpose of the following description,// > but it would only find a match with a directory.// > In other words, foo/ will match a directory foo and paths underneath it,// > but will not match a regular file or a symbolic link foo// >  (this is consistent with the way how pathspec works in general in Git).// '`foo/`' will not match regular file '`foo`' or symbolic link '`foo`'// -> ignore-rules will not deal with it, because it costs extra `fs.stat` call//      you could use option `mark: true` with `glob`// '`foo/`' should not continue with the '`..`'const REPLACERS = [  // > Trailing spaces are ignored unless they are quoted with backslash ("\")  [    // (a\ ) -> (a )    // (a  ) -> (a)    // (a \ ) -> (a  )    /\\?\s+$/,    match => match.indexOf('\\') === 0      ? SPACE      : EMPTY  ],  // replace (\ ) with ' '  [    /\\\s/g,    () => SPACE  ],  // Escape metacharacters  // which is written down by users but means special for regular expressions.  // > There are 12 characters with special meanings:  // > - the backslash \,  // > - the caret ^,  // > - the dollar sign $,  // > - the period or dot .,  // > - the vertical bar or pipe symbol |,  // > - the question mark ?,  // > - the asterisk or star *,  // > - the plus sign +,  // > - the opening parenthesis (,  // > - the closing parenthesis ),  // > - and the opening square bracket [,  // > - the opening curly brace {,  // > These special characters are often called "metacharacters".  [    /[\\$.|*+(){^]/g,    match => `\\${match}`  ],  [    // > a question mark (?) matches a single character    /(?!\\)\?/g,    () => '[^/]'  ],  // leading slash  [    // > A leading slash matches the beginning of the pathname.    // > For example, "/*.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c".    // A leading slash matches the beginning of the pathname    /^\//,    () => '^'  ],  // replace special metacharacter slash after the leading slash  [    /\//g,    () => '\\/'  ],  [    // > A leading "**" followed by a slash means match in all directories.    // > For example, "**/foo" matches file or directory "foo" anywhere,    // > the same as pattern "foo".    // > "**/foo/bar" matches file or directory "bar" anywhere that is directly    // >   under directory "foo".    // Notice that the '*'s have been replaced as '\\*'    /^\^*\\\*\\\*\\\//,    // '**/foo' <-> 'foo'    () => '^(?:.*\\/)?'  ],  // starting  [    // there will be no leading '/'    //   (which has been replaced by section "leading slash")    // If starts with '**', adding a '^' to the regular expression also works    /^(?=[^^])/,    function startingReplacer () {      // If has a slash `/` at the beginning or middle      return !/\/(?!$)/.test(this)        // > Prior to 2.22.1        // > If the pattern does not contain a slash /,        // >   Git treats it as a shell glob pattern        // Actually, if there is only a trailing slash,        //   git also treats it as a shell glob pattern        // After 2.22.1 (compatible but clearer)        // > If there is a separator at the beginning or middle (or both)        // > of the pattern, then the pattern is relative to the directory        // > level of the particular .gitignore file itself.        // > Otherwise the pattern may also match at any level below        // > the .gitignore level.        ? '(?:^|\\/)'        // > Otherwise, Git treats the pattern as a shell glob suitable for        // >   consumption by fnmatch(3)        : '^'    }  ],  // two globstars  [    // Use lookahead assertions so that we could match more than one `'/**'`    /\\\/\\\*\\\*(?=\\\/|$)/g,    // Zero, one or several directories    // should not use '*', or it will be replaced by the next replacer    // Check if it is not the last `'/**'`    (_, index, str) => index + 6 < str.length      // case: /**/      // > A slash followed by two consecutive asterisks then a slash matches      // >   zero or more directories.      // > For example, "a/**/b" matches "a/b", "a/x/b", "a/x/y/b" and so on.      // '/**/'      ? '(?:\\/[^\\/]+)*'      // case: /**      // > A trailing `"/**"` matches everything inside.      // #21: everything inside but it should not include the current folder      : '\\/.+'  ],  // normal intermediate wildcards  [    // Never replace escaped '*'    // ignore rule '\*' will match the path '*'    // 'abc.*/' -> go    // 'abc.*'  -> skip this rule,    //    coz trailing single wildcard will be handed by [trailing wildcard]    /(^|[^\\]+)(\\\*)+(?=.+)/g,    // '*.js' matches '.js'    // '*.js' doesn't match 'abc'    (_, p1, p2) => {      // 1.      // > An asterisk "*" matches anything except a slash.      // 2.      // > Other consecutive asterisks are considered regular asterisks      // > and will match according to the previous rules.      const unescaped = p2.replace(/\\\*/g, '[^\\/]*')      return p1 + unescaped    }  ],  [    // unescape, revert step 3 except for back slash    // For example, if a user escape a '\\*',    // after step 3, the result will be '\\\\\\*'    /\\\\\\(?=[$.|*+(){^])/g,    () => ESCAPE  ],  [    // '\\\\' -> '\\'    /\\\\/g,    () => ESCAPE  ],  [    // > The range notation, e.g. [a-zA-Z],    // > can be used to match one of the characters in a range.    // `\` is escaped by step 3    /(\\)?\[([^\]/]*?)(\\*)($|\])/g,    (match, leadEscape, range, endEscape, close) => leadEscape === ESCAPE      // '\\[bar]' -> '\\\\[bar\\]'      ? `\\[${range}${cleanRangeBackSlash(endEscape)}${close}`      : close === ']'        ? endEscape.length % 2 === 0          // A normal case, and it is a range notation          // '[bar]'          // '[bar\\\\]'          ? `[${sanitizeRange(range)}${endEscape}]`          // Invalid range notaton          // '[bar\\]' -> '[bar\\\\]'          : '[]'        : '[]'  ],  // ending  [    // 'js' will not match 'js.'    // 'ab' will not match 'abc'    /(?:[^*])$/,    // WTF!    // https://git-scm.com/docs/gitignore    // changes in [2.22.1](https://git-scm.com/docs/gitignore/2.22.1)    // which re-fixes #24, #38    // > If there is a separator at the end of the pattern then the pattern    // > will only match directories, otherwise the pattern can match both    // > files and directories.    // 'js*' will not match 'a.js'    // 'js/' will not match 'a.js'    // 'js' will match 'a.js' and 'a.js/'    match => /\/$/.test(match)      // foo/ will not match 'foo'      ? `${match}$`      // foo matches 'foo' and 'foo/'      : `${match}(?=$|\\/$)`  ],  // trailing wildcard  [    /(\^|\\\/)?\\\*$/,    (_, p1) => {      const prefix = p1        // '\^':        // '/*' does not match EMPTY        // '/*' does not match everything        // '\\\/':        // 'abc/*' does not match 'abc/'        ? `${p1}[^/]+`        // 'a*' matches 'a'        // 'a*' matches 'aa'        : '[^/]*'      return `${prefix}(?=$|\\/$)`    }  ],]// A simple cache, because an ignore rule only has only one certain meaningconst regexCache = Object.create(null)// @param {pattern}const makeRegex = (pattern, ignoreCase) => {  let source = regexCache[pattern]  if (!source) {    source = REPLACERS.reduce(      (prev, current) => prev.replace(current[0], current[1].bind(pattern)),      pattern    )    regexCache[pattern] = source  }  return ignoreCase    ? new RegExp(source, 'i')    : new RegExp(source)}const isString = subject => typeof subject === 'string'// > A blank line matches no files, so it can serve as a separator for readability.const checkPattern = pattern => pattern  && isString(pattern)  && !REGEX_TEST_BLANK_LINE.test(pattern)  && !REGEX_INVALID_TRAILING_BACKSLASH.test(pattern)  // > A line starting with # serves as a comment.  && pattern.indexOf('#') !== 0const splitPattern = pattern => pattern.split(REGEX_SPLITALL_CRLF)class IgnoreRule {  constructor (    origin,    pattern,    negative,    regex  ) {    this.origin = origin    this.pattern = pattern    this.negative = negative    this.regex = regex  }}const createRule = (pattern, ignoreCase) => {  const origin = pattern  let negative = false  // > An optional prefix "!" which negates the pattern;  if (pattern.indexOf('!') === 0) {    negative = true    pattern = pattern.substr(1)  }  pattern = pattern  // > Put a backslash ("\") in front of the first "!" for patterns that  // >   begin with a literal "!", for example, `"\!important!.txt"`.  .replace(REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION, '!')  // > Put a backslash ("\") in front of the first hash for patterns that  // >   begin with a hash.  .replace(REGEX_REPLACE_LEADING_EXCAPED_HASH, '#')  const regex = makeRegex(pattern, ignoreCase)  return new IgnoreRule(    origin,    pattern,    negative,    regex  )}const throwError = (message, Ctor) => {  throw new Ctor(message)}const checkPath = (path, originalPath, doThrow) => {  if (!isString(path)) {    return doThrow(      `path must be a string, but got \`${originalPath}\``,      TypeError    )  }  // We don't know if we should ignore EMPTY, so throw  if (!path) {    return doThrow(`path must not be empty`, TypeError)  }  // Check if it is a relative path  if (checkPath.isNotRelative(path)) {    const r = '`path.relative()`d'    return doThrow(      `path should be a ${r} string, but got "${originalPath}"`,      RangeError    )  }  return true}const isNotRelative = path => REGEX_TEST_INVALID_PATH.test(path)checkPath.isNotRelative = isNotRelativecheckPath.convert = p => pclass Ignore {  constructor ({    ignorecase = true,    ignoreCase = ignorecase,    allowRelativePaths = false  } = {}) {    define(this, KEY_IGNORE, true)    this._rules = []    this._ignoreCase = ignoreCase    this._allowRelativePaths = allowRelativePaths    this._initCache()  }  _initCache () {    this._ignoreCache = Object.create(null)    this._testCache = Object.create(null)  }  _addPattern (pattern) {    // #32    if (pattern && pattern[KEY_IGNORE]) {      this._rules = this._rules.concat(pattern._rules)      this._added = true      return    }    if (checkPattern(pattern)) {      const rule = createRule(pattern, this._ignoreCase)      this._added = true      this._rules.push(rule)    }  }  // @param {Array<string> | string | Ignore} pattern  add (pattern) {    this._added = false    makeArray(      isString(pattern)        ? splitPattern(pattern)        : pattern    ).forEach(this._addPattern, this)    // Some rules have just added to the ignore,    // making the behavior changed.    if (this._added) {      this._initCache()    }    return this  }  // legacy  addPattern (pattern) {    return this.add(pattern)  }  //          |           ignored : unignored  // negative |   0:0   |   0:1   |   1:0   |   1:1  // -------- | ------- | ------- | ------- | --------  //     0    |  TEST   |  TEST   |  SKIP   |    X  //     1    |  TESTIF |  SKIP   |  TEST   |    X  // - SKIP: always skip  // - TEST: always test  // - TESTIF: only test if checkUnignored  // - X: that never happen  // @param {boolean} whether should check if the path is unignored,  //   setting `checkUnignored` to `false` could reduce additional  //   path matching.  // @returns {TestResult} true if a file is ignored  _testOne (path, checkUnignored) {    let ignored = false    let unignored = false    this._rules.forEach(rule => {      const {negative} = rule      if (        unignored === negative && ignored !== unignored        || negative && !ignored && !unignored && !checkUnignored      ) {        return      }      const matched = rule.regex.test(path)      if (matched) {        ignored = !negative        unignored = negative      }    })    return {      ignored,      unignored    }  }  // @returns {TestResult}  _test (originalPath, cache, checkUnignored, slices) {    const path = originalPath      // Supports nullable path      && checkPath.convert(originalPath)    checkPath(      path,      originalPath,      this._allowRelativePaths        ? RETURN_FALSE        : throwError    )    return this._t(path, cache, checkUnignored, slices)  }  _t (path, cache, checkUnignored, slices) {    if (path in cache) {      return cache[path]    }    if (!slices) {      // path/to/a.js      // ['path', 'to', 'a.js']      slices = path.split(SLASH)    }    slices.pop()    // If the path has no parent directory, just test it    if (!slices.length) {      return cache[path] = this._testOne(path, checkUnignored)    }    const parent = this._t(      slices.join(SLASH) + SLASH,      cache,      checkUnignored,      slices    )    // If the path contains a parent directory, check the parent first    return cache[path] = parent.ignored      // > It is not possible to re-include a file if a parent directory of      // >   that file is excluded.      ? parent      : this._testOne(path, checkUnignored)  }  ignores (path) {    return this._test(path, this._ignoreCache, false).ignored  }  createFilter () {    return path => !this.ignores(path)  }  filter (paths) {    return makeArray(paths).filter(this.createFilter())  }  // @returns {TestResult}  test (path) {    return this._test(path, this._testCache, true)  }}const factory = options => new Ignore(options)const isPathValid = path =>  checkPath(path && checkPath.convert(path), path, RETURN_FALSE)factory.isPathValid = isPathValid// Fixes typescriptfactory.default = factorymodule.exports = factory// Windows// --------------------------------------------------------------/* istanbul ignore if */if (  // Detect `process` so that it can run in browsers.  typeof process !== 'undefined'  && (    process.env && process.env.IGNORE_TEST_WIN32    || process.platform === 'win32'  )) {  /* eslint no-control-regex: "off" */  const makePosix = str => /^\\\\\?\\/.test(str)  || /["<>|\u0000-\u001F]+/u.test(str)    ? str    : str.replace(/\\/g, '/')  checkPath.convert = makePosix  // 'C:\\foo'     <- 'C:\\foo' has been converted to 'C:/'  // 'd:\\foo'  const REGIX_IS_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i  checkPath.isNotRelative = path =>    REGIX_IS_WINDOWS_PATH_ABSOLUTE.test(path)    || isNotRelative(path)}
 |