From 6fb403b0b8240313b97462e276650d947adaadd1 Mon Sep 17 00:00:00 2001 From: Kael Zhang Date: Thu, 19 Dec 2024 16:24:08 +0800 Subject: [PATCH 01/16] #77: core: refactor RuleManager and IgnoreRule --- index.js | 377 ++++++++++++++++++++++++++++++++----------------- test/ignore.js | 37 +++-- test/others.js | 4 +- 3 files changed, 269 insertions(+), 149 deletions(-) diff --git a/index.js b/index.js index ec857df..d23c72b 100644 --- a/index.js +++ b/index.js @@ -13,13 +13,19 @@ 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, -// . -// .. + +// 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 @@ -68,7 +74,7 @@ const cleanRangeBackSlash = slashes => { const REPLACERS = [ [ - // remove BOM + // Remove BOM // TODO: // Other similar zero-width characters? /^\uFEFF/, @@ -89,7 +95,7 @@ const REPLACERS = [ ) ], - // replace (\ ) with ' ' + // Replace (\ ) with ' ' // (\ ) -> ' ' // (\\ ) -> '\\ ' // (\\\ ) -> '\\ ' @@ -293,51 +299,61 @@ const REPLACERS = [ ? `${match}$` // foo matches 'foo' and 'foo/' : `${match}(?=$|\\/$)` - ], + ] +] - // trailing wildcard - [ - /(\^|\\\/)?\\\*$/, - (_, p1) => { - const prefix = p1 - // '\^': - // '/*' does not match EMPTY - // '/*' does not match everything +const REGEX_REPLACE_TRAILING_WILDCARD = /(\^|\\\/)?\\\*$/ +const ESCAPED_SLASH = '\\/' +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] - - if (!source) { - source = REPLACERS.reduce( - (prev, [matcher, replacer]) => - prev.replace(matcher, replacer.bind(pattern)), - pattern - ) - regexCache[pattern] = source - } + [MODE_CHECK_IGNORE] (_, p1) { + const prefix = p1 - return ignoreCase - ? new RegExp(source, 'i') - : new RegExp(source) + // When doing `git check-ignore` + ? p1 === ESCAPED_SLASH + // '\\\/': + // 'abc/*' DOES match 'abc/' ! + ? `${p1}[^/]*` + // '\^': + // '/*' does not match EMPTY + // '/*' does not match everything + : `${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. @@ -353,20 +369,57 @@ const splitPattern = pattern => pattern.split(REGEX_SPLITALL_CRLF) class IgnoreRule { constructor ( - origin, - pattern, + // origin, + // pattern, + ignoreCase, negative, - regex + prefix ) { - this.origin = origin - this.pattern = pattern + // this.origin = origin + // this.pattern = pattern + this.ignoreCase = ignoreCase this.negative = negative - this.regex = regex + 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 this[key] = regex } } const createRule = (pattern, ignoreCase) => { - const origin = pattern + // const origin = pattern let negative = false // > An optional prefix "!" which negates the pattern; @@ -383,16 +436,97 @@ const createRule = (pattern, ignoreCase) => { // > begin with a hash. .replace(REGEX_REPLACE_LEADING_EXCAPED_HASH, '#') - const regex = makeRegex(pattern, ignoreCase) + const regexPrefix = makeRegexPrefix(pattern) return new IgnoreRule( - origin, - pattern, + 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 (checkPattern(pattern)) { + const rule = createRule(pattern, this._ignoreCase) + this._added = true + this._rules.push(rule) + } + } + + // @param {Array | 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 + + 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) { + ignored = !negative + unignored = negative + } + }) + + return { + ignored, + unignored + } + } +} + const throwError = (message, Ctor) => { throw new Ctor(message) } @@ -427,6 +561,7 @@ const isNotRelative = path => REGEX_TEST_INVALID_PATH.test(path) checkPath.isNotRelative = isNotRelative checkPath.convert = p => p + class Ignore { constructor ({ ignorecase = true, @@ -435,45 +570,24 @@ class Ignore { } = {}) { define(this, KEY_IGNORE, true) - this._rules = [] - this._ignoreCase = ignoreCase - this._allowRelativePaths = allowRelativePaths + this._rules = new RuleManager(ignoreCase) + this._strictPathCheck = !allowRelativePaths this._initCache() } _initCache () { + // A cache for the result of `.ignores()` 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) - } + // A cache for the result of `.test()` + this._testCache = Object.create(null) } - // @param {Array | 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() } @@ -485,49 +599,6 @@ class Ignore { 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 @@ -537,15 +608,55 @@ class Ignore { checkPath( path, originalPath, - this._allowRelativePaths - ? RETURN_FALSE - : throwError + this._strictPathCheck + ? throwError + : RETURN_FALSE ) return this._t(path, cache, checkUnignored, slices) } - _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.ignores(path) + } + + const slices = path.split(SLASH) + slices.pop() + + if (!slices.length) { + return this.ignores(path) + } + + const parent = this._t( + slices.join(SLASH) + SLASH, + this._ignoreCache, + false, + slices + ) + + if (parent.ignored) { + return true + } + + return this._rules.test(path, false, MODE_CHECK_IGNORE).ignored + } + + _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] } @@ -560,7 +671,7 @@ class Ignore { // If the path has no parent directory, just test it if (!slices.length) { - return cache[path] = this._testOne(path, checkUnignored) + return cache[path] = this._rules.test(path, checkUnignored, MODE_IGNORE) } const parent = this._t( @@ -575,7 +686,7 @@ class Ignore { // > It is not possible to re-include a file if a parent directory of // > that file is excluded. ? parent - : this._testOne(path, checkUnignored) + : this._rules.test(path, checkUnignored, MODE_IGNORE) } ignores (path) { diff --git a/test/ignore.js b/test/ignore.js index b1ca01b..1386645 100755 --- a/test/ignore.js +++ b/test/ignore.js @@ -49,22 +49,29 @@ cases(({ t.end() }) - checkEnv('IGNORE_ONLY_IGNORES') - && tt(`.ignores(path): ${description}`, t => { - const ig = ignore().addPattern(patterns) - - Object.keys(paths_object).forEach(path => { - const should_ignore = !!paths_object[path] - const not = should_ignore ? '' : 'not ' - - t.equal( - ig.ignores(path), - should_ignore, - `path: "${path}" should ${not}be ignored` - ) + const run_ignores = name => { + tt(`.${name}(path): ${description}`, t => { + const ig = ignore().addPattern(patterns) + + Object.keys(paths_object).forEach(path => { + const should_ignore = !!paths_object[path] + const not = should_ignore ? '' : 'not ' + + t.equal( + ig[name](path), + should_ignore, + `path: "${path}" should ${not}be ignored` + ) + }) + t.end() }) - t.end() - }) + } + + checkEnv('IGNORE_ONLY_IGNORES') + && run_ignores('ignores') + + checkEnv('IGNORE_ONLY_CHECK_IGNORE') + && run_ignores('ignores') if (!SHOULD_TEST_WINDOWS) { return diff --git a/test/others.js b/test/others.js index 163f56f..cff867c 100644 --- a/test/others.js +++ b/test/others.js @@ -56,7 +56,9 @@ _test('#32', t => { const aa = {} /* eslint no-underscore-dangle: ["off"] */ - aa._rules = a._rules.slice() + aa._rules = { + _rules: a._rules._rules.slice() + } aa[KEY_IGNORE] = true const b = ignore().add(aa).add('!.abc/e/') From 0b3201c5eedadee876704563c168b54859cf6eb1 Mon Sep 17 00:00:00 2001 From: Kael Zhang Date: Thu, 19 Dec 2024 16:29:29 +0800 Subject: [PATCH 02/16] #77: test: rename files --- test/fixtures/cases.js | 1 + test/{git-check-ignore.js => git-check-ignore.test.js} | 0 test/{ignore.js => ignore.test.js} | 2 +- test/{others.js => others.test.js} | 0 4 files changed, 2 insertions(+), 1 deletion(-) rename test/{git-check-ignore.js => git-check-ignore.test.js} (100%) rename test/{ignore.js => ignore.test.js} (98%) rename test/{others.js => others.test.js} (100%) diff --git a/test/fixtures/cases.js b/test/fixtures/cases.js index bcf2150..8eee8b1 100644 --- a/test/fixtures/cases.js +++ b/test/fixtures/cases.js @@ -1092,6 +1092,7 @@ const ENV_KEYS = [ 'IGNORE_ONLY_FILTER', 'IGNORE_ONLY_CREATE_FILTER', 'IGNORE_ONLY_IGNORES', + 'IGNORE_ONLY_CHECK_IGNORE', 'IGNORE_ONLY_WIN32', 'IGNORE_ONLY_FIXTURES', 'IGNORE_ONLY_OTHERS' diff --git a/test/git-check-ignore.js b/test/git-check-ignore.test.js similarity index 100% rename from test/git-check-ignore.js rename to test/git-check-ignore.test.js diff --git a/test/ignore.js b/test/ignore.test.js similarity index 98% rename from test/ignore.js rename to test/ignore.test.js index 1386645..0900e56 100755 --- a/test/ignore.js +++ b/test/ignore.test.js @@ -71,7 +71,7 @@ cases(({ && run_ignores('ignores') checkEnv('IGNORE_ONLY_CHECK_IGNORE') - && run_ignores('ignores') + && run_ignores('checkIgnore') if (!SHOULD_TEST_WINDOWS) { return diff --git a/test/others.js b/test/others.test.js similarity index 100% rename from test/others.js rename to test/others.test.js From 3eff865755a52e72b7bdca81bbf296d5729c5517 Mon Sep 17 00:00:00 2001 From: Kael Zhang Date: Thu, 19 Dec 2024 21:47:16 +0800 Subject: [PATCH 03/16] #77: .test(): also returns matched rule t --- index.js | 94 +++++++++++++++++++++++------------------- package.json | 10 ++--- test/fixtures/cases.js | 45 ++++++++++++++++---- test/ignore.test.js | 23 ++++++++--- 4 files changed, 113 insertions(+), 59 deletions(-) diff --git a/index.js b/index.js index d23c72b..41f58a0 100644 --- a/index.js +++ b/index.js @@ -5,6 +5,7 @@ function makeArray (subject) { : [subject] } +const UNDEFINED = undefined const EMPTY = '' const SPACE = ' ' const ESCAPE = '\\' @@ -36,8 +37,10 @@ if (typeof Symbol !== 'undefined') { } const KEY_IGNORE = TMP_KEY_IGNORE -const define = (object, key, value) => +const define = (object, key, value) => { Object.defineProperty(object, key, {value}) + return value +} const REGEX_REGEXP_RANGE = /([0-z])-([0-z])/g @@ -302,8 +305,7 @@ const REPLACERS = [ ] ] -const REGEX_REPLACE_TRAILING_WILDCARD = /(\^|\\\/)?\\\*$/ -const ESCAPED_SLASH = '\\/' +const REGEX_REPLACE_TRAILING_WILDCARD = /(^|\\\/)?\\\*$/ const MODE_IGNORE = 'regex' const MODE_CHECK_IGNORE = 'checkRegex' const UNDERSCORE = '_' @@ -327,17 +329,11 @@ const TRAILING_WILD_CARD_REPLACERS = { }, [MODE_CHECK_IGNORE] (_, p1) { + // When doing `git check-ignore` const prefix = p1 - - // When doing `git check-ignore` - ? p1 === ESCAPED_SLASH - // '\\\/': - // 'abc/*' DOES match 'abc/' ! - ? `${p1}[^/]*` - // '\^': - // '/*' does not match EMPTY - // '/*' does not match everything - : `${p1}[^/]+` + // '\\\/': + // 'abc/*' DOES match 'abc/' ! + ? `${p1}[^/]*` // 'a*' matches 'a' // 'a*' matches 'aa' @@ -369,17 +365,18 @@ const splitPattern = pattern => pattern.split(REGEX_SPLITALL_CRLF) class IgnoreRule { constructor ( - // origin, - // pattern, + pattern, + body, ignoreCase, negative, prefix ) { - // this.origin = origin - // this.pattern = pattern - this.ignoreCase = ignoreCase + this.pattern = pattern this.negative = negative - this.regexPrefix = prefix + + define(this, 'body', body) + define(this, 'ignoreCase', ignoreCase) + define(this, 'regexPrefix', prefix) } get regex () { @@ -414,21 +411,21 @@ class IgnoreRule { ? new RegExp(str, 'i') : new RegExp(str) - return this[key] = regex + return define(this, key, regex) } } const createRule = (pattern, ignoreCase) => { - // const origin = pattern 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 // > begin with a literal "!", for example, `"\!important!.txt"`. .replace(REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION, '!') @@ -439,6 +436,8 @@ const createRule = (pattern, ignoreCase) => { const regexPrefix = makeRegexPrefix(pattern) return new IgnoreRule( + pattern, + body, ignoreCase, negative, regexPrefix @@ -490,6 +489,7 @@ class RuleManager { test (path, checkUnignored, mode) { let ignored = false let unignored = false + let matchedRule this._rules.forEach(rule => { const {negative} = rule @@ -514,16 +514,28 @@ class RuleManager { const matched = rule[mode].test(path) - if (matched) { - ignored = !negative - unignored = negative + if (!matched) { + return } + + ignored = !negative + unignored = negative + + matchedRule = negative + ? UNDEFINED + : rule }) - return { + const ret = { ignored, unignored } + + if (matchedRule) { + ret.rule = matchedRule + } + + return ret } } @@ -623,22 +635,20 @@ class Ignore { return this.ignores(path) } - const slices = path.split(SLASH) + const slices = path.split(SLASH).filter(Boolean) slices.pop() - if (!slices.length) { - return this.ignores(path) - } + if (slices.length) { + const parent = this._t( + slices.join(SLASH) + SLASH, + this._ignoreCache, + false, + slices + ) - const parent = this._t( - slices.join(SLASH) + SLASH, - this._ignoreCache, - false, - slices - ) - - if (parent.ignored) { - return true + if (parent.ignored) { + return true + } } return this._rules.test(path, false, MODE_CHECK_IGNORE).ignored @@ -664,7 +674,7 @@ class Ignore { if (!slices) { // path/to/a.js // ['path', 'to', 'a.js'] - slices = path.split(SLASH) + slices = path.split(SLASH).filter(Boolean) } slices.pop() diff --git a/package.json b/package.json index 16a6817..e466472 100644 --- a/package.json +++ b/package.json @@ -20,12 +20,12 @@ "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:git": "npm run tap test/git-check-ignore.test.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: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", diff --git a/test/fixtures/cases.js b/test/fixtures/cases.js index 8eee8b1..92ccf19 100644 --- a/test/fixtures/cases.js +++ b/test/fixtures/cases.js @@ -23,6 +23,33 @@ const cases = [ // ], ///////////////////////////////////////////////////////////////////// [ + '#77: more cases for coverage', + [ + '/*' + ], + { + 'a': 1, + 'a/': 1, + 'a/b/': 1 + } + ], + [ + '#77: directory ending with / not always correctly ignored', + [ + 'c/*', + 'foo/bar/*' + ], + { + 'c/': 1, + 'c': 0, + 'foo/bar/': 1, + 'foo/bar': 0 + }, + false, + false, + // Only for checkIgnore + ['checkIgnore'] + ], [ '#108: gitignore rules with BOM', [ readPatterns('.gitignore-with-BOM'), @@ -1051,13 +1078,16 @@ const real_cases = cases_to_test_only.length : cases exports.cases = iteratee => { - real_cases.forEach(([ - description, - patterns, - paths_object, - test_only, - skip_test_fixture - ]) => { + real_cases.forEach(single => { + const [ + description, + patterns, + paths_object, + test_only, + skip_test_fixture, + scopes = false + ] = single + // All paths to test const paths = Object.keys(paths_object) @@ -1081,6 +1111,7 @@ exports.cases = iteratee => { test_only, skip_test_fixture, paths, + scopes, expected, expect_result }) diff --git a/test/ignore.test.js b/test/ignore.test.js index 0900e56..56a44fb 100755 --- a/test/ignore.test.js +++ b/test/ignore.test.js @@ -14,6 +14,7 @@ const make_win32 = path => path.replace(/\//g, '\\') cases(({ description, + scopes, patterns, paths_object, test_only, @@ -24,7 +25,19 @@ cases(({ ? only : test - checkEnv('IGNORE_ONLY_FILTER') + const check = (env, scope) => { + if (!checkEnv(env)) { + return false + } + + if (!scope || scopes === false) { + return true + } + + return scopes.includes(scope) + } + + check('IGNORE_ONLY_FILTER', 'filter') && tt(`.filter(): ${description}`, t => { const ig = ignore() const result = ig @@ -35,7 +48,7 @@ cases(({ t.end() }) - checkEnv('IGNORE_ONLY_CREATE_FILTER') + check('IGNORE_ONLY_CREATE_FILTER', 'createFilter') && tt(`.createFilter(): ${description}`, t => { const result = paths.filter( ignore() @@ -67,17 +80,17 @@ cases(({ }) } - checkEnv('IGNORE_ONLY_IGNORES') + check('IGNORE_ONLY_IGNORES', 'ignores') && run_ignores('ignores') - checkEnv('IGNORE_ONLY_CHECK_IGNORE') + check('IGNORE_ONLY_CHECK_IGNORE', 'checkIgnore') && run_ignores('checkIgnore') if (!SHOULD_TEST_WINDOWS) { return } - checkEnv('IGNORE_ONLY_WIN32') + check('IGNORE_ONLY_WIN32') && tt(`win32: .filter(): ${description}`, t => { const win_paths = paths.map(make_win32) From 62edbcf0fd327629cd577f709f1169595b0b70d2 Mon Sep 17 00:00:00 2001 From: Kael Zhang Date: Thu, 19 Dec 2024 22:08:13 +0800 Subject: [PATCH 04/16] #77: RuleManager: backward compatibility --- .eslintrc.js | 2 ++ index.js | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index cd6c5e3..aa5e0d7 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -12,6 +12,8 @@ module.exports = { allow: ['_rules', '_test'] }], + 'operator-linebreak': 0, + indent: ['error', 2, { MemberExpression: 0, diff --git a/index.js b/index.js index 41f58a0..e341d44 100644 --- a/index.js +++ b/index.js @@ -433,7 +433,7 @@ const createRule = (pattern, ignoreCase) => { // > begin with a hash. .replace(REGEX_REPLACE_LEADING_EXCAPED_HASH, '#') - const regexPrefix = makeRegexPrefix(pattern) + const regexPrefix = makeRegexPrefix(body) return new IgnoreRule( pattern, @@ -453,7 +453,13 @@ class RuleManager { _add (pattern) { // #32 if (pattern && pattern[KEY_IGNORE]) { - this._rules = this._rules.concat(pattern._rules._rules) + this._rules = this._rules.concat( + pattern._rules._rules + || + // Compatible with the old version + /* istanbul ignore next */ + pattern._rules + ) this._added = true return } From da6e19477574764637616271bb7fe5779f4fec94 Mon Sep 17 00:00:00 2001 From: Kael Zhang Date: Thu, 19 Dec 2024 22:13:50 +0800 Subject: [PATCH 05/16] README.md: more instructions for files name dirs --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1b06712..d19a885 100644 --- a/README.md +++ b/README.md @@ -218,7 +218,11 @@ Then the `paths` might be like this: #### 2. filenames and dirnames -`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 // First, we add a ignore pattern to ignore a directory From 5d278de04cb127ff77d4a04487a4dabe2e8375f7 Mon Sep 17 00:00:00 2001 From: Kael Zhang Date: Thu, 19 Dec 2024 22:58:33 +0800 Subject: [PATCH 06/16] core: supports .add({pattern, mark}) test: fixes tests and coverage --- README.md | 41 +++++++++++++++++++++++++--- index.js | 38 +++++++++++++++----------- test/fixtures/cases.js | 2 +- test/git-check-ignore.test.js | 7 ++++- test/ignore.test.js | 51 +++++++++++++++++++++-------------- 5 files changed, 99 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index d19a885..a3fcd8b 100644 --- a/README.md +++ b/README.md @@ -124,9 +124,11 @@ ig.filter(['.abc\\a.js', '.abc\\d\\e.js']) ## .add(pattern: string | Ignore): this ## .add(patterns: Array): this +## .add({pattern: string, mark?: string}): this -- **pattern** `String | Ignore` An ignore pattern string, or the `Ignore` instance -- **patterns** `Array` Array of ignore patterns. +- **pattern** `string | Ignore` An ignore pattern string, or the `Ignore` instance +- **patterns** `Array` 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. Adds a rule or several rules to the current manager. @@ -284,6 +286,17 @@ interface TestResult { ignored: boolean // true if the `pathname` is finally unignored by some negative pattern unignored: boolean + // The `IgnoreRule` which ignores the pathname + rule?: IgnoreRule +} + +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 } ``` @@ -291,10 +304,32 @@ interface TestResult { - `{ignored: false, unignored: true}`: the `pathname` is unignored - `{ignored: false, unignored: false}`: the `pathname` is never matched by any ignore rules. -## .checkIgnore(pattern) since 6.1.0 +## .checkIgnore(pattern) since 7.0.0 > new in 6.1.0 +Debug 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` + +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`. diff --git a/index.js b/index.js index e341d44..414af19 100644 --- a/index.js +++ b/index.js @@ -361,17 +361,21 @@ const checkPattern = pattern => pattern // > A line starting with # serves as a comment. && pattern.indexOf('#') !== 0 -const splitPattern = pattern => pattern.split(REGEX_SPLITALL_CRLF) +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) @@ -415,7 +419,10 @@ class IgnoreRule { } } -const createRule = (pattern, ignoreCase) => { +const createRule = ({ + pattern, + mark +}, ignoreCase) => { let negative = false let body = pattern @@ -437,6 +444,7 @@ const createRule = (pattern, ignoreCase) => { return new IgnoreRule( pattern, + mark, body, ignoreCase, negative, @@ -453,18 +461,18 @@ class RuleManager { _add (pattern) { // #32 if (pattern && pattern[KEY_IGNORE]) { - this._rules = this._rules.concat( - pattern._rules._rules - || - // Compatible with the old version - /* istanbul ignore next */ - pattern._rules - ) + this._rules = this._rules.concat(pattern._rules._rules) this._added = true return } - if (checkPattern(pattern)) { + if (isString(pattern)) { + pattern = { + pattern + } + } + + if (checkPattern(pattern.pattern)) { const rule = createRule(pattern, this._ignoreCase) this._added = true this._rules.push(rule) @@ -638,7 +646,7 @@ class Ignore { // 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.ignores(path) + return this.test(path) } const slices = path.split(SLASH).filter(Boolean) @@ -647,17 +655,17 @@ class Ignore { if (slices.length) { const parent = this._t( slices.join(SLASH) + SLASH, - this._ignoreCache, - false, + this._testCache, + true, slices ) if (parent.ignored) { - return true + return parent } } - return this._rules.test(path, false, MODE_CHECK_IGNORE).ignored + return this._rules.test(path, false, MODE_CHECK_IGNORE) } _t ( diff --git a/test/fixtures/cases.js b/test/fixtures/cases.js index 92ccf19..3a30e4e 100644 --- a/test/fixtures/cases.js +++ b/test/fixtures/cases.js @@ -37,7 +37,7 @@ const cases = [ '#77: directory ending with / not always correctly ignored', [ 'c/*', - 'foo/bar/*' + {pattern: 'foo/bar/*'} ], { 'c/': 1, diff --git a/test/git-check-ignore.test.js b/test/git-check-ignore.test.js index 79a28a3..4bae133 100644 --- a/test/git-check-ignore.test.js +++ b/test/git-check-ignore.test.js @@ -65,12 +65,17 @@ const debugSpawn = (...args) => { debug(out.output.toString()) } +const mapObjectRule = rule => + typeof rule === 'string' + ? rule + : rule.pattern + const getNativeGitIgnoreResults = (rules, paths) => { const dir = createUniqueTmp() const gitignore = typeof rules === 'string' ? rules - : rules.join('\n') + : rules.map(mapObjectRule).join('\n') touch(dir, '.gitignore', gitignore) diff --git a/test/ignore.test.js b/test/ignore.test.js index 56a44fb..054824f 100755 --- a/test/ignore.test.js +++ b/test/ignore.test.js @@ -62,29 +62,40 @@ cases(({ t.end() }) - const run_ignores = name => { - tt(`.${name}(path): ${description}`, t => { - const ig = ignore().addPattern(patterns) - - Object.keys(paths_object).forEach(path => { - const should_ignore = !!paths_object[path] - const not = should_ignore ? '' : 'not ' - - t.equal( - ig[name](path), - should_ignore, - `path: "${path}" should ${not}be ignored` - ) - }) - t.end() - }) - } - check('IGNORE_ONLY_IGNORES', 'ignores') - && run_ignores('ignores') + && tt(`.ignores(path): ${description}`, t => { + const ig = ignore().addPattern(patterns) + + Object.keys(paths_object).forEach(path => { + const should_ignore = !!paths_object[path] + const not = should_ignore ? '' : 'not ' + + t.equal( + ig.ignores(path), + should_ignore, + `path: "${path}" should ${not}be ignored` + ) + }) + t.end() + }) check('IGNORE_ONLY_CHECK_IGNORE', 'checkIgnore') - && run_ignores('checkIgnore') + && tt(`.checkIgnore(path): ${description}`, t => { + const ig = ignore().addPattern(patterns) + + Object.keys(paths_object).forEach(path => { + const should_ignore = !!paths_object[path] + const not = should_ignore ? '' : 'not ' + const {ignored} = ig.checkIgnore(path) + + t.equal( + ignored, + should_ignore, + `path: "${path}" should ${not}be ignored` + ) + }) + t.end() + }) if (!SHOULD_TEST_WINDOWS) { return From 6a06a87f138137a7b05f0920338681ab5b2a32c4 Mon Sep 17 00:00:00 2001 From: Kael Zhang Date: Thu, 19 Dec 2024 23:08:55 +0800 Subject: [PATCH 07/16] README.md: update --- README.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a3fcd8b..b9c4fcd 100644 --- a/README.md +++ b/README.md @@ -124,7 +124,7 @@ ig.filter(['.abc\\a.js', '.abc\\d\\e.js']) ## .add(pattern: string | Ignore): this ## .add(patterns: Array): this -## .add({pattern: string, mark?: string}): this +## .add({pattern: string, mark?: string}): this since 7.0.0 - **pattern** `string | Ignore` An ignore pattern string, or the `Ignore` instance - **patterns** `Array` Array of ignore patterns. @@ -277,11 +277,14 @@ Creates a filter function which could filter an array of paths with `Array.proto Returns `function(path)` the filter function. -## .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 { ignored: boolean // true if the `pathname` is finally unignored by some negative pattern @@ -290,6 +293,7 @@ interface TestResult { rule?: IgnoreRule } +// Since 7.0.0 interface IgnoreRule { // The original pattern pattern: string @@ -304,11 +308,13 @@ interface IgnoreRule { - `{ignored: false, unignored: true}`: the `pathname` is unignored - `{ignored: false, unignored: false}`: the `pathname` is never matched by any ignore rules. -## .checkIgnore(pattern) since 7.0.0 +## .checkIgnore(target: string): TestResult + +> new in 7.0.0 -> new in 6.1.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` -Debug 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` From de3cabe351e50b4a3b8c99990a48b0125b6d76c9 Mon Sep 17 00:00:00 2001 From: Kael Zhang Date: Fri, 20 Dec 2024 19:39:33 +0800 Subject: [PATCH 08/16] test: try to fix istanbul coverage for windows --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 414af19..0467b1d 100644 --- a/index.js +++ b/index.js @@ -741,7 +741,7 @@ factory.isPathValid = isPathValid // Windows // -------------------------------------------------------------- -/* istanbul ignore next */ +/* istanbul ignore if */ if ( // Detect `process` so that it can run in browsers. typeof process !== 'undefined' From 8e378e973da7faa94b98eeb8a4c0c1031244dfe6 Mon Sep 17 00:00:00 2001 From: Kael Zhang Date: Fri, 20 Dec 2024 22:29:47 +0800 Subject: [PATCH 09/16] test: R.I.P. appveyor --- .github/workflows/nodejs.yml | 6 +++--- README.md | 8 +------- appveyor.yml | 22 ---------------------- index.js | 4 ++-- package.json | 2 +- test/ignore.test.js | 2 +- 6 files changed, 8 insertions(+), 36 deletions(-) delete mode 100644 appveyor.yml diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 1d8db7b..05142b1 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -4,13 +4,13 @@ on: [push] jobs: build: - - runs-on: ubuntu-latest - strategy: matrix: + os: [ubuntu-latest, windows-latest, macos-latest] node-version: [20.x] + runs-on: ${{ matrix.os }} + steps: - uses: actions/checkout@v1 - name: Use Node.js ${{ matrix.node-version }} diff --git a/README.md b/README.md index b9c4fcd..fbe78f6 100644 --- a/README.md +++ b/README.md @@ -7,18 +7,12 @@ Downloads - + Build Status - - - Windows Build Status - - REGIX_IS_WINDOWS_PATH_ABSOLUTE.test(path) + REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path) || isNotRelative(path) } diff --git a/package.json b/package.json index e466472..e77c79c 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "test:ts": "node ./test/ts/simple.js", "tap": "tap --reporter classic", "test:git": "npm run tap test/git-check-ignore.test.js", - "test:ignore": "npm run tap test/ignore.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", diff --git a/test/ignore.test.js b/test/ignore.test.js index 054824f..514290f 100755 --- a/test/ignore.test.js +++ b/test/ignore.test.js @@ -101,7 +101,7 @@ cases(({ return } - check('IGNORE_ONLY_WIN32') + check('IGNORE_ONLY_WIN32', 'filter') && tt(`win32: .filter(): ${description}`, t => { const win_paths = paths.map(make_win32) From 5e756a41946a4d4525228f1ca49f169dab76c568 Mon Sep 17 00:00:00 2001 From: Kael Zhang Date: Fri, 20 Dec 2024 22:38:30 +0800 Subject: [PATCH 10/16] README.md: no tables --- README.md | 40 ++++++++++++---------------------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index fbe78f6..d59e55e 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,15 @@ - - - - - - - - - - - - -
LinuxOS XWindowsCoverageDownloads
- - Build Status - - - Coverage Status - - - npm module downloads per month -
+| 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 From 0e911859da861aa2eb2d703191f9b8ef77a4cb04 Mon Sep 17 00:00:00 2001 From: Kael Zhang Date: Fri, 20 Dec 2024 22:43:13 +0800 Subject: [PATCH 11/16] eslint: fixes linebreak-style bug in eslint --- .eslintrc.js | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index aa5e0d7..4efed74 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,24 +1,31 @@ // http://eslint.org/docs/user-guide/configuring +const rules = { + 'no-underscore-dangle': ['error', { + allowAfterThis: true, + enforceInMethodNames: false, + // node-ignore only + allow: ['_rules', '_test'] + }], + + 'operator-linebreak': 0, + + indent: ['error', 2, { + MemberExpression: 0, + + // Eslint bug + ignoreComments: true + }] +} + +if (process.platform === 'win32') { + // Ignore linebreak-style on Windows, due to a bug of eslint + rules['linebreak-style'] = 0 +} + module.exports = { // Uses `require.resolve` to support npm linked eslint-config extends: require.resolve('eslint-config-ostai'), root: true, - rules: { - 'no-underscore-dangle': ['error', { - allowAfterThis: true, - enforceInMethodNames: false, - // node-ignore only - allow: ['_rules', '_test'] - }], - - 'operator-linebreak': 0, - - indent: ['error', 2, { - MemberExpression: 0, - - // Eslint bug - ignoreComments: true - }] - } + rules } From ca808dc34555da2aa12a1d61b2f758f2c6d279f1 Mon Sep 17 00:00:00 2001 From: Kael Zhang Date: Fri, 20 Dec 2024 22:58:24 +0800 Subject: [PATCH 12/16] test: fixes skipped pending for windows --- test/git-check-ignore.test.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/git-check-ignore.test.js b/test/git-check-ignore.test.js index 4bae133..e3e7a88 100644 --- a/test/git-check-ignore.test.js +++ b/test/git-check-ignore.test.js @@ -162,6 +162,10 @@ checkEnv('IGNORE_ONLY_FIXTURES') && cases(({ // which `node-ignore` should not do as well || !expected.every(notGitBuiltin) ) { + test(`test skipped for windows`, t => { + t.pass() + t.end() + }) return } From 4542293f40ba2c394c7828380e6d10faee1e2a41 Mon Sep 17 00:00:00 2001 From: Kael Zhang Date: Fri, 20 Dec 2024 22:59:43 +0800 Subject: [PATCH 13/16] test: dummy test for windows --- test/git-check-ignore.test.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/git-check-ignore.test.js b/test/git-check-ignore.test.js index e3e7a88..35dc607 100644 --- a/test/git-check-ignore.test.js +++ b/test/git-check-ignore.test.js @@ -162,10 +162,6 @@ checkEnv('IGNORE_ONLY_FIXTURES') && cases(({ // which `node-ignore` should not do as well || !expected.every(notGitBuiltin) ) { - test(`test skipped for windows`, t => { - t.pass() - t.end() - }) return } @@ -176,3 +172,8 @@ checkEnv('IGNORE_ONLY_FIXTURES') && cases(({ t.end() }) }) + +test(`dummy test for windows`, t => { + t.pass() + t.end() +}) From 700c18520ed6799e5450d1bf5344b69adb1c85b3 Mon Sep 17 00:00:00 2001 From: Kael Zhang Date: Fri, 20 Dec 2024 23:06:45 +0800 Subject: [PATCH 14/16] test: try to fix coverage for windows --- index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 402a4a9..c3bda51 100644 --- a/index.js +++ b/index.js @@ -585,6 +585,9 @@ const checkPath = (path, originalPath, doThrow) => { 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 @@ -741,7 +744,7 @@ factory.isPathValid = isPathValid // Windows // -------------------------------------------------------------- -/* istanbul ignore if */ +/* istanbul ignore next */ if ( // Detect `process` so that it can run in browsers. typeof process !== 'undefined' From 65c18e24f3d68de4e3287912ab27ace0e715dbb4 Mon Sep 17 00:00:00 2001 From: Kael Zhang Date: Mon, 23 Dec 2024 19:30:01 +0800 Subject: [PATCH 15/16] #77: bump version 6.1.0 --- README.md | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d59e55e..f79e06e 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ ig.filter(['.abc\\a.js', '.abc\\d\\e.js']) ## .add(pattern: string | Ignore): this ## .add(patterns: Array): this -## .add({pattern: string, mark?: string}): this since 7.0.0 +## .add({pattern: string, mark?: string}): this since 6.1.0 - **pattern** `string | Ignore` An ignore pattern string, or the `Ignore` instance - **patterns** `Array` Array of ignore patterns. @@ -271,7 +271,7 @@ interface TestResult { rule?: IgnoreRule } -// Since 7.0.0 +// Since 6.1.0 interface IgnoreRule { // The original pattern pattern: string @@ -288,7 +288,7 @@ interface IgnoreRule { ## .checkIgnore(target: string): TestResult -> new in 7.0.0 +> new in 6.1.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` diff --git a/package.json b/package.json index e77c79c..be91788 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ignore", - "version": "6.0.1", + "version": "6.1.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", From 079e1b0619e16ca18a4d8454c5c3865b78dd636c Mon Sep 17 00:00:00 2001 From: Kael Zhang Date: Mon, 23 Dec 2024 19:30:50 +0800 Subject: [PATCH 16/16] 7.0.0 --- README.md | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f79e06e..d59e55e 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ ig.filter(['.abc\\a.js', '.abc\\d\\e.js']) ## .add(pattern: string | Ignore): this ## .add(patterns: Array): this -## .add({pattern: string, mark?: string}): this since 6.1.0 +## .add({pattern: string, mark?: string}): this since 7.0.0 - **pattern** `string | Ignore` An ignore pattern string, or the `Ignore` instance - **patterns** `Array` Array of ignore patterns. @@ -271,7 +271,7 @@ interface TestResult { rule?: IgnoreRule } -// Since 6.1.0 +// Since 7.0.0 interface IgnoreRule { // The original pattern pattern: string @@ -288,7 +288,7 @@ interface IgnoreRule { ## .checkIgnore(target: string): TestResult -> new in 6.1.0 +> 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` diff --git a/package.json b/package.json index be91788..aa00c13 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ignore", - "version": "6.1.0", + "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",