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

Issue:
docs example for `import/named` errors in imports from third-party libraries doesn't work
`import/named` describes a few examples with 3rd party libraries, specifically with React and Redux. 

However, I attempted to reproduce the example in a [fresh create-react-app project](https://github.com/MustafaHaddara/eslint-plugin-import-repro/commit/6c371fa87cf04704c5c8ec462669597e5a360dd2), and it didn't flag anything wrong with my imports from redux. 

Redux doesn't have a `jsnext:main` key in its `package.json`, and the [link to the `rollup` wiki in the further reading section of the docs](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/named.md#further-reading) is dead. `jsnext:main` is [deprecated](https://github.com/jsforum/jsforum/issues/5) in favour of [`pkg.module`](https://github.com/rollup/rollup/wiki/pkg.module), but Redux ships with a `pkg.module` definition and yet `import/named` doesn't catch bad imports from redux.

What's the correct way to configure this plugin to report non-existent named imports from third party libraries?


Discussion:
Looks like these examples all need updating.

I doubt we look at the nonstandard "module" field; that's not a real thing (neither is `jsnext:main`, of course, but support for that predates my involvement here).

Redux 4's "main" is https://unpkg.com/browse/redux@4.1.0/lib/redux.js, which is CJS, but has (conceptually) 5 meaningful named exports:
 - applyMiddleware
 - bindActionCreators
 - combineReducers
 - compose
 - createStore

It's likely that since we don't support "module", and this package, according to node, has nothing but a single CJS file, that there's no way we can check this currently.
Thanks for the quick response!

Are you aware of any other eslint plugins that can lint imports from third-party libraries? 
As far as I know of, this is the only package that lints imports and looks at other files at all.

Since we do support jsnext:main, and since major packages have dropped it in favor of "module", i'd be willing to review a PR that added support for it.
I've opened a draft PR [here](https://github.com/import-js/eslint-plugin-import/pull/2166) (still needs tests), let me know if you think i'm looking in the entirely wrong direction or what. I'm also not sure how to manually test it. 

Would love to get your thoughts, thanks. 



Patch:
diff --git a/docs/rules/named.md b/docs/rules/named.md
index 01ccb14ae7..0f697cc254 100644
--- a/docs/rules/named.md
+++ b/docs/rules/named.md
@@ -5,7 +5,7 @@ Verifies that all named imports are part of the set of named exports in the refe
 For `export`, verifies that all named exports exist in the referenced module.
 
 Note: for packages, the plugin will find exported names
-from [`jsnext:main`], if present in `package.json`.
+from [`jsnext:main`] (deprecated) or `module`, if present in `package.json`.
 Redux's npm module includes this key, and thereby is lintable, for example.
 
 A module path that is [ignored] or not [unambiguously an ES module] will not be reported when imported. Note that type imports and exports, as used by [Flow], are always ignored.
@@ -91,8 +91,10 @@ runtime, you will likely see false positives with this rule.
 ## Further Reading
 
 - [`import/ignore`] setting
-- [`jsnext:main`] (Rollup)
+- [`jsnext:main`] deprecation
+- [`pkg.module`] (Rollup)
 
 
-[`jsnext:main`]: https://github.com/rollup/rollup/wiki/jsnext:main
+[`jsnext:main`]: https://github.com/jsforum/jsforum/issues/5
+[`pkg.module`]: https://github.com/rollup/rollup/wiki/pkg.module
 [`import/ignore`]: ../../README.md#importignore
diff --git a/resolvers/node/CHANGELOG.md b/resolvers/node/CHANGELOG.md
index 8fa31bed7d..86554a4231 100644
--- a/resolvers/node/CHANGELOG.md
+++ b/resolvers/node/CHANGELOG.md
@@ -5,6 +5,9 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
 
 ## Unreleased
 
+### Added
+- use "module" in the same spot as "jsnext:main" ([#2166], thanks [@MustafaHaddara])
+
 ## v0.3.4 - 2020-06-16
 ### Added
 - add `.node` extension ([#1663])
@@ -48,6 +51,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
 ### Fixed
 - find files with `.json` extensions (#333, thanks for noticing @jfmengels)
 
+[#2166]: https://github.com/benmosher/eslint-plugin-import/pull/2166
 [#438]: https://github.com/benmosher/eslint-plugin-import/pull/438
 
 [#1663]: https://github.com/benmosher/eslint-plugin-import/issues/1663
@@ -61,3 +65,4 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
 [@SkeLLLa]: https://github.com/SkeLLLa
 [@ljharb]: https://github.com/ljharb
 [@opichals]: https://github.com/opichals
+[@MustafaHaddara]: https://github.com/MustafaHaddara
\ No newline at end of file
diff --git a/resolvers/node/index.js b/resolvers/node/index.js
index 85550ddf7a..84fc5076b6 100644
--- a/resolvers/node/index.js
+++ b/resolvers/node/index.js
@@ -42,8 +42,10 @@ function opts(file, config) {
 }
 
 function packageFilter(pkg) {
-  if (pkg['jsnext:main']) {
-    pkg['main'] = pkg['jsnext:main'];
+  if (pkg.module) {
+    pkg.main = pkg.module;
+  } else if (pkg['jsnext:main']) {
+    pkg.main = pkg['jsnext:main'];
   }
   return pkg;
 }


Test patch:
diff --git a/resolvers/node/test/package-mains/jsnext/package.json b/resolvers/node/test/package-mains/jsnext/package.json
new file mode 100644
index 0000000000..d336fedaf4
--- /dev/null
+++ b/resolvers/node/test/package-mains/jsnext/package.json
@@ -0,0 +1,4 @@
+{
+  "main": "lib/index.js",
+  "jsnext:main": "src/index.js"
+}
diff --git a/resolvers/node/test/package-mains/jsnext/src/index.js b/resolvers/node/test/package-mains/jsnext/src/index.js
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/resolvers/node/test/package-mains/module-and-jsnext/package.json b/resolvers/node/test/package-mains/module-and-jsnext/package.json
new file mode 100644
index 0000000000..4b1355aaed
--- /dev/null
+++ b/resolvers/node/test/package-mains/module-and-jsnext/package.json
@@ -0,0 +1,5 @@
+{
+  "main": "lib/index.js",
+  "module": "src/index.js",
+  "jsnext:main": "lib/index.js"
+}
diff --git a/resolvers/node/test/package-mains/module-and-jsnext/src/index.js b/resolvers/node/test/package-mains/module-and-jsnext/src/index.js
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/resolvers/node/test/package-mains/module/package.json b/resolvers/node/test/package-mains/module/package.json
new file mode 100644
index 0000000000..3a80819f88
--- /dev/null
+++ b/resolvers/node/test/package-mains/module/package.json
@@ -0,0 +1,4 @@
+{
+  "main": "lib/index.js",
+  "module": "src/index.js"
+}
diff --git a/resolvers/node/test/package-mains/module/src/index.js b/resolvers/node/test/package-mains/module/src/index.js
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/resolvers/node/test/package-mains/package.json b/resolvers/node/test/package-mains/package.json
new file mode 100644
index 0000000000..0a5fb6e237
--- /dev/null
+++ b/resolvers/node/test/package-mains/package.json
@@ -0,0 +1,1 @@
+{ "dummy": true }
\ No newline at end of file
diff --git a/resolvers/node/test/packageMains.js b/resolvers/node/test/packageMains.js
new file mode 100644
index 0000000000..0a7d9463c7
--- /dev/null
+++ b/resolvers/node/test/packageMains.js
@@ -0,0 +1,27 @@
+'use strict';
+
+const chai = require('chai');
+const expect = chai.expect;
+const path = require('path');
+
+const webpack = require('../');
+
+const file = path.join(__dirname, 'package-mains', 'dummy.js');
+
+
+describe('packageMains', function () {
+  it('captures module', function () {
+    expect(webpack.resolve('./module', file)).property('path')
+      .to.equal(path.join(__dirname, 'package-mains', 'module', 'src', 'index.js'));
+  });
+
+  it('captures jsnext', function () {
+    expect(webpack.resolve('./jsnext', file)).property('path')
+      .to.equal(path.join(__dirname, 'package-mains', 'jsnext', 'src', 'index.js'));
+  });
+
+  it('captures module instead of jsnext', function () {
+    expect(webpack.resolve('./module-and-jsnext', file)).property('path')
+      .to.equal(path.join(__dirname, 'package-mains', 'module-and-jsnext', 'src', 'index.js'));
+  });
+});
diff --git a/resolvers/webpack/test/package-mains/module-and-jsnext/package.json b/resolvers/webpack/test/package-mains/module-and-jsnext/package.json
new file mode 100644
index 0000000000..4b1355aaed
--- /dev/null
+++ b/resolvers/webpack/test/package-mains/module-and-jsnext/package.json
@@ -0,0 +1,5 @@
+{
+  "main": "lib/index.js",
+  "module": "src/index.js",
+  "jsnext:main": "lib/index.js"
+}
diff --git a/resolvers/webpack/test/package-mains/module-and-jsnext/src/index.js b/resolvers/webpack/test/package-mains/module-and-jsnext/src/index.js
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/resolvers/webpack/test/packageMains.js b/resolvers/webpack/test/packageMains.js
index ed9c79a398..96becbc8ce 100644
--- a/resolvers/webpack/test/packageMains.js
+++ b/resolvers/webpack/test/packageMains.js
@@ -21,6 +21,11 @@ describe('packageMains', function () {
       .to.equal(path.join(__dirname, 'package-mains', 'jsnext', 'src', 'index.js'));
   });
 
+  it('captures module instead of jsnext', function () {
+    expect(webpack.resolve('./module-and-jsnext', file)).property('path')
+      .to.equal(path.join(__dirname, 'package-mains', 'module-and-jsnext', 'src', 'index.js'));
+  });
+
   it('captures webpack', function () {
     expect(webpack.resolve('./webpack', file)).property('path')
       .to.equal(path.join(__dirname, 'package-mains', 'webpack', 'webpack.js'));