🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

ignore

Package Overview
Dependencies
Maintainers
1
Versions
99
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ignore - npm Package Compare versions

Comparing version
6.0.2
to
7.0.0
+777
index.mjs
// A simple implementation of make-array
function makeArray (subject) {
return Array.isArray(subject)
? subject
: [subject]
}
const UNDEFINED = undefined
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
// Invalid:
// - /foo,
// - ./foo,
// - ../foo,
// - .
// - ..
// Valid:
// - .foo
const REGEX_TEST_INVALID_PATH = /^\.*\/|^\.+$/
const REGEX_TEST_TRAILING_SLASH = /\/$/
const SLASH = '/'
// Do not use ternary expression here, since "istanbul ignore next" is buggy
let TMP_KEY_IGNORE = 'node-ignore'
/* istanbul ignore else */
if (typeof Symbol !== 'undefined') {
TMP_KEY_IGNORE = Symbol.for('node-ignore')
}
const KEY_IGNORE = TMP_KEY_IGNORE
const define = (object, key, value) => {
Object.defineProperty(object, key, {value})
return value
}
const REGEX_REGEXP_RANGE = /([0-z])-([0-z])/g
const RETURN_FALSE = () => false
// Sanitize the range of a regular expression
// The cases are complicated, see test cases for details
const 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 #59
const 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 = [
[
// Remove BOM
// TODO:
// Other similar zero-width characters?
/^\uFEFF/,
() => EMPTY
],
// > Trailing spaces are ignored unless they are quoted with backslash ("\")
[
// (a\ ) -> (a )
// (a ) -> (a)
// (a ) -> (a)
// (a \ ) -> (a )
/((?:\\\\)*?)(\\?\s+)$/,
(_, m1, m2) => m1 + (
m2.indexOf('\\') === 0
? SPACE
: EMPTY
)
],
// Replace (\ ) with ' '
// (\ ) -> ' '
// (\\ ) -> '\\ '
// (\\\ ) -> '\\ '
[
/(\\+?)\s/g,
(_, m1) => {
const {length} = m1
return m1.slice(0, length - length % 2) + 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}(?=$|\\/$)`
]
]
const REGEX_REPLACE_TRAILING_WILDCARD = /(^|\\\/)?\\\*$/
const MODE_IGNORE = 'regex'
const MODE_CHECK_IGNORE = 'checkRegex'
const UNDERSCORE = '_'
const TRAILING_WILD_CARD_REPLACERS = {
[MODE_IGNORE] (_, 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}(?=$|\\/$)`
},
[MODE_CHECK_IGNORE] (_, p1) {
// When doing `git check-ignore`
const prefix = p1
// '\\\/':
// 'abc/*' DOES match 'abc/' !
? `${p1}[^/]*`
// 'a*' matches 'a'
// 'a*' matches 'aa'
: '[^/]*'
return `${prefix}(?=$|\\/$)`
}
}
// @param {pattern}
const makeRegexPrefix = pattern => REPLACERS.reduce(
(prev, [matcher, replacer]) =>
prev.replace(matcher, replacer.bind(pattern)),
pattern
)
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('#') !== 0
const splitPattern = pattern => pattern
.split(REGEX_SPLITALL_CRLF)
.filter(Boolean)
class IgnoreRule {
constructor (
pattern,
mark,
body,
ignoreCase,
negative,
prefix
) {
this.pattern = pattern
this.mark = mark
this.negative = negative
define(this, 'body', body)
define(this, 'ignoreCase', ignoreCase)
define(this, 'regexPrefix', prefix)
}
get regex () {
const key = UNDERSCORE + MODE_IGNORE
if (this[key]) {
return this[key]
}
return this._make(MODE_IGNORE, key)
}
get checkRegex () {
const key = UNDERSCORE + MODE_CHECK_IGNORE
if (this[key]) {
return this[key]
}
return this._make(MODE_CHECK_IGNORE, key)
}
_make (mode, key) {
const str = this.regexPrefix.replace(
REGEX_REPLACE_TRAILING_WILDCARD,
// It does not need to bind pattern
TRAILING_WILD_CARD_REPLACERS[mode]
)
const regex = this.ignoreCase
? new RegExp(str, 'i')
: new RegExp(str)
return define(this, key, regex)
}
}
const createRule = ({
pattern,
mark
}, ignoreCase) => {
let negative = false
let body = pattern
// > An optional prefix "!" which negates the pattern;
if (body.indexOf('!') === 0) {
negative = true
body = body.substr(1)
}
body = body
// > 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 regexPrefix = makeRegexPrefix(body)
return new IgnoreRule(
pattern,
mark,
body,
ignoreCase,
negative,
regexPrefix
)
}
class RuleManager {
constructor (ignoreCase) {
this._ignoreCase = ignoreCase
this._rules = []
}
_add (pattern) {
// #32
if (pattern && pattern[KEY_IGNORE]) {
this._rules = this._rules.concat(pattern._rules._rules)
this._added = true
return
}
if (isString(pattern)) {
pattern = {
pattern
}
}
if (checkPattern(pattern.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._add, this)
return this._added
}
// Test one single path without recursively checking parent directories
//
// - checkUnignored `boolean` whether should check if the path is unignored,
// setting `checkUnignored` to `false` could reduce additional
// path matching.
// - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
// @returns {TestResult} true if a file is ignored
test (path, checkUnignored, mode) {
let ignored = false
let unignored = false
let matchedRule
this._rules.forEach(rule => {
const {negative} = rule
// | 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
if (
unignored === negative && ignored !== unignored
|| negative && !ignored && !unignored && !checkUnignored
) {
return
}
const matched = rule[mode].test(path)
if (!matched) {
return
}
ignored = !negative
unignored = negative
matchedRule = negative
? UNDEFINED
: rule
})
const ret = {
ignored,
unignored
}
if (matchedRule) {
ret.rule = matchedRule
}
return ret
}
}
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 = isNotRelative
// On windows, the following function will be replaced
/* istanbul ignore next */
checkPath.convert = p => p
class Ignore {
constructor ({
ignorecase = true,
ignoreCase = ignorecase,
allowRelativePaths = false
} = {}) {
define(this, KEY_IGNORE, true)
this._rules = new RuleManager(ignoreCase)
this._strictPathCheck = !allowRelativePaths
this._initCache()
}
_initCache () {
// A cache for the result of `.ignores()`
this._ignoreCache = Object.create(null)
// A cache for the result of `.test()`
this._testCache = Object.create(null)
}
add (pattern) {
if (this._rules.add(pattern)) {
// Some rules have just added to the ignore,
// making the behavior changed,
// so we need to re-initialize the result cache
this._initCache()
}
return this
}
// legacy
addPattern (pattern) {
return this.add(pattern)
}
// @returns {TestResult}
_test (originalPath, cache, checkUnignored, slices) {
const path = originalPath
// Supports nullable path
&& checkPath.convert(originalPath)
checkPath(
path,
originalPath,
this._strictPathCheck
? throwError
: RETURN_FALSE
)
return this._t(path, cache, checkUnignored, slices)
}
checkIgnore (path) {
// If the path doest not end with a slash, `.ignores()` is much equivalent
// to `git check-ignore`
if (!REGEX_TEST_TRAILING_SLASH.test(path)) {
return this.test(path)
}
const slices = path.split(SLASH).filter(Boolean)
slices.pop()
if (slices.length) {
const parent = this._t(
slices.join(SLASH) + SLASH,
this._testCache,
true,
slices
)
if (parent.ignored) {
return parent
}
}
return this._rules.test(path, false, MODE_CHECK_IGNORE)
}
_t (
// The path to be tested
path,
// The cache for the result of a certain checking
cache,
// Whether should check if the path is unignored
checkUnignored,
// The path slices
slices
) {
if (path in cache) {
return cache[path]
}
if (!slices) {
// path/to/a.js
// ['path', 'to', 'a.js']
slices = path.split(SLASH).filter(Boolean)
}
slices.pop()
// If the path has no parent directory, just test it
if (!slices.length) {
return cache[path] = this._rules.test(path, checkUnignored, MODE_IGNORE)
}
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._rules.test(path, checkUnignored, MODE_IGNORE)
}
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
// Windows
// --------------------------------------------------------------
/* istanbul ignore next */
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 REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i
checkPath.isNotRelative = path =>
REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path)
|| isNotRelative(path)
}
export default factory
export {
isPathValid
}
+26
-5
type Pathname = string
interface IgnoreRule {
pattern: string
mark?: string
negative: boolean
}
interface TestResult {
ignored: boolean
unignored: boolean
rule?: IgnoreRule
}
interface PatternParams {
pattern: string
mark?: string
}
export interface Ignore {

@@ -14,3 +26,5 @@ /**

*/
add(patterns: string | Ignore | readonly (string | Ignore)[]): this
add(
patterns: string | Ignore | readonly (string | Ignore)[] | PatternParams
): this

@@ -44,2 +58,9 @@ /**

test(pathname: Pathname): TestResult
/**
* Debugs ignore rules and returns the checking result, which is
* equivalent to `git check-ignore -v`.
* @returns TestResult
*/
checkIgnore(pathname: Pathname): TestResult
}

@@ -58,7 +79,7 @@

declare function ignore(options?: Options): Ignore
declare function isPathValid (pathname: string): boolean
declare namespace ignore {
export function isPathValid (pathname: string): boolean
export default ignore
export {
isPathValid
}
export default ignore
+284
-143

@@ -8,2 +8,3 @@ // A simple implementation of make-array

const UNDEFINED = undefined
const EMPTY = ''

@@ -17,9 +18,15 @@ const SPACE = ' '

const REGEX_SPLITALL_CRLF = /\r?\n/g
// /foo,
// ./foo,
// ../foo,
// .
// ..
// Invalid:
// - /foo,
// - ./foo,
// - ../foo,
// - .
// - ..
// Valid:
// - .foo
const REGEX_TEST_INVALID_PATH = /^\.*\/|^\.+$/
const REGEX_TEST_TRAILING_SLASH = /\/$/
const SLASH = '/'

@@ -35,4 +42,6 @@

const define = (object, key, value) =>
const define = (object, key, value) => {
Object.defineProperty(object, key, {value})
return value
}

@@ -74,3 +83,3 @@ const REGEX_REGEXP_RANGE = /([0-z])-([0-z])/g

[
// remove BOM
// Remove BOM
// TODO:

@@ -96,3 +105,3 @@ // Other similar zero-width characters?

// replace (\ ) with ' '
// Replace (\ ) with ' '
// (\ ) -> ' '

@@ -301,47 +310,50 @@ // (\\ ) -> '\\ '

: `${match}(?=$|\\/$)`
],
]
]
// trailing wildcard
[
/(\^|\\\/)?\\\*$/,
(_, p1) => {
const prefix = p1
// '\^':
// '/*' does not match EMPTY
// '/*' does not match everything
const REGEX_REPLACE_TRAILING_WILDCARD = /(^|\\\/)?\\\*$/
const MODE_IGNORE = 'regex'
const MODE_CHECK_IGNORE = 'checkRegex'
const UNDERSCORE = '_'
// '\\\/':
// 'abc/*' does not match 'abc/'
? `${p1}[^/]+`
const TRAILING_WILD_CARD_REPLACERS = {
[MODE_IGNORE] (_, p1) {
const prefix = p1
// '\^':
// '/*' does not match EMPTY
// '/*' does not match everything
// 'a*' matches 'a'
// 'a*' matches 'aa'
: '[^/]*'
// '\\\/':
// 'abc/*' does not match 'abc/'
? `${p1}[^/]+`
return `${prefix}(?=$|\\/$)`
}
],
]
// 'a*' matches 'a'
// 'a*' matches 'aa'
: '[^/]*'
// A simple cache, because an ignore rule only has only one certain meaning
const regexCache = Object.create(null)
return `${prefix}(?=$|\\/$)`
},
// @param {pattern}
const makeRegex = (pattern, ignoreCase) => {
let source = regexCache[pattern]
[MODE_CHECK_IGNORE] (_, p1) {
// When doing `git check-ignore`
const prefix = p1
// '\\\/':
// 'abc/*' DOES match 'abc/' !
? `${p1}[^/]*`
if (!source) {
source = REPLACERS.reduce(
(prev, [matcher, replacer]) =>
prev.replace(matcher, replacer.bind(pattern)),
pattern
)
regexCache[pattern] = source
// 'a*' matches 'a'
// 'a*' matches 'aa'
: '[^/]*'
return `${prefix}(?=$|\\/$)`
}
return ignoreCase
? new RegExp(source, 'i')
: new RegExp(source)
}
// @param {pattern}
const makeRegexPrefix = pattern => REPLACERS.reduce(
(prev, [matcher, replacer]) =>
prev.replace(matcher, replacer.bind(pattern)),
pattern
)
const isString = subject => typeof subject === 'string'

@@ -358,29 +370,74 @@

const splitPattern = pattern => pattern.split(REGEX_SPLITALL_CRLF)
const splitPattern = pattern => pattern
.split(REGEX_SPLITALL_CRLF)
.filter(Boolean)
class IgnoreRule {
constructor (
origin,
pattern,
mark,
body,
ignoreCase,
negative,
regex
prefix
) {
this.origin = origin
this.pattern = pattern
this.mark = mark
this.negative = negative
this.regex = regex
define(this, 'body', body)
define(this, 'ignoreCase', ignoreCase)
define(this, 'regexPrefix', prefix)
}
get regex () {
const key = UNDERSCORE + MODE_IGNORE
if (this[key]) {
return this[key]
}
return this._make(MODE_IGNORE, key)
}
get checkRegex () {
const key = UNDERSCORE + MODE_CHECK_IGNORE
if (this[key]) {
return this[key]
}
return this._make(MODE_CHECK_IGNORE, key)
}
_make (mode, key) {
const str = this.regexPrefix.replace(
REGEX_REPLACE_TRAILING_WILDCARD,
// It does not need to bind pattern
TRAILING_WILD_CARD_REPLACERS[mode]
)
const regex = this.ignoreCase
? new RegExp(str, 'i')
: new RegExp(str)
return define(this, key, regex)
}
}
const createRule = (pattern, ignoreCase) => {
const origin = pattern
const createRule = ({
pattern,
mark
}, ignoreCase) => {
let negative = false
let body = pattern
// > An optional prefix "!" which negates the pattern;
if (pattern.indexOf('!') === 0) {
if (body.indexOf('!') === 0) {
negative = true
pattern = pattern.substr(1)
body = body.substr(1)
}
pattern = pattern
body = body
// > Put a backslash ("\") in front of the first "!" for patterns that

@@ -393,12 +450,115 @@ // > begin with a literal "!", for example, `"\!important!.txt"`.

const regex = makeRegex(pattern, ignoreCase)
const regexPrefix = makeRegexPrefix(body)
return new IgnoreRule(
origin,
pattern,
mark,
body,
ignoreCase,
negative,
regex
regexPrefix
)
}
class RuleManager {
constructor (ignoreCase) {
this._ignoreCase = ignoreCase
this._rules = []
}
_add (pattern) {
// #32
if (pattern && pattern[KEY_IGNORE]) {
this._rules = this._rules.concat(pattern._rules._rules)
this._added = true
return
}
if (isString(pattern)) {
pattern = {
pattern
}
}
if (checkPattern(pattern.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._add, this)
return this._added
}
// Test one single path without recursively checking parent directories
//
// - checkUnignored `boolean` whether should check if the path is unignored,
// setting `checkUnignored` to `false` could reduce additional
// path matching.
// - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
// @returns {TestResult} true if a file is ignored
test (path, checkUnignored, mode) {
let ignored = false
let unignored = false
let matchedRule
this._rules.forEach(rule => {
const {negative} = rule
// | 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
if (
unignored === negative && ignored !== unignored
|| negative && !ignored && !unignored && !checkUnignored
) {
return
}
const matched = rule[mode].test(path)
if (!matched) {
return
}
ignored = !negative
unignored = negative
matchedRule = negative
? UNDEFINED
: rule
})
const ret = {
ignored,
unignored
}
if (matchedRule) {
ret.rule = matchedRule
}
return ret
}
}
const throwError = (message, Ctor) => {

@@ -436,4 +596,8 @@ throw new Ctor(message)

checkPath.isNotRelative = isNotRelative
// On windows, the following function will be replaced
/* istanbul ignore next */
checkPath.convert = p => p
class Ignore {

@@ -447,5 +611,4 @@ constructor ({

this._rules = []
this._ignoreCase = ignoreCase
this._allowRelativePaths = allowRelativePaths
this._rules = new RuleManager(ignoreCase)
this._strictPathCheck = !allowRelativePaths
this._initCache()

@@ -455,34 +618,14 @@ }

_initCache () {
// A cache for the result of `.ignores()`
this._ignoreCache = Object.create(null)
// A cache for the result of `.test()`
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) {
if (this._rules.add(pattern)) {
// Some rules have just added to the ignore,
// making the behavior changed,
// so we need to re-initialize the result cache
this._initCache()

@@ -499,45 +642,2 @@ }

// | 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}

@@ -552,5 +652,5 @@ _test (originalPath, cache, checkUnignored, slices) {

originalPath,
this._allowRelativePaths
? RETURN_FALSE
: throwError
this._strictPathCheck
? throwError
: RETURN_FALSE
)

@@ -561,3 +661,41 @@

_t (path, cache, checkUnignored, slices) {
checkIgnore (path) {
// If the path doest not end with a slash, `.ignores()` is much equivalent
// to `git check-ignore`
if (!REGEX_TEST_TRAILING_SLASH.test(path)) {
return this.test(path)
}
const slices = path.split(SLASH).filter(Boolean)
slices.pop()
if (slices.length) {
const parent = this._t(
slices.join(SLASH) + SLASH,
this._testCache,
true,
slices
)
if (parent.ignored) {
return parent
}
}
return this._rules.test(path, false, MODE_CHECK_IGNORE)
}
_t (
// The path to be tested
path,
// The cache for the result of a certain checking
cache,
// Whether should check if the path is unignored
checkUnignored,
// The path slices
slices
) {
if (path in cache) {

@@ -570,3 +708,3 @@ return cache[path]

// ['path', 'to', 'a.js']
slices = path.split(SLASH)
slices = path.split(SLASH).filter(Boolean)
}

@@ -578,3 +716,3 @@

if (!slices.length) {
return cache[path] = this._testOne(path, checkUnignored)
return cache[path] = this._rules.test(path, checkUnignored, MODE_IGNORE)
}

@@ -594,3 +732,3 @@

? parent
: this._testOne(path, checkUnignored)
: this._rules.test(path, checkUnignored, MODE_IGNORE)
}

@@ -623,10 +761,6 @@

// Fixes typescript
factory.default = factory
module.exports = factory
// Windows
// --------------------------------------------------------------
/* istanbul ignore if */
/* istanbul ignore next */
if (

@@ -650,6 +784,13 @@ // Detect `process` so that it can run in browsers.

// 'd:\\foo'
const REGIX_IS_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i
const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i
checkPath.isNotRelative = path =>
REGIX_IS_WINDOWS_PATH_ABSOLUTE.test(path)
REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path)
|| isNotRelative(path)
}
// COMMONJS_EXPORTS ////////////////////////////////////////////////////////////
// Fixes typescript
factory.default = factory
module.exports = factory
+239
-128
"use strict";
var _TRAILING_WILD_CARD_R;
function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }

@@ -15,2 +14,5 @@ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }

function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
// A simple implementation of make-array

@@ -20,2 +22,3 @@ function makeArray(subject) {

}
var UNDEFINED = undefined;
var EMPTY = '';

@@ -29,8 +32,13 @@ var SPACE = ' ';

var REGEX_SPLITALL_CRLF = /\r?\n/g;
// /foo,
// ./foo,
// ../foo,
// .
// ..
// Invalid:
// - /foo,
// - ./foo,
// - ../foo,
// - .
// - ..
// Valid:
// - .foo
var REGEX_TEST_INVALID_PATH = /^\.*\/|^\.+$/;
var REGEX_TEST_TRAILING_SLASH = /\/$/;
var SLASH = '/';

@@ -46,5 +54,6 @@

var define = function define(object, key, value) {
return Object.defineProperty(object, key, {
Object.defineProperty(object, key, {
value: value
});
return value;
};

@@ -85,3 +94,3 @@ var REGEX_REGEXP_RANGE = /([0-z])-([0-z])/g;

var REPLACERS = [[
// remove BOM
// Remove BOM
// TODO:

@@ -101,3 +110,3 @@ // Other similar zero-width characters?

}],
// replace (\ ) with ' '
// Replace (\ ) with ' '
// (\ ) -> ' '

@@ -274,5 +283,8 @@ // (\\ ) -> '\\ '

: "".concat(match, "(?=$|\\/$)");
}],
// trailing wildcard
[/(\^|\\\/)?\\\*$/, function (_, p1) {
}]];
var REGEX_REPLACE_TRAILING_WILDCARD = /(^|\\\/)?\\\*$/;
var MODE_IGNORE = 'regex';
var MODE_CHECK_IGNORE = 'checkRegex';
var UNDERSCORE = '_';
var TRAILING_WILD_CARD_REPLACERS = (_TRAILING_WILD_CARD_R = {}, _defineProperty(_TRAILING_WILD_CARD_R, MODE_IGNORE, function (_, p1) {
var prefix = p1

@@ -289,20 +301,21 @@ // '\^':

return "".concat(prefix, "(?=$|\\/$)");
}]];
}), _defineProperty(_TRAILING_WILD_CARD_R, MODE_CHECK_IGNORE, function (_, p1) {
// When doing `git check-ignore`
var prefix = p1
// '\\\/':
// 'abc/*' DOES match 'abc/' !
? "".concat(p1, "[^/]*") // 'a*' matches 'a'
// 'a*' matches 'aa'
: '[^/]*';
return "".concat(prefix, "(?=$|\\/$)");
}), _TRAILING_WILD_CARD_R);
// A simple cache, because an ignore rule only has only one certain meaning
var regexCache = Object.create(null);
// @param {pattern}
var makeRegex = function makeRegex(pattern, ignoreCase) {
var source = regexCache[pattern];
if (!source) {
source = REPLACERS.reduce(function (prev, _ref) {
var _ref2 = _slicedToArray(_ref, 2),
matcher = _ref2[0],
replacer = _ref2[1];
return prev.replace(matcher, replacer.bind(pattern));
}, pattern);
regexCache[pattern] = source;
}
return ignoreCase ? new RegExp(source, 'i') : new RegExp(source);
var makeRegexPrefix = function makeRegexPrefix(pattern) {
return REPLACERS.reduce(function (prev, _ref) {
var _ref2 = _slicedToArray(_ref, 2),
matcher = _ref2[0],
replacer = _ref2[1];
return prev.replace(matcher, replacer.bind(pattern));
}, pattern);
};

@@ -321,21 +334,56 @@ var isString = function isString(subject) {

var splitPattern = function splitPattern(pattern) {
return pattern.split(REGEX_SPLITALL_CRLF);
return pattern.split(REGEX_SPLITALL_CRLF).filter(Boolean);
};
var IgnoreRule = /*#__PURE__*/_createClass(function IgnoreRule(origin, pattern, negative, regex) {
_classCallCheck(this, IgnoreRule);
this.origin = origin;
this.pattern = pattern;
this.negative = negative;
this.regex = regex;
});
var createRule = function createRule(pattern, ignoreCase) {
var origin = pattern;
var IgnoreRule = /*#__PURE__*/function () {
function IgnoreRule(pattern, mark, body, ignoreCase, negative, prefix) {
_classCallCheck(this, IgnoreRule);
this.pattern = pattern;
this.mark = mark;
this.negative = negative;
define(this, 'body', body);
define(this, 'ignoreCase', ignoreCase);
define(this, 'regexPrefix', prefix);
}
_createClass(IgnoreRule, [{
key: "regex",
get: function get() {
var key = UNDERSCORE + MODE_IGNORE;
if (this[key]) {
return this[key];
}
return this._make(MODE_IGNORE, key);
}
}, {
key: "checkRegex",
get: function get() {
var key = UNDERSCORE + MODE_CHECK_IGNORE;
if (this[key]) {
return this[key];
}
return this._make(MODE_CHECK_IGNORE, key);
}
}, {
key: "_make",
value: function _make(mode, key) {
var str = this.regexPrefix.replace(REGEX_REPLACE_TRAILING_WILDCARD,
// It does not need to bind pattern
TRAILING_WILD_CARD_REPLACERS[mode]);
var regex = this.ignoreCase ? new RegExp(str, 'i') : new RegExp(str);
return define(this, key, regex);
}
}]);
return IgnoreRule;
}();
var createRule = function createRule(_ref3, ignoreCase) {
var pattern = _ref3.pattern,
mark = _ref3.mark;
var negative = false;
var body = pattern;
// > An optional prefix "!" which negates the pattern;
if (pattern.indexOf('!') === 0) {
if (body.indexOf('!') === 0) {
negative = true;
pattern = pattern.substr(1);
body = body.substr(1);
}
pattern = pattern
body = body
// > Put a backslash ("\") in front of the first "!" for patterns that

@@ -347,5 +395,92 @@ // > begin with a literal "!", for example, `"\!important!.txt"`.

.replace(REGEX_REPLACE_LEADING_EXCAPED_HASH, '#');
var regex = makeRegex(pattern, ignoreCase);
return new IgnoreRule(origin, pattern, negative, regex);
var regexPrefix = makeRegexPrefix(body);
return new IgnoreRule(pattern, mark, body, ignoreCase, negative, regexPrefix);
};
var RuleManager = /*#__PURE__*/function () {
function RuleManager(ignoreCase) {
_classCallCheck(this, RuleManager);
this._ignoreCase = ignoreCase;
this._rules = [];
}
_createClass(RuleManager, [{
key: "_add",
value: function _add(pattern) {
// #32
if (pattern && pattern[KEY_IGNORE]) {
this._rules = this._rules.concat(pattern._rules._rules);
this._added = true;
return;
}
if (isString(pattern)) {
pattern = {
pattern: pattern
};
}
if (checkPattern(pattern.pattern)) {
var rule = createRule(pattern, this._ignoreCase);
this._added = true;
this._rules.push(rule);
}
}
// @param {Array<string> | string | Ignore} pattern
}, {
key: "add",
value: function add(pattern) {
this._added = false;
makeArray(isString(pattern) ? splitPattern(pattern) : pattern).forEach(this._add, this);
return this._added;
}
// Test one single path without recursively checking parent directories
//
// - checkUnignored `boolean` whether should check if the path is unignored,
// setting `checkUnignored` to `false` could reduce additional
// path matching.
// - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
// @returns {TestResult} true if a file is ignored
}, {
key: "test",
value: function test(path, checkUnignored, mode) {
var ignored = false;
var unignored = false;
var matchedRule;
this._rules.forEach(function (rule) {
var negative = rule.negative;
// | 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
if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
return;
}
var matched = rule[mode].test(path);
if (!matched) {
return;
}
ignored = !negative;
unignored = negative;
matchedRule = negative ? UNDEFINED : rule;
});
var ret = {
ignored: ignored,
unignored: unignored
};
if (matchedRule) {
ret.rule = matchedRule;
}
return ret;
}
}]);
return RuleManager;
}();
var throwError = function throwError(message, Ctor) {

@@ -375,2 +510,5 @@ throw new Ctor(message);

checkPath.isNotRelative = isNotRelative;
// On windows, the following function will be replaced
/* istanbul ignore next */
checkPath.convert = function (p) {

@@ -381,14 +519,13 @@ return p;

function Ignore() {
var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
_ref3$ignorecase = _ref3.ignorecase,
ignorecase = _ref3$ignorecase === void 0 ? true : _ref3$ignorecase,
_ref3$ignoreCase = _ref3.ignoreCase,
ignoreCase = _ref3$ignoreCase === void 0 ? ignorecase : _ref3$ignoreCase,
_ref3$allowRelativePa = _ref3.allowRelativePaths,
allowRelativePaths = _ref3$allowRelativePa === void 0 ? false : _ref3$allowRelativePa;
var _ref4 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
_ref4$ignorecase = _ref4.ignorecase,
ignorecase = _ref4$ignorecase === void 0 ? true : _ref4$ignorecase,
_ref4$ignoreCase = _ref4.ignoreCase,
ignoreCase = _ref4$ignoreCase === void 0 ? ignorecase : _ref4$ignoreCase,
_ref4$allowRelativePa = _ref4.allowRelativePaths,
allowRelativePaths = _ref4$allowRelativePa === void 0 ? false : _ref4$allowRelativePa;
_classCallCheck(this, Ignore);
define(this, KEY_IGNORE, true);
this._rules = [];
this._ignoreCase = ignoreCase;
this._allowRelativePaths = allowRelativePaths;
this._rules = new RuleManager(ignoreCase);
this._strictPathCheck = !allowRelativePaths;
this._initCache();

@@ -399,31 +536,15 @@ }

value: function _initCache() {
// A cache for the result of `.ignores()`
this._ignoreCache = Object.create(null);
// A cache for the result of `.test()`
this._testCache = Object.create(null);
}
}, {
key: "_addPattern",
value: function _addPattern(pattern) {
// #32
if (pattern && pattern[KEY_IGNORE]) {
this._rules = this._rules.concat(pattern._rules);
this._added = true;
return;
}
if (checkPattern(pattern)) {
var rule = createRule(pattern, this._ignoreCase);
this._added = true;
this._rules.push(rule);
}
}
// @param {Array<string> | string | Ignore} pattern
}, {
key: "add",
value: function 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) {
if (this._rules.add(pattern)) {
// Some rules have just added to the ignore,
// making the behavior changed,
// so we need to re-initialize the result cache
this._initCache();

@@ -441,40 +562,2 @@ }

// | 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
}, {
key: "_testOne",
value: function _testOne(path, checkUnignored) {
var ignored = false;
var unignored = false;
this._rules.forEach(function (rule) {
var negative = rule.negative;
if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
return;
}
var matched = rule.regex.test(path);
if (matched) {
ignored = !negative;
unignored = negative;
}
});
return {
ignored: ignored,
unignored: unignored
};
}
// @returns {TestResult}

@@ -487,8 +570,34 @@ }, {

&& checkPath.convert(originalPath);
checkPath(path, originalPath, this._allowRelativePaths ? RETURN_FALSE : throwError);
checkPath(path, originalPath, this._strictPathCheck ? throwError : RETURN_FALSE);
return this._t(path, cache, checkUnignored, slices);
}
}, {
key: "checkIgnore",
value: function checkIgnore(path) {
// If the path doest not end with a slash, `.ignores()` is much equivalent
// to `git check-ignore`
if (!REGEX_TEST_TRAILING_SLASH.test(path)) {
return this.test(path);
}
var slices = path.split(SLASH).filter(Boolean);
slices.pop();
if (slices.length) {
var parent = this._t(slices.join(SLASH) + SLASH, this._testCache, true, slices);
if (parent.ignored) {
return parent;
}
}
return this._rules.test(path, false, MODE_CHECK_IGNORE);
}
}, {
key: "_t",
value: function _t(path, cache, checkUnignored, slices) {
value: function _t(
// The path to be tested
path,
// The cache for the result of a certain checking
cache,
// Whether should check if the path is unignored
checkUnignored,
// The path slices
slices) {
if (path in cache) {

@@ -500,3 +609,3 @@ return cache[path];

// ['path', 'to', 'a.js']
slices = path.split(SLASH);
slices = path.split(SLASH).filter(Boolean);
}

@@ -507,3 +616,3 @@ slices.pop();

if (!slices.length) {
return cache[path] = this._testOne(path, checkUnignored);
return cache[path] = this._rules.test(path, checkUnignored, MODE_IGNORE);
}

@@ -516,3 +625,3 @@ var parent = this._t(slices.join(SLASH) + SLASH, cache, checkUnignored, slices);

// > that file is excluded.
? parent : this._testOne(path, checkUnignored);
? parent : this._rules.test(path, checkUnignored, MODE_IGNORE);
}

@@ -555,9 +664,5 @@ }, {

// Fixes typescript
factory["default"] = factory;
module.exports = factory;
// Windows
// --------------------------------------------------------------
/* istanbul ignore if */
/* istanbul ignore next */
if (

@@ -574,6 +679,12 @@ // Detect `process` so that it can run in browsers.

// 'd:\\foo'
var REGIX_IS_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
var REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
checkPath.isNotRelative = function (path) {
return REGIX_IS_WINDOWS_PATH_ABSOLUTE.test(path) || isNotRelative(path);
return REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path) || isNotRelative(path);
};
}
// COMMONJS_EXPORTS ////////////////////////////////////////////////////////////
// Fixes typescript
factory["default"] = factory;
module.exports = factory;
{
"name": "ignore",
"version": "6.0.2",
"version": "7.0.0",
"description": "Ignore is a manager and filter for .gitignore rules, the one used by eslint, gitbook and many others.",
"main": "index.js",
"module": "index.mjs",
"types": "index.d.ts",
"files": [
"legacy.js",
"index.js",
"index.mjs",
"index.d.ts",

@@ -13,18 +17,19 @@ "LICENSE-MIT"

"prepublishOnly": "npm run build",
"build": "babel -o legacy.js index.js",
"build": "babel -o legacy.js index.js && node ./scripts/build.js",
"test:lint": "eslint .",
"test:tsc": "tsc ./test/ts/simple.ts --lib ES6",
"test:tsc:16": "tsc ./test/ts/simple.ts --lib ES6 --moduleResolution Node16 --module Node16",
"test:ts": "node ./test/ts/simple.js",
"tap": "tap --reporter classic",
"test:git": "npm run tap test/git-check-ignore.js",
"test:ignore": "npm run tap test/ignore.js",
"test:ignore:only": "IGNORE_ONLY_IGNORES=1 npm run tap test/ignore.js",
"test:others": "npm run tap test/others.js",
"test:cases": "npm run tap test/*.js -- --coverage",
"test:no-coverage": "npm run tap test/*.js -- --no-check-coverage",
"test:only": "npm run test:lint && npm run test:tsc && npm run test:ts && npm run test:cases",
"test:git": "npm run tap test/git-check-ignore.test.js",
"test:ignore": "npm run tap test/ignore.test.js",
"test:ignore:only": "IGNORE_ONLY_IGNORES=1 npm run tap test/ignore.test.js",
"test:others": "npm run tap test/others.test.js",
"test:cases": "npm run tap test/*.test.js -- --coverage",
"test:no-coverage": "npm run tap test/*.test.js -- --no-check-coverage",
"test:only": "npm run test:lint && npm run build && npm run test:tsc && npm run test:tsc:16 && npm run test:ts && npm run test:cases",
"test": "npm run test:only",
"test:win32": "IGNORE_TEST_WIN32=1 npm run test",
"report": "tap --coverage-report=html",
"posttest": "npm run report && codecov"
"// posttest": "npm run report && codecov"
},

@@ -59,3 +64,3 @@ "repository": {

"@babel/preset-env": "^7.22.9",
"codecov": "^3.8.2",
"codecov": "^3.8.3",
"debug": "^4.3.4",

@@ -71,3 +76,3 @@ "eslint": "^8.46.0",

"tmp": "0.2.3",
"typescript": "^5.1.6"
"typescript": "^5.6.2"
},

@@ -74,0 +79,0 @@ "engines": {

+119
-65

@@ -1,36 +0,14 @@

<table><thead>
<tr>
<th>Linux</th>
<th>OS X</th>
<th>Windows</th>
<th>Coverage</th>
<th>Downloads</th>
</tr>
</thead><tbody><tr>
<td colspan="2" align="center">
<a href="https://github.com/kaelzhang/node-ignore/actions/workflows/nodejs.yml">
<img
src="https://github.com/kaelzhang/node-ignore/actions/workflows/nodejs.yml/badge.svg"
alt="Build Status" /></a>
</td>
<td align="center">
<a href="https://ci.appveyor.com/project/kaelzhang/node-ignore">
<img
src="https://ci.appveyor.com/api/projects/status/github/kaelzhang/node-ignore?branch=master&svg=true"
alt="Windows Build Status" /></a>
</td>
<td align="center">
<a href="https://codecov.io/gh/kaelzhang/node-ignore">
<img
src="https://codecov.io/gh/kaelzhang/node-ignore/branch/master/graph/badge.svg"
alt="Coverage Status" /></a>
</td>
<td align="center">
<a href="https://www.npmjs.org/package/ignore">
<img
src="http://img.shields.io/npm/dm/ignore.svg"
alt="npm module downloads per month" /></a>
</td>
</tr></tbody></table>
| Linux / MacOS / Windows | Coverage | Downloads |
| ----------------------- | -------- | --------- |
| [![build][bb]][bl] | [![coverage][cb]][cl] | [![downloads][db]][dl] |
[bb]: https://github.com/kaelzhang/node-ignore/actions/workflows/nodejs.yml/badge.svg
[bl]: https://github.com/kaelzhang/node-ignore/actions/workflows/nodejs.yml
[cb]: https://codecov.io/gh/kaelzhang/node-ignore/branch/master/graph/badge.svg
[cl]: https://codecov.io/gh/kaelzhang/node-ignore
[db]: http://img.shields.io/npm/dm/ignore.svg
[dl]: https://www.npmjs.org/package/ignore
# ignore

@@ -127,5 +105,7 @@

## .add(patterns: Array<string | Ignore>): this
## .add({pattern: string, mark?: string}): this since 7.0.0
- **pattern** `String | Ignore` An ignore pattern string, or the `Ignore` instance
- **patterns** `Array<String | Ignore>` Array of ignore patterns.
- **pattern** `string | Ignore` An ignore pattern string, or the `Ignore` instance
- **patterns** `Array<string | Ignore>` Array of ignore patterns.
- **mark?** `string` Pattern mark, which is used to associate the pattern with a certain marker, such as the line no of the `.gitignore` file. Actually it could be an arbitrary string and is optional.

@@ -153,28 +133,16 @@ Adds a rule or several rules to the current manager.

## <strike>.addIgnoreFile(path)</strike>
## .ignores(pathname: [Pathname](#pathname-conventions)): boolean
REMOVED in `3.x` for now.
> new in 3.2.0
To upgrade `ignore@2.x` up to `3.x`, use
Returns `Boolean` whether `pathname` should be ignored.
```js
import fs from 'fs'
if (fs.existsSync(filename)) {
ignore().add(fs.readFileSync(filename).toString())
}
ig.ignores('.abc/a.js') // true
```
instead.
Please **PAY ATTENTION** that `.ignores()` is **NOT** equivalent to `git check-ignore` although in most cases they return equivalent results.
## .filter(paths: Array&lt;Pathname&gt;): Array&lt;Pathname&gt;
However, for the purposes of imitating the behavior of `git check-ignore`, please use `.checkIgnore()` instead.
```ts
type Pathname = string
```
Filters the given array of pathnames, and returns the filtered array.
- **paths** `Array.<Pathname>` The array of `pathname`s to be filtered.
### `Pathname` Conventions:

@@ -235,4 +203,8 @@

`node-ignore` does NO `fs.stat` during path matching, so for the example below:
`node-ignore` does NO `fs.stat` during path matching, so `node-ignore` treats
- `foo` as a file
- **`foo/` as a directory**
For the example below:
```js

@@ -272,12 +244,13 @@ // First, we add a ignore pattern to ignore a directory

## .ignores(pathname: Pathname): boolean
> new in 3.2.0
## .filter(paths: Array&lt;Pathname&gt;): Array&lt;Pathname&gt;
Returns `Boolean` whether `pathname` should be ignored.
```js
ig.ignores('.abc/a.js') // true
```ts
type Pathname = string
```
Filters the given array of pathnames, and returns the filtered array.
- **paths** `Array.<Pathname>` The array of `pathname`s to be filtered.
## .createFilter()

@@ -289,7 +262,10 @@

## .test(pathname: Pathname) since 5.0.0
## .test(pathname: Pathname): TestResult
> New in 5.0.0
Returns `TestResult`
```ts
// Since 5.0.0
interface TestResult {

@@ -299,3 +275,15 @@ ignored: boolean

unignored: boolean
// The `IgnoreRule` which ignores the pathname
rule?: IgnoreRule
}
// Since 7.0.0
interface IgnoreRule {
// The original pattern
pattern: string
// Whether the pattern is a negative pattern
negative: boolean
// Which is used for other packages to build things upon `node-ignore`
mark?: string
}
```

@@ -307,4 +295,38 @@

## static `ignore.isPathValid(pathname): boolean` since 5.0.0
## .checkIgnore(target: string): TestResult
> new in 7.0.0
Debugs gitignore / exclude files, which is equivalent to `git check-ignore -v`. Usually this method is used for other packages to implement the function of `git check-ignore -v` upon `node-ignore`
- **target** `string` the target to test.
Returns `TestResult`
```js
ig.add({
pattern: 'foo/*',
mark: '60'
})
const {
ignored,
rule
} = checkIgnore('foo/')
if (ignored) {
console.log(`.gitignore:${result}:${rule.mark}:${rule.pattern} foo/`)
}
// .gitignore:60:foo/* foo/
```
Please pay attention that this method does not have a strong built-in cache mechanism.
The purpose of introducing this method is to make it possible to implement the `git check-ignore` command in JavaScript based on `node-ignore`.
So do not use this method in those situations where performance is extremely important.
## static `isPathValid(pathname): boolean` since 5.0.0
Check whether the `pathname` is an valid `path.relative()`d path according to the [convention](#1-pathname-should-be-a-pathrelatived-pathname).

@@ -315,5 +337,23 @@

```js
ignore.isPathValid('./foo') // false
import {isPathValid} from 'ignore'
isPathValid('./foo') // false
```
## <strike>.addIgnoreFile(path)</strike>
REMOVED in `3.x` for now.
To upgrade `ignore@2.x` up to `3.x`, use
```js
import fs from 'fs'
if (fs.existsSync(filename)) {
ignore().add(fs.readFileSync(filename).toString())
}
```
instead.
## ignore(options)

@@ -355,2 +395,16 @@

## Upgrade 5.x -> 6.x
To bring better compatibility for TypeScript with `moduleResolution:Node16`, `ignore.isPathValid` has been removed in TypeScript definitions since `6.x`
```js
// < 6, or works with commonjs
ignore.isPathValid('./foo') // false
// >= 6.x
import {isPathValid} from 'ignore'
isPathValid('./foo') // false
```
## Upgrade 4.x -> 5.x

@@ -391,3 +445,3 @@

]
.filter(isValidPath)
.filter(isPathValid)

@@ -394,0 +448,0 @@ ig.filter(paths)