Repository: import-js/eslint-plugin-import (js)

Issue:
[no-namespace] allow namespace imports for specific modules
I want to disallow using namespaces as a rule, but some third-party libraries don't use default exports. The specific one that we use quite a bit in our application is [yup](https://github.com/jquense/yup). Even if we use TypeScript's `allowSyntheticDefaultImports` rule, we still have to import the library using `import * as yup from 'yup';`.

I'd like to be able to do something like the following:
```
rules: {
    // ...
    'import/no-namespace': ['warn', {allow: ['yup', 'some-lib', '@scoped/lib']}],
    // ...
},
```

With the above config, the following would be considered correct:
```
import * as yup from 'yup';
import * as validation from 'yup';
import * as lib from 'some-lib';
```

And the following would be considered incorrect:
```
import * as nope from 'not-allowed';

// even though this contains the string "some-lib", it should not be valid; I think the allow list should be exact matches only
import * as stillNope from '@scoped/some-lib';
```

I came across pull request #1679 from earlier this year, but it appears it was closed without being merged.

Pull request description:
[New] `no-namespace`: Add `ignore` option
Closes #1916
Closes #1903

Hi, we want to use the rule `no-namespace` in our project but we have a `i18n` codegen tool that forces us to use wildcard imports for certain files that follow some pattern (`\S+\.i18n`, to be precise). Also I've seen that there's people with similar issue.

I thought that we can implement something similar to `argsIgnorePattern/varsIgnorePattern` in [core eslint rules](https://github.com/eslint/eslint/blob/master/lib/rules/no-unused-vars.js#L107). 

I made a test for that case and updated the docs as well. Please let me know if there's something else I should do to get this merged.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 493c7094..45aacceb 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 e0b0f0b9..e9872605 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 ca51823a..472b93dd 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


Test patch:
diff --git a/tests/src/rules/no-namespace.js b/tests/src/rules/no-namespace.js
index d7c4c9cf..d75928c1 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: [