From bba59c4848cdd31461a9f45ebe79865d28cd3f5f Mon Sep 17 00:00:00 2001 From: Arkadii Berezkin Date: Wed, 2 Jun 2021 16:19:05 +0300 Subject: [PATCH] [New] `no-namespace`: Add `ignore` option Closes #1916. Closes #1903. --- CHANGELOG.md | 3 +++ docs/rules/no-namespace.md | 11 +++++++++++ src/rules/no-namespace.js | 31 ++++++++++++++++++++++++------- tests/src/rules/no-namespace.js | 1 + 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 493c70940..45aacceb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel ### Added - [`no-dynamic-require`]: add option `esmodule` ([#1223], thanks [@vikr01]) - [`named`]: add `commonjs` option ([#1222], thanks [@vikr01]) +- [`no-namespace`]: Add `ignore` option ([#2112], thanks [@aberezkin]) ### Fixed - [`no-duplicates`]: ensure autofix avoids excessive newlines ([#2028], thanks [@ertrzyiks]) @@ -822,6 +823,7 @@ for info on changes for earlier releases. [#2146]: https://github.com/benmosher/eslint-plugin-import/pull/2146 [#2138]: https://github.com/benmosher/eslint-plugin-import/pull/2138 [#2121]: https://github.com/benmosher/eslint-plugin-import/pull/2121 +[#2112]: https://github.com/benmosher/eslint-plugin-import/pull/2112 [#2099]: https://github.com/benmosher/eslint-plugin-import/pull/2099 [#2097]: https://github.com/benmosher/eslint-plugin-import/pull/2097 [#2090]: https://github.com/benmosher/eslint-plugin-import/pull/2090 @@ -1252,6 +1254,7 @@ for info on changes for earlier releases. [@1pete]: https://github.com/1pete [@3nuc]: https://github.com/3nuc [@aamulumi]: https://github.com/aamulumi +[@aberezkin]: https://github.com/aberezkin [@adamborowski]: https://github.com/adamborowski [@adjerbetian]: https://github.com/adjerbetian [@ai]: https://github.com/ai diff --git a/docs/rules/no-namespace.md b/docs/rules/no-namespace.md index e0b0f0b96..e98726051 100644 --- a/docs/rules/no-namespace.md +++ b/docs/rules/no-namespace.md @@ -5,6 +5,12 @@ Enforce a convention of not using namespace (a.k.a. "wildcard" `*`) imports. +(fixable) The `--fix` option on the [command line] automatically fixes problems reported by this rule, provided that the namespace object is only used for direct member access, e.g. `namespace.a`. The `--fix` functionality for this rule requires ESLint 5 or newer. +### Options + +This rule supports the following options: + +- `ignore`: array of glob strings for modules that should be ignored by the rule. + ## Rule Details Valid: @@ -15,6 +21,11 @@ import { a, b } from './bar' import defaultExport, { a, b } from './foobar' ``` +```js +/* eslint import/no-namespace: ["error", {ignore: ['*.ext']] */ +import * as bar from './ignored-module.ext'; +``` + Invalid: ```js diff --git a/src/rules/no-namespace.js b/src/rules/no-namespace.js index ca51823a0..472b93dd0 100644 --- a/src/rules/no-namespace.js +++ b/src/rules/no-namespace.js @@ -3,6 +3,7 @@ * @author Radek Benkel */ +import minimatch from 'minimatch'; import docsUrl from '../docsUrl'; //------------------------------------------------------------------------------ @@ -17,16 +18,32 @@ module.exports = { url: docsUrl('no-namespace'), }, fixable: 'code', - schema: [], + schema: [{ + type: 'object', + properties: { + ignore: { + type: 'array', + items: { + type: 'string', + }, + uniqueItems: true, + }, + }, + }], }, create: function (context) { + const firstOption = context.options[0] || {}; + const ignoreGlobs = firstOption.ignore; + return { - 'ImportNamespaceSpecifier': function (node) { + ImportNamespaceSpecifier(node) { + if (ignoreGlobs && ignoreGlobs.find(glob => minimatch(node.parent.source.value, glob, { matchBase: true }))) { + return; + } + const scopeVariables = context.getScope().variables; - const namespaceVariable = scopeVariables.find((variable) => - variable.defs[0].node === node - ); + const namespaceVariable = scopeVariables.find((variable) => variable.defs[0].node === node); const namespaceReferences = namespaceVariable.references; const namespaceIdentifiers = namespaceReferences.map(reference => reference.identifier); const canFix = namespaceIdentifiers.length > 0 && !usesNamespaceAsObject(namespaceIdentifiers); @@ -63,11 +80,11 @@ module.exports = { ); // Replace the ImportNamespaceSpecifier with a list of ImportSpecifiers - const namedImportSpecifiers = importNames.map((importName) => + const namedImportSpecifiers = importNames.map((importName) => ( importName === importLocalNames[importName] ? importName : `${importName} as ${importLocalNames[importName]}` - ); + )); fixes.push(fixer.replaceText(node, `{ ${namedImportSpecifiers.join(', ')} }`)); // Pass 2: Replace references to the namespace with references to the named imports diff --git a/tests/src/rules/no-namespace.js b/tests/src/rules/no-namespace.js index d7c4c9cf8..d75928c1d 100644 --- a/tests/src/rules/no-namespace.js +++ b/tests/src/rules/no-namespace.js @@ -78,6 +78,7 @@ ruleTester.run('no-namespace', require('rules/no-namespace'), { { code: 'import { a, b } from \'./foo\';', parserOptions: { ecmaVersion: 2015, sourceType: 'module' } }, { code: 'import bar from \'bar\';', parserOptions: { ecmaVersion: 2015, sourceType: 'module' } }, { code: 'import bar from \'./bar\';', parserOptions: { ecmaVersion: 2015, sourceType: 'module' } }, + { code: 'import * as bar from \'./ignored-module.ext\';', parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, options: [{ ignore: ['*.ext'] }] }, ], invalid: [