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