From 19ad061290e1e97f760cfdce90a651cea9042c32 Mon Sep 17 00:00:00 2001 From: gfyoung Date: Sat, 15 Jan 2022 14:17:31 -0800 Subject: [PATCH] feat: no-restricted-imports support casing (#15439) * fix: no-restricted-imports support casing Path matching in `.gitignore` can be case-sensitive, and ignore@5.2.0 supports this as well as maintains support for relative paths, whose support was dropped after 4.0.6 but restored in 5.2.0 (this was a blocker for past upgrades). By default, this rule remains case-insensitive to maintain backwards compatibility with earlier versions. Only by explicitly specifying it in a custom pattern object can it be triggered. * Set allowRelativePaths directly in files Per member feedback, the allowing of relative paths was not entirely intentional for rules using the `ignore` library. This commit also reverts the utility for creating `ignore` instances. * Update word in docs for allowRelativePaths Per reviewer feedback --- docs/rules/no-restricted-imports.md | 29 ++++++++++++++++++++++++ lib/rules/no-restricted-imports.js | 19 ++++++++++++---- lib/rules/no-restricted-modules.js | 3 ++- package.json | 2 +- tests/lib/rules/no-restricted-imports.js | 20 ++++++++++++++++ 5 files changed, 67 insertions(+), 6 deletions(-) diff --git a/docs/rules/no-restricted-imports.md b/docs/rules/no-restricted-imports.md index 414485fdf62..3a88fabcacd 100644 --- a/docs/rules/no-restricted-imports.md +++ b/docs/rules/no-restricted-imports.md @@ -91,6 +91,17 @@ or like this if you want to apply a custom message to pattern matches: The custom message will be appended to the default error message. +Pattern matches can also be configured to be case-sensitive: + +```json +"no-restricted-imports": ["error", { + "patterns": [{ + "group": ["import1/private/prefix[A-Z]*"], + "caseSensitive": true + }] +}] +``` + To restrict the use of all Node.js core imports (via ): ```json @@ -176,6 +187,15 @@ import * as Foo from "foo"; import pick from 'lodash/pick'; ``` +```js +/*eslint no-restricted-imports: ["error", { patterns: [{ + group: ["foo[A-Z]*"], + caseSensitive: true +}]}]*/ + +import pick from 'fooBar'; +``` + Examples of **correct** code for this rule: ```js @@ -218,6 +238,15 @@ import { AllowedObject as DisallowedObject } from "foo"; import lodash from 'lodash'; ``` +```js +/*eslint no-restricted-imports: ["error", { patterns: [{ + group: ["foo[A-Z]*"], + caseSensitive: true +}]}]*/ + +import pick from 'food'; +``` + ## When Not To Use It Don't use this rule or don't include a module in the list for this rule if you want to be able to import a module in your project without an ESLint error or warning. diff --git a/lib/rules/no-restricted-imports.js b/lib/rules/no-restricted-imports.js index 455cc336c5f..3bb45d715ff 100644 --- a/lib/rules/no-restricted-imports.js +++ b/lib/rules/no-restricted-imports.js @@ -69,6 +69,9 @@ const arrayOfStringsOrObjectPatterns = { message: { type: "string", minLength: 1 + }, + caseSensitive: { + type: "boolean" } }, additionalProperties: false, @@ -148,10 +151,18 @@ module.exports = { }, {}); // Handle patterns too, either as strings or groups - const restrictedPatterns = (isPathAndPatternsObject ? options[0].patterns : []) || []; - const restrictedPatternGroups = restrictedPatterns.length > 0 && typeof restrictedPatterns[0] === "string" - ? [{ matcher: ignore().add(restrictedPatterns) }] - : restrictedPatterns.map(({ group, message }) => ({ matcher: ignore().add(group), customMessage: message })); + let restrictedPatterns = (isPathAndPatternsObject ? options[0].patterns : []) || []; + + // standardize to array of objects if we have an array of strings + if (restrictedPatterns.length > 0 && typeof restrictedPatterns[0] === "string") { + restrictedPatterns = [{ group: restrictedPatterns }]; + } + + // relative paths are supported for this rule + const restrictedPatternGroups = restrictedPatterns.map(({ group, message, caseSensitive }) => ({ + matcher: ignore({ allowRelativePaths: true, ignorecase: !caseSensitive }).add(group), + customMessage: message + })); // if no imports are restricted we don't need to check if (Object.keys(restrictedPaths).length === 0 && restrictedPatternGroups.length === 0) { diff --git a/lib/rules/no-restricted-modules.js b/lib/rules/no-restricted-modules.js index 26e75ef81a2..d92aa7a86bc 100644 --- a/lib/rules/no-restricted-modules.js +++ b/lib/rules/no-restricted-modules.js @@ -103,7 +103,8 @@ module.exports = { return {}; } - const ig = ignore().add(restrictedPatterns); + // relative paths are supported for this rule + const ig = ignore({ allowRelativePaths: true }).add(restrictedPatterns); /** diff --git a/package.json b/package.json index 3cb6cea4249..d3b87ab64b9 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ "functional-red-black-tree": "^1.0.1", "glob-parent": "^6.0.1", "globals": "^13.6.0", - "ignore": "^4.0.6", + "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", diff --git a/tests/lib/rules/no-restricted-imports.js b/tests/lib/rules/no-restricted-imports.js index 3cf7eb371a7..643c87ede17 100644 --- a/tests/lib/rules/no-restricted-imports.js +++ b/tests/lib/rules/no-restricted-imports.js @@ -54,6 +54,16 @@ ruleTester.run("no-restricted-imports", rule, { code: "import withPatterns from \"foo/bar\";", options: [{ patterns: [{ group: ["foo/*", "!foo/bar"], message: "foo is forbidden, use bar instead" }] }] }, + { + code: "import withPatternsCaseSensitive from 'foo';", + options: [{ + patterns: [{ + group: ["FOO"], + message: "foo is forbidden, use bar instead", + caseSensitive: true + }] + }] + }, { code: "import AllowedObject from \"foo\";", options: [{ @@ -344,6 +354,16 @@ ruleTester.run("no-restricted-imports", rule, { column: 1, endColumn: 36 }] + }, { + code: "import withPatternsCaseInsensitive from 'foo';", + options: [{ patterns: [{ group: ["FOO"] }] }], + errors: [{ + message: "'foo' import is restricted from being used by a pattern.", + type: "ImportDeclaration", + line: 1, + column: 1, + endColumn: 47 + }] }, { code: "import withGitignores from \"foo/bar\";", options: [{ patterns: ["foo/*", "!foo/baz"] }],