CoolFace
Datasetpublic

basant307/AI_Governance_Project

sourceHugging Faceapache-2.0updated 2mo agoView on Hugging Face
0likes45downloads
index.js637 linesDownload Raw Back to ignore
1// A simple implementation of make-array2function makeArray (subject) {3  return Array.isArray(subject)4    ? subject5    : [subject]6}7 8const EMPTY = ''9const SPACE = ' '10const ESCAPE = '\\'11const REGEX_TEST_BLANK_LINE = /^\s+$/12const REGEX_INVALID_TRAILING_BACKSLASH = /(?:[^\\]|^)\\$/13const REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION = /^\\!/14const REGEX_REPLACE_LEADING_EXCAPED_HASH = /^\\#/15const REGEX_SPLITALL_CRLF = /\r?\n/g16// /foo,17// ./foo,18// ../foo,19// .20// ..21const REGEX_TEST_INVALID_PATH = /^\.*\/|^\.+$/22 23const SLASH = '/'24 25// Do not use ternary expression here, since "istanbul ignore next" is buggy26let TMP_KEY_IGNORE = 'node-ignore'27/* istanbul ignore else */28if (typeof Symbol !== 'undefined') {29  TMP_KEY_IGNORE = Symbol.for('node-ignore')30}31const KEY_IGNORE = TMP_KEY_IGNORE32 33const define = (object, key, value) =>34  Object.defineProperty(object, key, {value})35 36const REGEX_REGEXP_RANGE = /([0-z])-([0-z])/g37 38const RETURN_FALSE = () => false39 40// Sanitize the range of a regular expression41// The cases are complicated, see test cases for details42const sanitizeRange = range => range.replace(43  REGEX_REGEXP_RANGE,44  (match, from, to) => from.charCodeAt(0) <= to.charCodeAt(0)45    ? match46    // Invalid range (out of order) which is ok for gitignore rules but47    //   fatal for JavaScript regular expression, so eliminate it.48    : EMPTY49)50 51// See fixtures #5952const cleanRangeBackSlash = slashes => {53  const {length} = slashes54  return slashes.slice(0, length - length % 2)55}56 57// > If the pattern ends with a slash,58// > it is removed for the purpose of the following description,59// > but it would only find a match with a directory.60// > In other words, foo/ will match a directory foo and paths underneath it,61// > but will not match a regular file or a symbolic link foo62// >  (this is consistent with the way how pathspec works in general in Git).63// '`foo/`' will not match regular file '`foo`' or symbolic link '`foo`'64// -> ignore-rules will not deal with it, because it costs extra `fs.stat` call65//      you could use option `mark: true` with `glob`66 67// '`foo/`' should not continue with the '`..`'68const REPLACERS = [69 70  [71    // remove BOM72    // TODO:73    // Other similar zero-width characters?74    /^\uFEFF/,75    () => EMPTY76  ],77 78  // > Trailing spaces are ignored unless they are quoted with backslash ("\")79  [80    // (a\ ) -> (a )81    // (a  ) -> (a)82    // (a ) -> (a)83    // (a \ ) -> (a  )84    /((?:\\\\)*?)(\\?\s+)$/,85    (_, m1, m2) => m1 + (86      m2.indexOf('\\') === 087        ? SPACE88        : EMPTY89    )90  ],91 92  // replace (\ ) with ' '93  // (\ ) -> ' '94  // (\\ ) -> '\\ '95  // (\\\ ) -> '\\ '96  [97    /(\\+?)\s/g,98    (_, m1) => {99      const {length} = m1100      return m1.slice(0, length - length % 2) + SPACE101    }102  ],103 104  // Escape metacharacters105  // which is written down by users but means special for regular expressions.106 107  // > There are 12 characters with special meanings:108  // > - the backslash \,109  // > - the caret ^,110  // > - the dollar sign $,111  // > - the period or dot .,112  // > - the vertical bar or pipe symbol |,113  // > - the question mark ?,114  // > - the asterisk or star *,115  // > - the plus sign +,116  // > - the opening parenthesis (,117  // > - the closing parenthesis ),118  // > - and the opening square bracket [,119  // > - the opening curly brace {,120  // > These special characters are often called "metacharacters".121  [122    /[\\$.|*+(){^]/g,123    match => `\\${match}`124  ],125 126  [127    // > a question mark (?) matches a single character128    /(?!\\)\?/g,129    () => '[^/]'130  ],131 132  // leading slash133  [134 135    // > A leading slash matches the beginning of the pathname.136    // > For example, "/*.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c".137    // A leading slash matches the beginning of the pathname138    /^\//,139    () => '^'140  ],141 142  // replace special metacharacter slash after the leading slash143  [144    /\//g,145    () => '\\/'146  ],147 148  [149    // > A leading "**" followed by a slash means match in all directories.150    // > For example, "**/foo" matches file or directory "foo" anywhere,151    // > the same as pattern "foo".152    // > "**/foo/bar" matches file or directory "bar" anywhere that is directly153    // >   under directory "foo".154    // Notice that the '*'s have been replaced as '\\*'155    /^\^*\\\*\\\*\\\//,156 157    // '**/foo' <-> 'foo'158    () => '^(?:.*\\/)?'159  ],160 161  // starting162  [163    // there will be no leading '/'164    //   (which has been replaced by section "leading slash")165    // If starts with '**', adding a '^' to the regular expression also works166    /^(?=[^^])/,167    function startingReplacer () {168      // If has a slash `/` at the beginning or middle169      return !/\/(?!$)/.test(this)170        // > Prior to 2.22.1171        // > If the pattern does not contain a slash /,172        // >   Git treats it as a shell glob pattern173        // Actually, if there is only a trailing slash,174        //   git also treats it as a shell glob pattern175 176        // After 2.22.1 (compatible but clearer)177        // > If there is a separator at the beginning or middle (or both)178        // > of the pattern, then the pattern is relative to the directory179        // > level of the particular .gitignore file itself.180        // > Otherwise the pattern may also match at any level below181        // > the .gitignore level.182        ? '(?:^|\\/)'183 184        // > Otherwise, Git treats the pattern as a shell glob suitable for185        // >   consumption by fnmatch(3)186        : '^'187    }188  ],189 190  // two globstars191  [192    // Use lookahead assertions so that we could match more than one `'/**'`193    /\\\/\\\*\\\*(?=\\\/|$)/g,194 195    // Zero, one or several directories196    // should not use '*', or it will be replaced by the next replacer197 198    // Check if it is not the last `'/**'`199    (_, index, str) => index + 6 < str.length200 201      // case: /**/202      // > A slash followed by two consecutive asterisks then a slash matches203      // >   zero or more directories.204      // > For example, "a/**/b" matches "a/b", "a/x/b", "a/x/y/b" and so on.205      // '/**/'206      ? '(?:\\/[^\\/]+)*'207 208      // case: /**209      // > A trailing `"/**"` matches everything inside.210 211      // #21: everything inside but it should not include the current folder212      : '\\/.+'213  ],214 215  // normal intermediate wildcards216  [217    // Never replace escaped '*'218    // ignore rule '\*' will match the path '*'219 220    // 'abc.*/' -> go221    // 'abc.*'  -> skip this rule,222    //    coz trailing single wildcard will be handed by [trailing wildcard]223    /(^|[^\\]+)(\\\*)+(?=.+)/g,224 225    // '*.js' matches '.js'226    // '*.js' doesn't match 'abc'227    (_, p1, p2) => {228      // 1.229      // > An asterisk "*" matches anything except a slash.230      // 2.231      // > Other consecutive asterisks are considered regular asterisks232      // > and will match according to the previous rules.233      const unescaped = p2.replace(/\\\*/g, '[^\\/]*')234      return p1 + unescaped235    }236  ],237 238  [239    // unescape, revert step 3 except for back slash240    // For example, if a user escape a '\\*',241    // after step 3, the result will be '\\\\\\*'242    /\\\\\\(?=[$.|*+(){^])/g,243    () => ESCAPE244  ],245 246  [247    // '\\\\' -> '\\'248    /\\\\/g,249    () => ESCAPE250  ],251 252  [253    // > The range notation, e.g. [a-zA-Z],254    // > can be used to match one of the characters in a range.255 256    // `\` is escaped by step 3257    /(\\)?\[([^\]/]*?)(\\*)($|\])/g,258    (match, leadEscape, range, endEscape, close) => leadEscape === ESCAPE259      // '\\[bar]' -> '\\\\[bar\\]'260      ? `\\[${range}${cleanRangeBackSlash(endEscape)}${close}`261      : close === ']'262        ? endEscape.length % 2 === 0263          // A normal case, and it is a range notation264          // '[bar]'265          // '[bar\\\\]'266          ? `[${sanitizeRange(range)}${endEscape}]`267          // Invalid range notaton268          // '[bar\\]' -> '[bar\\\\]'269          : '[]'270        : '[]'271  ],272 273  // ending274  [275    // 'js' will not match 'js.'276    // 'ab' will not match 'abc'277    /(?:[^*])$/,278 279    // WTF!280    // https://git-scm.com/docs/gitignore281    // changes in [2.22.1](https://git-scm.com/docs/gitignore/2.22.1)282    // which re-fixes #24, #38283 284    // > If there is a separator at the end of the pattern then the pattern285    // > will only match directories, otherwise the pattern can match both286    // > files and directories.287 288    // 'js*' will not match 'a.js'289    // 'js/' will not match 'a.js'290    // 'js' will match 'a.js' and 'a.js/'291    match => /\/$/.test(match)292      // foo/ will not match 'foo'293      ? `${match}$`294      // foo matches 'foo' and 'foo/'295      : `${match}(?=$|\\/$)`296  ],297 298  // trailing wildcard299  [300    /(\^|\\\/)?\\\*$/,301    (_, p1) => {302      const prefix = p1303        // '\^':304        // '/*' does not match EMPTY305        // '/*' does not match everything306 307        // '\\\/':308        // 'abc/*' does not match 'abc/'309        ? `${p1}[^/]+`310 311        // 'a*' matches 'a'312        // 'a*' matches 'aa'313        : '[^/]*'314 315      return `${prefix}(?=$|\\/$)`316    }317  ],318]319 320// A simple cache, because an ignore rule only has only one certain meaning321const regexCache = Object.create(null)322 323// @param {pattern}324const makeRegex = (pattern, ignoreCase) => {325  let source = regexCache[pattern]326 327  if (!source) {328    source = REPLACERS.reduce(329      (prev, [matcher, replacer]) =>330        prev.replace(matcher, replacer.bind(pattern)),331      pattern332    )333    regexCache[pattern] = source334  }335 336  return ignoreCase337    ? new RegExp(source, 'i')338    : new RegExp(source)339}340 341const isString = subject => typeof subject === 'string'342 343// > A blank line matches no files, so it can serve as a separator for readability.344const checkPattern = pattern => pattern345  && isString(pattern)346  && !REGEX_TEST_BLANK_LINE.test(pattern)347  && !REGEX_INVALID_TRAILING_BACKSLASH.test(pattern)348 349  // > A line starting with # serves as a comment.350  && pattern.indexOf('#') !== 0351 352const splitPattern = pattern => pattern.split(REGEX_SPLITALL_CRLF)353 354class IgnoreRule {355  constructor (356    origin,357    pattern,358    negative,359    regex360  ) {361    this.origin = origin362    this.pattern = pattern363    this.negative = negative364    this.regex = regex365  }366}367 368const createRule = (pattern, ignoreCase) => {369  const origin = pattern370  let negative = false371 372  // > An optional prefix "!" which negates the pattern;373  if (pattern.indexOf('!') === 0) {374    negative = true375    pattern = pattern.substr(1)376  }377 378  pattern = pattern379  // > Put a backslash ("\") in front of the first "!" for patterns that380  // >   begin with a literal "!", for example, `"\!important!.txt"`.381  .replace(REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION, '!')382  // > Put a backslash ("\") in front of the first hash for patterns that383  // >   begin with a hash.384  .replace(REGEX_REPLACE_LEADING_EXCAPED_HASH, '#')385 386  const regex = makeRegex(pattern, ignoreCase)387 388  return new IgnoreRule(389    origin,390    pattern,391    negative,392    regex393  )394}395 396const throwError = (message, Ctor) => {397  throw new Ctor(message)398}399 400const checkPath = (path, originalPath, doThrow) => {401  if (!isString(path)) {402    return doThrow(403      `path must be a string, but got \`${originalPath}\``,404      TypeError405    )406  }407 408  // We don't know if we should ignore EMPTY, so throw409  if (!path) {410    return doThrow(`path must not be empty`, TypeError)411  }412 413  // Check if it is a relative path414  if (checkPath.isNotRelative(path)) {415    const r = '`path.relative()`d'416    return doThrow(417      `path should be a ${r} string, but got "${originalPath}"`,418      RangeError419    )420  }421 422  return true423}424 425const isNotRelative = path => REGEX_TEST_INVALID_PATH.test(path)426 427checkPath.isNotRelative = isNotRelative428checkPath.convert = p => p429 430class Ignore {431  constructor ({432    ignorecase = true,433    ignoreCase = ignorecase,434    allowRelativePaths = false435  } = {}) {436    define(this, KEY_IGNORE, true)437 438    this._rules = []439    this._ignoreCase = ignoreCase440    this._allowRelativePaths = allowRelativePaths441    this._initCache()442  }443 444  _initCache () {445    this._ignoreCache = Object.create(null)446    this._testCache = Object.create(null)447  }448 449  _addPattern (pattern) {450    // #32451    if (pattern && pattern[KEY_IGNORE]) {452      this._rules = this._rules.concat(pattern._rules)453      this._added = true454      return455    }456 457    if (checkPattern(pattern)) {458      const rule = createRule(pattern, this._ignoreCase)459      this._added = true460      this._rules.push(rule)461    }462  }463 464  // @param {Array<string> | string | Ignore} pattern465  add (pattern) {466    this._added = false467 468    makeArray(469      isString(pattern)470        ? splitPattern(pattern)471        : pattern472    ).forEach(this._addPattern, this)473 474    // Some rules have just added to the ignore,475    // making the behavior changed.476    if (this._added) {477      this._initCache()478    }479 480    return this481  }482 483  // legacy484  addPattern (pattern) {485    return this.add(pattern)486  }487 488  //          |           ignored : unignored489  // negative |   0:0   |   0:1   |   1:0   |   1:1490  // -------- | ------- | ------- | ------- | --------491  //     0    |  TEST   |  TEST   |  SKIP   |    X492  //     1    |  TESTIF |  SKIP   |  TEST   |    X493 494  // - SKIP: always skip495  // - TEST: always test496  // - TESTIF: only test if checkUnignored497  // - X: that never happen498 499  // @param {boolean} whether should check if the path is unignored,500  //   setting `checkUnignored` to `false` could reduce additional501  //   path matching.502 503  // @returns {TestResult} true if a file is ignored504  _testOne (path, checkUnignored) {505    let ignored = false506    let unignored = false507 508    this._rules.forEach(rule => {509      const {negative} = rule510      if (511        unignored === negative && ignored !== unignored512        || negative && !ignored && !unignored && !checkUnignored513      ) {514        return515      }516 517      const matched = rule.regex.test(path)518 519      if (matched) {520        ignored = !negative521        unignored = negative522      }523    })524 525    return {526      ignored,527      unignored528    }529  }530 531  // @returns {TestResult}532  _test (originalPath, cache, checkUnignored, slices) {533    const path = originalPath534      // Supports nullable path535      && checkPath.convert(originalPath)536 537    checkPath(538      path,539      originalPath,540      this._allowRelativePaths541        ? RETURN_FALSE542        : throwError543    )544 545    return this._t(path, cache, checkUnignored, slices)546  }547 548  _t (path, cache, checkUnignored, slices) {549    if (path in cache) {550      return cache[path]551    }552 553    if (!slices) {554      // path/to/a.js555      // ['path', 'to', 'a.js']556      slices = path.split(SLASH)557    }558 559    slices.pop()560 561    // If the path has no parent directory, just test it562    if (!slices.length) {563      return cache[path] = this._testOne(path, checkUnignored)564    }565 566    const parent = this._t(567      slices.join(SLASH) + SLASH,568      cache,569      checkUnignored,570      slices571    )572 573    // If the path contains a parent directory, check the parent first574    return cache[path] = parent.ignored575      // > It is not possible to re-include a file if a parent directory of576      // >   that file is excluded.577      ? parent578      : this._testOne(path, checkUnignored)579  }580 581  ignores (path) {582    return this._test(path, this._ignoreCache, false).ignored583  }584 585  createFilter () {586    return path => !this.ignores(path)587  }588 589  filter (paths) {590    return makeArray(paths).filter(this.createFilter())591  }592 593  // @returns {TestResult}594  test (path) {595    return this._test(path, this._testCache, true)596  }597}598 599const factory = options => new Ignore(options)600 601const isPathValid = path =>602  checkPath(path && checkPath.convert(path), path, RETURN_FALSE)603 604factory.isPathValid = isPathValid605 606// Fixes typescript607factory.default = factory608 609module.exports = factory610 611// Windows612// --------------------------------------------------------------613/* istanbul ignore if */614if (615  // Detect `process` so that it can run in browsers.616  typeof process !== 'undefined'617  && (618    process.env && process.env.IGNORE_TEST_WIN32619    || process.platform === 'win32'620  )621) {622  /* eslint no-control-regex: "off" */623  const makePosix = str => /^\\\\\?\\/.test(str)624  || /["<>|\u0000-\u001F]+/u.test(str)625    ? str626    : str.replace(/\\/g, '/')627 628  checkPath.convert = makePosix629 630  // 'C:\\foo'     <- 'C:\\foo' has been converted to 'C:/'631  // 'd:\\foo'632  const REGIX_IS_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i633  checkPath.isNotRelative = path =>634    REGIX_IS_WINDOWS_PATH_ABSOLUTE.test(path)635    || isNotRelative(path)636}637 
basant307/AI_Governance_Project · CoolFace