diff --git a/README.md b/README.md index 4bdac9d..8f26cc6 100644 --- a/README.md +++ b/README.md @@ -298,7 +298,19 @@ interface TestResult { - `{ignored: false, unignored: true}`: the `pathname` is unignored - `{ignored: false, unignored: false}`: the `pathname` is never matched by any ignore rules. -## `options.ignorecase` since 4.0.0 +## static `ignore.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). + +This method is **NOT** used to check if an ignore pattern is valid. + +```js +ignore.isPathValid('./foo') // false +``` + +## ignore(options) + +### `options.ignorecase` since 4.0.0 Similar as the `core.ignorecase` option of [git-config](https://git-scm.com/docs/git-config), `node-ignore` will be case insensitive if `options.ignorecase` is set to `true` (the default value), otherwise case sensitive. @@ -312,14 +324,20 @@ ig.add('*.png') ig.ignores('*.PNG') // false ``` -## static `ignore.isPathValid(pathname): boolean` since 5.0.0 +### `options.ignoreCase?: boolean` since 5.2.0 -Check whether the `pathname` is an valid `path.relative()`d path according to the [convention](#1-pathname-should-be-a-pathrelatived-pathname). +Which is alternative to `options.ignoreCase` -This method is **NOT** used to check if an ignore pattern is valid. +### `options.allowRelativePaths?: boolean` since 5.2.0 + +This option brings backward compatibility with projects which based on `ignore@4.x` + +However, passing a relative path to test if it is ignored or not is not a good practise, which might lead to unexpected behavior ```js -ignore.isPathValid('./foo') // false +ignore({ + allowRelativePaths: true +}).ignores('../foo/bar.js') // And it will not throw ``` **** @@ -328,7 +346,9 @@ ignore.isPathValid('./foo') // false ## Upgrade 4.x -> 5.x -Since `5.0.0`, if an invalid `Pathname` passed into `ig.ignores()`, an error will be thrown, while `ignore < 5.0.0` did not make sure what the return value was, as well as +Since `5.0.0`, if an invalid `Pathname` passed into `ig.ignores()`, an error will be thrown, unless `options.allowRelative = true` is passed to the `Ignore` factory. + +While `ignore < 5.0.0` did not make sure what the return value was, as well as ```ts .ignores(pathname: Pathname): boolean diff --git a/index.d.ts b/index.d.ts index 73dea9d..520eafa 100644 --- a/index.d.ts +++ b/index.d.ts @@ -20,7 +20,7 @@ export interface Ignore { * @returns The filtered array of paths */ filter(pathnames: readonly Pathname[]): Pathname[] - + /** * Creates a filter function which could filter * an array of paths with Array.prototype.filter. @@ -44,6 +44,9 @@ export interface Ignore { interface Options { ignorecase?: boolean + // For compatibility + ignoreCase?: boolean + allowRelativePaths?: boolean } /** diff --git a/index.js b/index.js index 0ff33ea..d935eb1 100644 --- a/index.js +++ b/index.js @@ -30,6 +30,8 @@ const define = (object, key, 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( @@ -288,7 +290,7 @@ const REPLACERS = [ const regexCache = Object.create(null) // @param {pattern} -const makeRegex = (pattern, ignorecase) => { +const makeRegex = (pattern, ignoreCase) => { let source = regexCache[pattern] if (!source) { @@ -299,7 +301,7 @@ const makeRegex = (pattern, ignorecase) => { regexCache[pattern] = source } - return ignorecase + return ignoreCase ? new RegExp(source, 'i') : new RegExp(source) } @@ -330,7 +332,7 @@ class IgnoreRule { } } -const createRule = (pattern, ignorecase) => { +const createRule = (pattern, ignoreCase) => { const origin = pattern let negative = false @@ -348,7 +350,7 @@ const createRule = (pattern, ignorecase) => { // > begin with a hash. .replace(REGEX_REPLACE_LEADING_EXCAPED_HASH, '#') - const regex = makeRegex(pattern, ignorecase) + const regex = makeRegex(pattern, ignoreCase) return new IgnoreRule( origin, @@ -394,12 +396,15 @@ checkPath.convert = p => p class Ignore { constructor ({ - ignorecase = true + ignorecase = true, + ignoreCase = ignorecase, + allowRelativePaths = false } = {}) { define(this, KEY_IGNORE, true) this._rules = [] - this._ignorecase = ignorecase + this._ignoreCase = ignoreCase + this._allowRelativePaths = allowRelativePaths this._initCache() } @@ -417,7 +422,7 @@ class Ignore { } if (checkPattern(pattern)) { - const rule = createRule(pattern, this._ignorecase) + const rule = createRule(pattern, this._ignoreCase) this._added = true this._rules.push(rule) } @@ -496,7 +501,13 @@ class Ignore { // Supports nullable path && checkPath.convert(originalPath) - checkPath(path, originalPath, throwError) + checkPath( + path, + originalPath, + this._allowRelativePaths + ? RETURN_FALSE + : throwError + ) return this._t(path, cache, checkUnignored, slices) } @@ -554,10 +565,8 @@ class Ignore { const factory = options => new Ignore(options) -const returnFalse = () => false - const isPathValid = path => - checkPath(path && checkPath.convert(path), path, returnFalse) + checkPath(path && checkPath.convert(path), path, RETURN_FALSE) factory.isPathValid = isPathValid diff --git a/package.json b/package.json index 27f37b7..45de575 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ignore", - "version": "5.1.9", + "version": "5.2.0", "description": "Ignore is a manager and filter for .gitignore rules, the one used by eslint, gitbook and many others.", "files": [ "legacy.js", diff --git a/test/others.js b/test/others.js index ea304c7..f317a70 100644 --- a/test/others.js +++ b/test/others.js @@ -227,3 +227,17 @@ IGNORE_TEST_CASES.forEach(([d, patterns, path, [ignored, unignored]]) => { t.end() }) }) + +_test('options.allowRelativePaths', t => { + const ig = ignore({ + allowRelativePaths: true + }) + + ig.add('foo') + + t.is(ig.ignores('../foo/bar.js'), true) + + t.throws(() => ignore().ignores('../foo/bar.js')) + + t.end() +})