Repository: import-js/eslint-plugin-import
Pull request #2198 (2021-08-19 20:21:37)

Release 2.24.1
node resolver is already published.


Patch:
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
index 8fd76799..0ef28872 100644
--- a/.github/FUNDING.yml
+++ b/.github/FUNDING.yml
@@ -2,7 +2,7 @@
 
 github: [ljharb]
 patreon: # Replace with a single Patreon username
-open_collective: # Replace with a single Open Collective username
+open_collective: eslint-plugin-import # Replace with a single Open Collective username
 ko_fi: # Replace with a single Ko-fi username
 tidelift: npm/eslint-plugin-import
 community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 998055e6..4991b7a9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,16 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
 
 ## [Unreleased]
 
+## [2.24.1] - 2021-08-19
+
+### Fixed
+- `ExportMap`: Add default export when esModuleInterop is true and anything is exported ([#2184], thanks [@Maxim-Mazurok])
+- [`named`], [`namespace`]: properly set reexports on `export * as … from` ([#1998], [#2161], thanks [@ljharb])
+- [`no-duplicates`]: correctly handle case of mixed default/named type imports ([#2149], thanks [@GoodForOneFare], [@nwalters512])
+
+### Changed
+- [Docs] `max-dependencies`: 📖 Document `ignoreTypeImports` option ([#2196], thanks [@himynameisdave])
+
 ## [2.24.0] - 2021-08-08
 
 ### Added
@@ -17,11 +27,12 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
 ### Fixed
 - [`no-duplicates`]: ensure autofix avoids excessive newlines ([#2028], thanks [@ertrzyiks])
 - [`extensions`]: avoid crashing on partially typed import/export statements ([#2118], thanks [@ljharb])
-- [`no-extraneous-dependencies`]: add ESM intermediate package.json support] ([#2121], thanks [@paztis])
+- [`no-extraneous-dependencies`]: add ESM intermediate package.json support ([#2121], thanks [@paztis])
 - Use `context.getPhysicalFilename()` when available (ESLint 7.28+) ([#2160], thanks [@pmcelhaney])
 - [`extensions`]/`importType`: fix isScoped treating @/abc as scoped module ([#2146], thanks [@rperello])
 
 ### Changed
+- [Docs] [`extensions`]: improved cases for using `@/...` ([#2140], thanks [@wenfangdu])
 - [Docs] [`extensions`]: removed incorrect cases ([#2138], thanks [@wenfangdu])
 - [Tests] [`order`]: add tests for `pathGroupsExcludedImportTypes: ['type']` ([#2158], thanks [@atav32])
 - [Docs] [`order`]:  improve the documentation for the `pathGroupsExcludedImportTypes` option ([#2156], thanks [@liby])
@@ -94,6 +105,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
 - [Docs] Add import/recommended ruleset to README ([#2034], thanks [@edemaine])
 
 ## [2.22.1] - 2020-09-27
+
 ### Fixed
 - [`default`]/TypeScript: avoid crash on `export =` with a MemberExpression ([#1841], thanks [@ljharb])
 - [`extensions`]/importType: Fix @/abc being treated as scoped module ([#1854], thanks [@3nuc])
@@ -104,6 +116,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
 - [`export`]: add tests for a name collision with `export * from` ([#1704], thanks @tomprats)
 
 ## [2.22.0] - 2020-06-26
+
 ### Added
 - [`no-unused-modules`]: consider exported TypeScript interfaces, types and enums ([#1819], thanks [@nicolashenry])
 - [`no-cycle`]: allow `maxDepth` option to be `"∞"` (thanks [@ljharb])
@@ -124,16 +137,19 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
 - [docs] [`imports-first`]: deprecation info and link to `first` docs ([#1835], thanks [@beatrizrezener])
 
 ## [2.21.2] - 2020-06-09
+
 ### Fixed
 - [`order`]: avoid a crash on TypeScript’s `export import` syntax ([#1808], thanks [@ljharb])
 - [`newline-after-import`]: consider TypeScript `import =` syntax' ([#1811], thanks [@ljharb])
 - [`no-internal-modules`]: avoid a crash on a named export declaration ([#1814], thanks [@ljharb])
 
 ## [2.21.1] - 2020-06-07
+
 ### Fixed
 - TypeScript: [`import/named`]: avoid requiring `typescript` when not using TS ([#1805], thanks [@ljharb])
 
 ## [2.21.0] - 2020-06-07
+
 ### Added
 - [`import/default`]: support default export in TSExportAssignment ([#1528], thanks [@joaovieira])
 - [`no-cycle`]: add `ignoreExternal` option ([#1681], thanks [@sveyret])
@@ -164,6 +180,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
 - [eslint] bump minimum v7 version to v7.2.0
 
 ## [2.20.2] - 2020-03-28
+
 ### Fixed
 - [`order`]: fix `isExternalModule` detect on windows ([#1651], thanks [@fisker])
 - [`order`]: recognize ".." as a "parent" path ([#1658], thanks [@golopot])
@@ -173,6 +190,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
 - [Docs] `no-webpack-loader-syntax`: Updates webpack URLs ([#1751], thanks [@MikeyBeLike])
 
 ## [2.20.1] - 2020-02-01
+
 ### Fixed
 - [`export`]: Handle function overloading in `*.d.ts` ([#1619], thanks [@IvanGoncharov])
 - [`no-absolute-path`]: fix a crash with invalid import syntax ([#1616], thanks [@ljharb])
@@ -190,6 +208,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
 - [Tests] `order`: Add TS import type tests ([#1736], thanks [@kmui2])
 
 ## [2.20.0] - 2020-01-10
+
 ### Added
 - [`order`]: added `caseInsensitive` as an additional option to `alphabetize` ([#1586], thanks [@dbrewer5])
 - [`no-restricted-paths`]: New `except` option per `zone`, allowing exceptions to be defined for a restricted zone ([#1238], thanks [@rsolomon])
@@ -206,10 +225,12 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
 - [`extensions`]: improve `ignorePackages` docs ([#1248], thanks [@ivo-stefchev])
 
 ## [2.19.1] - 2019-12-08
+
 ### Fixed
 - [`no-extraneous-dependencies`]: ensure `node.source` exists
 
 ## [2.19.0] - 2019-12-08
+
 ### Added
 - [`internal-regex` setting]: regex pattern for marking packages "internal"  ([#1491], thanks [@Librazy])
 - [`group-exports`]: make aggregate module exports valid ([#1472], thanks [@atikenny])
@@ -241,10 +262,12 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
 - [`no-unused-modules`]/`eslint-module-utils`: Avoid superfluous calls and code ([#1551], thanks [@brettz9])
 
 ## [2.18.2] - 2019-07-19
+
 ### Fixed
 - Skip warning on type interfaces ([#1425], thanks [@lencioni])
 
 ## [2.18.1] - 2019-07-18
+
 ### Fixed
 - Improve parse perf when using `@typescript-eslint/parser` ([#1409], thanks [@bradzacher])
 - [`prefer-default-export`]: don't warn on TypeAlias & TSTypeAliasDeclaration ([#1377], thanks [@sharmilajesupaul])
@@ -255,6 +278,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
 - [`no-extraneous-dependencies`], `importType`: remove lodash ([#1419], thanks [@ljharb])
 
 ## [2.18.0] - 2019-06-24
+
 ### Added
 - Support eslint v6 ([#1393], thanks [@sheepsteak])
 - [`order`]: Adds support for correctly sorting unknown types into a single group ([#1375], thanks [@swernerx])
@@ -269,6 +293,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
 - [`no-named-as-default-member`]: update broken link ([#1389], thanks [@fooloomanzoo])
 
 ## [2.17.3] - 2019-05-23
+
 ### Fixed
 - [`no-common-js`]: Also throw an error when assigning ([#1354], thanks [@charlessuh])
 - [`no-unused-modules`]: don't crash when lint file outside src-folder ([#1347], thanks [@rfermann])
@@ -284,15 +309,18 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
 - Document `env` option for `eslint-import-resolver-webpack` ([#1363], thanks [@kgregory])
 
 ## [2.17.2] - 2019-04-16
+
 ### Fixed
 - [`no-unused-modules`]: avoid crash when using `ignoreExports`-option ([#1331], [#1323], thanks [@rfermann])
 - [`no-unused-modules`]: make sure that rule with no options will not fail ([#1330], [#1334], thanks [@kiwka])
 
 ## [2.17.1] - 2019-04-13
+
 ### Fixed
 - require v2.4 of `eslint-module-utils` ([#1322])
 
 ## [2.17.0] - 2019-04-13
+
 ### Added
 - [`no-useless-path-segments`]: Add `noUselessIndex` option ([#1290], thanks [@timkraut])
 - [`no-duplicates`]: Add autofix ([#1312], thanks [@lydell])
@@ -318,6 +346,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
 - [`no-commonjs`]: add tests that show corner cases ([#1308], thanks [@TakeScoop])
 
 ## [2.16.0] - 2019-01-29
+
 ### Added
 - `typescript` config ([#1257], thanks [@kirill-konshin])
 
@@ -325,6 +354,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
 - Memory leak of `SourceCode` objects for all parsed dependencies, resolved. (issue [#1266], thanks [@asapach] and [@sergei-startsev] for digging in)
 
 ## [2.15.0] - 2019-01-22
+
 ### Added
 - new rule: [`no-named-export`] ([#1157], thanks [@fsmaia])
 
@@ -334,6 +364,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
 - [`named`]: fix destructuring assignment ([#1232], thanks [@ljqx])
 
 ## [2.14.0] - 2018-08-13
+
 ### Added
 - [`no-useless-path-segments`]: add commonJS (CJS) support ([#1128], thanks [@1pete])
 - [`namespace`]: add JSX check ([#1151], thanks [@jf248])
@@ -349,6 +380,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
 - add explicit support for RestElement alongside ExperimentalRestProperty (thanks [@ljharb])
 
 ## [2.13.0] - 2018-06-24
+
 ### Added
 - Add ESLint 5 support ([#1122], thanks [@ai] and [@ljharb])
 - Add [`no-relative-parent-imports`] rule: disallow relative imports from parent directories ([#1093], thanks [@chrislloyd])
@@ -357,12 +389,14 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
 - `namespace` rule: ensure it works in eslint 5/ecmaVersion 2018 (thanks [@ljharb])
 
 ## [2.12.0] - 2018-05-17
+
 ### Added
 - Ignore type imports for [`named`] rule ([#931], thanks [@mattijsbliek])
 - Add documentation for [`no-useless-path-segments`] rule ([#1068], thanks [@manovotny])
 - `packageDir` option for [`no-extraneous-dependencies`] can be array-valued ([#1085], thanks [@hulkish])
 
 ## [2.11.0] - 2018-04-09
+
 ### Added
 - Fixer for [`first`] ([#1046], thanks [@fengkfengk])
 - `allow-require` option for [`no-commonjs`] rule ([#880], thanks [@futpib])
@@ -371,11 +405,13 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
 - memory/CPU regression where ASTs were held in memory ([#1058], thanks [@klimashkin]/[@lukeapage])
 
 ## [2.10.0] - 2018-03-29
+
 ### Added
 - Autofixer for [`order`] rule ([#908], thanks [@tihonove])
 - Add [`no-cycle`] rule: reports import cycles.
 
 ## [2.9.0] - 2018-02-21
+
 ### Added
 - Add [`group-exports`] rule: style-guide rule to report use of multiple named exports ([#721], thanks [@robertrossmann])
 - Add [`no-self-import`] rule: forbids a module from importing itself. ([#727], [#449], [#447], thanks [@giodamelio]).
@@ -396,14 +432,17 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
 - TypeError for missing AST fields from TypeScript ([#842] / [#944], thanks [@alexgorbatchev])
 
 ## [2.7.0] - 2017-07-06
+
 ### Changed
 - [`no-absolute-path`] picks up speed boost, optional AMD support ([#843], thanks [@jseminck])
 
 ## [2.6.1] - 2017-06-29
+
 ### Fixed
 - update bundled node resolver dependency to latest version
 
 ## [2.6.0] - 2017-06-23
+
 ### Changed
 - update tests / peerDeps for ESLint 4.0 compatibility ([#871], thanks [@mastilver])
 - [`memo-parser`] updated to require `filePath` on parser options as it melts
@@ -426,6 +465,7 @@ Yanked due to critical issue in eslint-module-utils with cache key resulting fro
 - Add `allow` option to [`no-unassigned-import`] to allow for files that match the globs ([#671], [#737], thanks [@kevin940726]).
 
 ## [2.3.0] - 2017-05-18
+
 ### Added
 - [`no-anonymous-default-export`] rule: report anonymous default exports ([#712], thanks [@duncanbeevers]).
 - Add new value to [`order`]'s `newlines-between` option to allow newlines inside import groups ([#627], [#628], thanks [@giodamelio])
@@ -440,8 +480,8 @@ Yanked due to critical issue in eslint-module-utils with cache key resulting fro
 - "default is a reserved keyword" in no-maned-default tests by locking down babylon to 6.15.0 (#756, thanks @gmathieu)
 - support scoped modules containing non word characters
 
-
 ## [2.2.0] - 2016-11-07
+
 ### Fixed
 - Corrected a few gaffs in the auto-ignore logic to fix major performance issues
   with projects that did not explicitly ignore `node_modules`. ([#654])
@@ -450,6 +490,7 @@ Yanked due to critical issue in eslint-module-utils with cache key resulting fro
 - [`prefer-default-export`]: fixed crash on export extensions ([#653])
 
 ## [2.1.0] - 2016-11-02
+
 ### Added
 - Add [`no-named-default`] rule: style-guide rule to report use of unnecessarily named default imports ([#596], thanks [@ntdb])
 - [`no-extraneous-dependencies`]: check globs against CWD + absolute path ([#602] + [#630], thanks [@ljharb])
@@ -462,10 +503,12 @@ Yanked due to critical issue in eslint-module-utils with cache key resulting fro
 - Fixed documentation for the default values for the [`order`] rule ([#601])
 
 ## [2.0.1] - 2016-10-06
+
 ### Fixed
 - Fixed code that relied on removed dependencies. ([#604])
 
 ## [2.0.0]! - 2016-09-30
+
 ### Added
 - [`unambiguous`] rule: report modules that are not unambiguously ES modules.
 - `recommended` shared config. Roughly `errors` and `warnings` mixed together,
@@ -491,6 +534,7 @@ Yanked due to critical issue in eslint-module-utils with cache key resulting fro
 - [`no-internal-modules`]: support `@`-scoped packages ([#577]+[#578], thanks [@spalger])
 
 ## [1.16.0] - 2016-09-22
+
 ### Added
 - Added [`no-dynamic-require`] rule: forbid `require()` calls with expressions. ([#567], [#568])
 - Added [`no-internal-modules`] rule: restrict deep package imports to specific folders. ([#485], thanks [@spalger]!)
@@ -501,6 +545,7 @@ Yanked due to critical issue in eslint-module-utils with cache key resulting fro
 - [`default`]: allow re-export of values from ignored files as default ([#545], thanks [@skyrpex])
 
 ## [1.15.0] - 2016-09-12
+
 ### Added
 - Added an `allow` option to [`no-nodejs-modules`] to allow exceptions ([#452], [#509]).
 - Added [`no-absolute-path`] rule ([#530], [#538])
@@ -511,6 +556,7 @@ Yanked due to critical issue in eslint-module-utils with cache key resulting fro
 - [`no-named-as-default-member`] Allow default import to have a property named "default" ([#507], [#508], thanks [@jquense] for both!)
 
 ## [1.14.0] - 2016-08-22
+
 ### Added
 - [`import/parsers` setting]: parse some dependencies (i.e. TypeScript!) with a different parser than the ESLint-configured parser. ([#503])
 
@@ -518,6 +564,7 @@ Yanked due to critical issue in eslint-module-utils with cache key resulting fro
 - [`namespace`] exception for get property from `namespace` import, which are re-export from commonjs module ([#499] fixes [#416], thanks [@wKich])
 
 ## [1.13.0] - 2016-08-11
+
 ### Added
 - `allowComputed` option for [`namespace`] rule. If set to `true`, won't report
   computed member references to namespaces. (see [#456])
@@ -530,15 +577,18 @@ Yanked due to critical issue in eslint-module-utils with cache key resulting fro
   in an imported file. (fixes [#478], thanks [@rhys-vdw])
 
 ## [1.12.0] - 2016-07-26
+
 ### Added
 - [`import/external-module-folders` setting]: a possibility to configure folders for "external" modules ([#444], thanks [@zloirock])
 
 ## [1.11.1] - 2016-07-20
+
 ### Fixed
 - [`newline-after-import`] exception for `switch` branches with `require`s iff parsed as `sourceType:'module'`.
   (still [#441], thanks again [@ljharb])
 
 ## [1.11.0] - 2016-07-17
+
 ### Added
 - Added an `peerDependencies` option to [`no-extraneous-dependencies`] to allow/forbid peer dependencies ([#423], [#428], thanks [@jfmengels]!).
 
@@ -547,20 +597,24 @@ Yanked due to critical issue in eslint-module-utils with cache key resulting fro
   function expression (e.g. `() => require('a') || require('b')`). ([#441], thanks [@ljharb])
 
 ## [1.10.3] - 2016-07-08
+
 ### Fixed
 - removing `Symbol` dependencies (i.e. `for-of` loops) due to Node 0.10 polyfill
   issue (see [#415]). Should not make any discernible semantic difference.
 
 ## [1.10.2] - 2016-07-04
+
 ### Fixed
 - Something horrible happened during `npm prepublish` of 1.10.1.
   Several `rm -rf node_modules && npm i` and `gulp clean && npm prepublish`s later, it is rebuilt and republished as 1.10.2. Thanks [@rhettlivingston] for noticing and reporting!
 
 ## [1.10.1] - 2016-07-02 [YANKED]
+
 ### Added
 - Officially support ESLint 3.x. (peerDependencies updated to `2.x - 3.x`)
 
 ## [1.10.0] - 2016-06-30
+
 ### Added
 - Added new rule [`no-restricted-paths`]. ([#155]/[#371], thanks [@lo1tuma])
 - [`import/core-modules` setting]: allow configuration of additional module names,
@@ -571,14 +625,17 @@ Yanked due to critical issue in eslint-module-utils with cache key resulting fro
 - Fixed crash with `newline-after-import` related to the use of switch cases. (fixes [#386], thanks [@ljharb] for reporting) ([#395])
 
 ## [1.9.2] - 2016-06-21
+
 ### Fixed
 - Issues with ignored/CJS files in [`export`] and [`no-deprecated`] rules. ([#348], [#370])
 
 ## [1.9.1] - 2016-06-16
+
 ### Fixed
 - Reordered precedence for loading resolvers. ([#373])
 
 ## [1.9.0] - 2016-06-10
+
 ### Added
 - Added support TomDoc comments to [`no-deprecated`]. ([#321], thanks [@josh])
 - Added support for loading custom resolvers ([#314], thanks [@le0nik])
@@ -587,6 +644,7 @@ Yanked due to critical issue in eslint-module-utils with cache key resulting fro
 - [`prefer-default-export`] handles `export function` and `export const` in same file ([#359], thanks [@scottnonnenberg])
 
 ## [1.8.1] - 2016-05-23
+
 ### Fixed
 - `export * from 'foo'` now properly ignores a `default` export from `foo`, if any. ([#328]/[#332], thanks [@jkimbo])
   This impacts all static analysis of imported names. ([`default`], [`named`], [`namespace`], [`export`])
@@ -596,6 +654,7 @@ Yanked due to critical issue in eslint-module-utils with cache key resulting fro
 - [`prefer-default-export`] properly handles deep destructuring, `export * from ...`, and files with no exports. ([#342]+[#343], thanks [@scottnonnenberg])
 
 ## [1.8.0] - 2016-05-11
+
 ### Added
 - [`prefer-default-export`], new rule. ([#308], thanks [@gavriguy])
 
@@ -604,6 +663,7 @@ Yanked due to critical issue in eslint-module-utils with cache key resulting fro
 - Make [`no-extraneous-dependencies`] handle scoped packages ([#316], thanks [@jfmengels])
 
 ## [1.7.0] - 2016-05-06
+
 ### Added
 - [`newline-after-import`], new rule. ([#245], thanks [@singles])
 - Added an `optionalDependencies` option to [`no-extraneous-dependencies`] to allow/forbid optional dependencies ([#266], thanks [@jfmengels]).
@@ -618,6 +678,7 @@ Yanked due to critical issue in eslint-module-utils with cache key resulting fro
   module is not resolved. Also, never report for builtins (i.e. `path`). ([#296])
 
 ## [1.6.1] - 2016-04-28
+
 ### Fixed
 - [`no-named-as-default-member`]: don't crash on rest props. ([#281], thanks [@SimenB])
 - support for Node 6: don't pass `null` to `path` functions.
@@ -625,6 +686,7 @@ Yanked due to critical issue in eslint-module-utils with cache key resulting fro
   config ([#288]).
 
 ## [1.6.0] - 2016-04-25
+
 ### Added
 - add [`no-named-as-default-member`] to `warnings` canned config
 - add [`no-extraneous-dependencies`] rule ([#241], thanks [@jfmengels])
@@ -643,6 +705,7 @@ Yanked due to critical issue in eslint-module-utils with cache key resulting fro
 - [`no-named-as-default-member`] had a crash on destructuring in loops (thanks for heads up from [@lemonmade])
 
 ## [1.5.0] - 2016-04-18
+
 ### Added
 - report resolver errors at the top of the linted file
 - add [`no-namespace`] rule ([#239], thanks [@singles])
@@ -655,6 +718,7 @@ Yanked due to critical issue in eslint-module-utils with cache key resulting fro
 - support for Node 0.10, via `es6-*` ponyfills. Using native Map/Set/Symbol.
 
 ## [1.4.0] - 2016-03-25
+
 ### Added
 - Resolver plugin interface v2: more explicit response format that more clearly covers the found-but-core-module case, where there is no path.
   Still backwards-compatible with the original version of the resolver spec.
@@ -665,6 +729,7 @@ Yanked due to critical issue in eslint-module-utils with cache key resulting fro
 - using `es6-*` ponyfills instead of `babel-runtime`
 
 ## [1.3.0] - 2016-03-20
+
 Major perf improvements. Between parsing only once and ignoring gigantic, non-module `node_modules`,
 there is very little added time.
 
@@ -680,6 +745,7 @@ memoizing parser, and takes only 27s with naked `babel-eslint` (thus, reparsing
   something that looks like an `export` is detected in the module content.
 
 ## [1.2.0] - 2016-03-19
+
 Thanks [@lencioni] for identifying a huge amount of rework in resolve and kicking
 off a bunch of memoization.
 
@@ -690,6 +756,7 @@ I'm seeing 62% improvement over my normal test codebase when executing only
 - added caching to core/resolve via [#214], configured via [`import/cache` setting]
 
 ## [1.1.0] - 2016-03-15
+
 ### Added
 - Added an [`ignore`](./docs/rules/no-unresolved.md#ignore) option to [`no-unresolved`] for those pesky files that no resolver can find. (still prefer enhancing the Webpack and Node resolvers to using it, though). See [#89] for details.
 
@@ -741,6 +808,7 @@ I'm seeing 62% improvement over my normal test codebase when executing only
 - `babylon` as default import parser (see Breaking)
 
 ## [0.13.0] - 2016-02-08
+
 ### Added
 - [`no-commonjs`] rule
 - [`no-amd`] rule
@@ -749,17 +817,21 @@ I'm seeing 62% improvement over my normal test codebase when executing only
 - Removed vestigial `no-require` rule. [`no-commonjs`] is more complete.
 
 ## [0.12.2] - 2016-02-06 [YANKED]
+
 Unpublished from npm and re-released as 0.13.0. See [#170].
 
 ## [0.12.1] - 2015-12-17
+
 ### Changed
 - Broke docs for rules out into individual files.
 
 ## [0.12.0] - 2015-12-14
+
 ### Changed
 - Ignore [`import/ignore` setting] if exports are actually found in the parsed module. Does this to support use of `jsnext:main` in `node_modules` without the pain of managing an allow list or a nuanced deny list.
 
 ## [0.11.0] - 2015-11-27
+
 ### Added
 - Resolver plugins. Now the linter can read Webpack config, properly follow aliases and ignore externals, dismisses inline loaders, etc. etc.!
 
@@ -822,11 +894,15 @@ for info on changes for earlier releases.
 
 [`memo-parser`]: ./memo-parser/README.md
 
+[#2196]: https://github.com/import-js/eslint-plugin-import/pull/2196
+[#2184]: https://github.com/import-js/eslint-plugin-import/pull/2184
 [#2179]: https://github.com/import-js/eslint-plugin-import/pull/2179
 [#2160]: https://github.com/import-js/eslint-plugin-import/pull/2160
 [#2158]: https://github.com/import-js/eslint-plugin-import/pull/2158
 [#2156]: https://github.com/import-js/eslint-plugin-import/pull/2156
+[#2149]: https://github.com/benmosher/eslint-plugin-import/pull/2149
 [#2146]: https://github.com/import-js/eslint-plugin-import/pull/2146
+[#2140]: https://github.com/import-js/eslint-plugin-import/pull/2140
 [#2138]: https://github.com/import-js/eslint-plugin-import/pull/2138
 [#2121]: https://github.com/import-js/eslint-plugin-import/pull/2121
 [#2112]: https://github.com/import-js/eslint-plugin-import/pull/2112
@@ -1074,10 +1150,12 @@ for info on changes for earlier releases.
 [#211]: https://github.com/import-js/eslint-plugin-import/pull/211
 [#164]: https://github.com/import-js/eslint-plugin-import/pull/164
 [#157]: https://github.com/import-js/eslint-plugin-import/pull/157
+[#2161]: https://github.com/import-js/eslint-plugin-import/issues/2161
 [#2118]: https://github.com/import-js/eslint-plugin-import/issues/2118
 [#2067]: https://github.com/import-js/eslint-plugin-import/issues/2067
 [#2056]: https://github.com/import-js/eslint-plugin-import/issues/2056
 [#2063]: https://github.com/import-js/eslint-plugin-import/issues/2063
+[#1998]: https://github.com/import-js/eslint-plugin-import/issues/1998
 [#1965]: https://github.com/import-js/eslint-plugin-import/issues/1965
 [#1924]: https://github.com/import-js/eslint-plugin-import/issues/1924
 [#1854]: https://github.com/import-js/eslint-plugin-import/issues/1854
@@ -1181,7 +1259,8 @@ for info on changes for earlier releases.
 [#119]: https://github.com/import-js/eslint-plugin-import/issues/119
 [#89]: https://github.com/import-js/eslint-plugin-import/issues/89
 
-[Unreleased]: https://github.com/import-js/eslint-plugin-import/compare/v2.24.0...HEAD
+[Unreleased]: https://github.com/import-js/eslint-plugin-import/compare/v2.24.1...HEAD
+[2.24.1]: https://github.com/import-js/eslint-plugin-import/compare/v2.23.0...v2.24.1
 [2.24.0]: https://github.com/import-js/eslint-plugin-import/compare/v2.23.4...v2.24.0
 [2.23.4]: https://github.com/import-js/eslint-plugin-import/compare/v2.23.3...v2.23.4
 [2.23.3]: https://github.com/import-js/eslint-plugin-import/compare/v2.23.2...v2.23.3
@@ -1330,10 +1409,12 @@ for info on changes for earlier releases.
 [@gavriguy]: https://github.com/gavriguy
 [@giodamelio]: https://github.com/giodamelio
 [@golopot]: https://github.com/golopot
+[@GoodForOneFare]: https://github.com/GoodForOneFare
 [@graingert]: https://github.com/graingert
 [@grit96]: https://github.com/grit96
 [@guillaumewuip]: https://github.com/guillaumewuip
 [@hayes]: https://github.com/hayes
+[@himynameisdave]: https://github.com/himynameisdave
 [@hulkish]: https://github.com/hulkish
 [@Hypnosphi]: https://github.com/Hypnosphi
 [@isiahmeadows]: https://github.com/isiahmeadows
@@ -1362,8 +1443,8 @@ for info on changes for earlier releases.
 [@kiwka]: https://github.com/kiwka
 [@klimashkin]: https://github.com/klimashkin
 [@kmui2]: https://github.com/kmui2
-[@KostyaZgara]: https://github.com/KostyaZgara
 [@knpwrs]: https://github.com/knpwrs
+[@KostyaZgara]: https://github.com/KostyaZgara
 [@laysent]: https://github.com/laysent
 [@le0nik]: https://github.com/le0nik
 [@lemonmade]: https://github.com/lemonmade
@@ -1396,6 +1477,7 @@ for info on changes for earlier releases.
 [@nicolashenry]: https://github.com/nicolashenry
 [@noelebrun]: https://github.com/noelebrun
 [@ntdb]: https://github.com/ntdb
+[@nwalters512]: https://github.com/nwalters512
 [@panrafal]: https://github.com/panrafal
 [@paztis]: https://github.com/paztis
 [@pcorpet]: https://github.com/pcorpet
@@ -1458,4 +1540,4 @@ for info on changes for earlier releases.
 [@wtgtybhertgeghgtwtg]: https://github.com/wtgtybhertgeghgtwtg
 [@xpl]: https://github.com/xpl
 [@yordis]: https://github.com/yordis
-[@zloirock]: https://github.com/zloirock
\ No newline at end of file
+[@zloirock]: https://github.com/zloirock
diff --git a/docs/rules/extensions.md b/docs/rules/extensions.md
index bf29dbe5..575895c5 100644
--- a/docs/rules/extensions.md
+++ b/docs/rules/extensions.md
@@ -109,6 +109,8 @@ import foo from './foo';
 import bar from './bar';
 
 import Component from './Component';
+
+import foo from '@/foo';
 ```
 
 The following patterns are not considered problems when configuration set to "always":
@@ -121,6 +123,8 @@ import bar from './bar.json';
 import Component from './Component.jsx';
 
 import * as path from 'path';
+
+import foo from '@/foo.js';
 ```
 
 The following patterns are considered problems when configuration set to "ignorePackages":
@@ -145,6 +149,7 @@ import Component from './Component.jsx';
 
 import express from 'express';
 
+import foo from '@/foo'
 ```
 
 The following patterns are not considered problems when configuration set to `['error', 'always', {ignorePackages: true} ]`:
@@ -156,6 +161,7 @@ import baz from 'foo/baz.js';
 
 import express from 'express';
 
+import foo from '@/foo';
 ```
 
 ## When Not To Use It
diff --git a/docs/rules/max-dependencies.md b/docs/rules/max-dependencies.md
index 20d29cf0..3bead827 100644
--- a/docs/rules/max-dependencies.md
+++ b/docs/rules/max-dependencies.md
@@ -6,20 +6,20 @@ This is a useful rule because a module with too many dependencies is a code smel
 
 Importing multiple named exports from a single module will only count once (e.g. `import {x, y, z} from './foo'` will only count as a single dependency).
 
-### Options
+## Options
 
-This rule takes the following option:
-
-`max`: The maximum number of dependencies allowed. Anything over will trigger the rule. **Default is 10** if the rule is enabled and no `max` is specified.
-
-You can set the option like this:
+This rule has the following options, with these defaults:
 
 ```js
-"import/max-dependencies": ["error", {"max": 10}]
+"import/max-dependencies": ["error", {
+  "max": 10,
+  "ignoreTypeImports": false,
+}]
 ```
 
+### `max`
 
-## Example
+This option sets the maximum number of dependencies allowed. Anything over will trigger the rule. **Default is 10** if the rule is enabled and no `max` is specified.
 
 Given a max value of `{"max": 2}`:
 
@@ -39,6 +39,28 @@ const anotherA = require('./a'); // still 1
 import {x, y, z} from './foo'; // 2
 ```
 
+### `ignoreTypeImports`
+
+Ignores `type` imports. Type imports are a feature released in TypeScript 3.8, you can [read more here](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export). Defaults to `false`.
+
+Given `{"max": 2, "ignoreTypeImports": true}`:
+
+### Fail
+
+```ts
+import a from './a';
+import b from './b';
+import c from './c';
+```
+
+### Pass
+
+```ts
+import a from './a';
+import b from './b';
+import type c from './c'; // Doesn't count against max
+```
+
 ## When Not To Use It
 
 If you don't care how many dependencies a module has.
diff --git a/docs/rules/no-unresolved.md b/docs/rules/no-unresolved.md
index 30cd8cb2..ae6177df 100644
--- a/docs/rules/no-unresolved.md
+++ b/docs/rules/no-unresolved.md
@@ -6,7 +6,7 @@ as defined by standard Node `require.resolve` behavior.
 See [settings](../../README.md#settings) for customization options for the resolution (i.e.
 additional filetypes, `NODE_PATH`, etc.)
 
-This rule can also optionally report on unresolved modules in CommonJS `require('./foo')` calls and AMD `require(['./foo'], function (foo){...})` and `define(['./foo'], function (foo){...})`.
+This rule can also optionally report on unresolved modules in CommonJS `require('./foo')` calls and AMD `require(['./foo'], function (foo) {...})` and `define(['./foo'], function (foo) {...})`.
 
 To enable this, send `{ commonjs: true/false, amd: true/false }` as a rule option.
 Both are disabled by default.
diff --git a/package.json b/package.json
index e3bc5a8d..df42105d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "eslint-plugin-import",
-  "version": "2.24.0",
+  "version": "2.24.1",
   "description": "Import with sanity.",
   "engines": {
     "node": ">=4"
@@ -69,7 +69,7 @@
     "babel-register": "^6.26.0",
     "babylon": "^6.18.0",
     "chai": "^4.3.4",
-    "coveralls": "^3.1.0",
+    "coveralls": "^3.1.1",
     "cross-env": "^4.0.0",
     "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0",
     "eslint-import-resolver-node": "file:./resolvers/node",
@@ -104,16 +104,16 @@
     "array.prototype.flat": "^1.2.4",
     "debug": "^2.6.9",
     "doctrine": "^2.1.0",
-    "eslint-import-resolver-node": "^0.3.5",
+    "eslint-import-resolver-node": "^0.3.6",
     "eslint-module-utils": "^2.6.2",
     "find-up": "^2.0.0",
     "has": "^1.0.3",
-    "is-core-module": "^2.4.0",
+    "is-core-module": "^2.6.0",
     "minimatch": "^3.0.4",
-    "object.values": "^1.1.3",
+    "object.values": "^1.1.4",
     "pkg-up": "^2.0.0",
     "read-pkg-up": "^3.0.0",
     "resolve": "^1.20.0",
-    "tsconfig-paths": "^3.9.0"
+    "tsconfig-paths": "^3.10.1"
   }
 }
diff --git a/resolvers/node/CHANGELOG.md b/resolvers/node/CHANGELOG.md
index 2fbf07ab..c237855a 100644
--- a/resolvers/node/CHANGELOG.md
+++ b/resolvers/node/CHANGELOG.md
@@ -5,6 +5,10 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
 
 ## Unreleased
 
+## v0.3.6 - 2021-08-15
+### Fixed
+- when "module" does not exist, fall back to "main" ([#2186], thanks [@ljharb])
+
 ## v0.3.5 - 2021-08-08
 ### Added
 - use "module" in the same spot as "jsnext:main" ([#2166], thanks [@MustafaHaddara])
@@ -52,13 +56,13 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
 ### Fixed
 - find files with `.json` extensions (#333, thanks for noticing @jfmengels)
 
+[#2186]: https://github.com/import-js/eslint-plugin-import/issues/2186
 [#2166]: https://github.com/import-js/eslint-plugin-import/pull/2166
-[#438]: https://github.com/import-js/eslint-plugin-import/pull/438
-
 [#1663]: https://github.com/import-js/eslint-plugin-import/issues/1663
 [#1595]: https://github.com/import-js/eslint-plugin-import/pull/1595
 [#939]: https://github.com/import-js/eslint-plugin-import/issues/939
 [#531]: https://github.com/import-js/eslint-plugin-import/issues/531
+[#438]: https://github.com/import-js/eslint-plugin-import/pull/438
 [#437]: https://github.com/import-js/eslint-plugin-import/issues/437
 
 [@jasonkarns]: https://github.com/jasonkarns
@@ -66,4 +70,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
+[@MustafaHaddara]: https://github.com/MustafaHaddara
diff --git a/resolvers/node/index.js b/resolvers/node/index.js
index 84fc5076..899e552e 100644
--- a/resolvers/node/index.js
+++ b/resolvers/node/index.js
@@ -17,7 +17,8 @@ exports.resolve = function (source, file, config) {
   }
 
   try {
-    resolvedPath = resolve.sync(source, opts(file, config));
+    const cachedFilter = function (pkg, dir) { return packageFilter(pkg, dir, config); };
+    resolvedPath = resolve.sync(source, opts(file, config, cachedFilter));
     log('Resolved to:', resolvedPath);
     return { found: true, path: resolvedPath };
   } catch (err) {
@@ -26,7 +27,7 @@ exports.resolve = function (source, file, config) {
   }
 };
 
-function opts(file, config) {
+function opts(file, config, packageFilter) {
   return Object.assign({
     // more closely matches Node (#333)
     // plus 'mjs' for native modules! (#939)
@@ -36,16 +37,32 @@ function opts(file, config) {
   {
     // path.resolve will handle paths relative to CWD
     basedir: path.dirname(path.resolve(file)),
-    packageFilter: packageFilter,
-
+    packageFilter,
   });
 }
 
-function packageFilter(pkg) {
+function identity(x) { return x; }
+
+function packageFilter(pkg, dir, config) {
+  let found = false;
+  const file = path.join(dir, 'dummy.js');
   if (pkg.module) {
-    pkg.main = pkg.module;
-  } else if (pkg['jsnext:main']) {
-    pkg.main = pkg['jsnext:main'];
+    try {
+      resolve.sync(String(pkg.module).replace(/^(?:\.\/)?/, './'), opts(file, config, identity));
+      pkg.main = pkg.module;
+      found = true;
+    } catch (err) {
+      log('resolve threw error trying to find pkg.module:', err);
+    }
+  }
+  if (!found && pkg['jsnext:main']) {
+    try {
+      resolve.sync(String(pkg['jsnext:main']).replace(/^(?:\.\/)?/, './'), opts(file, config, identity));
+      pkg.main = pkg['jsnext:main'];
+      found = true;
+    } catch (err) {
+      log('resolve threw error trying to find pkg[\'jsnext:main\']:', err);
+    }
   }
   return pkg;
 }
diff --git a/resolvers/node/package.json b/resolvers/node/package.json
index 993f1b89..5e7e9dea 100644
--- a/resolvers/node/package.json
+++ b/resolvers/node/package.json
@@ -1,6 +1,6 @@
 {
   "name": "eslint-import-resolver-node",
-  "version": "0.3.5",
+  "version": "0.3.6",
   "description": "Node default behavior import resolution plugin for eslint-plugin-import.",
   "main": "index.js",
   "files": [
diff --git a/resolvers/webpack/index.js b/resolvers/webpack/index.js
index 50832f8f..c7a3fbca 100644
--- a/resolvers/webpack/index.js
+++ b/resolvers/webpack/index.js
@@ -118,8 +118,7 @@ exports.resolve = function (source, file, settings) {
 
     if (typeof configIndex !== 'undefined' && webpackConfig.length > configIndex) {
       webpackConfig = webpackConfig[configIndex];
-    }
-    else {
+    } else {
       webpackConfig = find(webpackConfig, function findFirstWithResolve(config) {
         return !!config.resolve;
       });
@@ -311,16 +310,16 @@ function createWebpack1ResolveSync(webpackRequire, resolveConfig, plugins) {
 /* eslint-disable */
 // from https://github.com/webpack/webpack/blob/v1.13.0/lib/WebpackOptionsApply.js#L365
 function makeRootPlugin(ModulesInRootPlugin, name, root) {
-  if(typeof root === "string")
+  if (typeof root === 'string') {
     return new ModulesInRootPlugin(name, root);
-  else if(Array.isArray(root)) {
+  } else if (Array.isArray(root)) {
     return function() {
-      root.forEach(function(root) {
+      root.forEach(function (root) {
         this.apply(new ModulesInRootPlugin(name, root));
       }, this);
     };
   }
-  return function() {};
+  return function () {};
 }
 /* eslint-enable */
 
@@ -436,17 +435,17 @@ function findConfigPath(configPath, packageDir) {
 }
 
 function registerCompiler(moduleDescriptor) {
-  if(moduleDescriptor) {
-    if(typeof moduleDescriptor === 'string') {
+  if (moduleDescriptor) {
+    if (typeof moduleDescriptor === 'string') {
       require(moduleDescriptor);
-    } else if(!Array.isArray(moduleDescriptor)) {
+    } else if (!Array.isArray(moduleDescriptor)) {
       moduleDescriptor.register(require(moduleDescriptor.module));
     } else {
-      for(let i = 0; i < moduleDescriptor.length; i++) {
+      for (let i = 0; i < moduleDescriptor.length; i++) {
         try {
           registerCompiler(moduleDescriptor[i]);
           break;
-        } catch(e) {
+        } catch (e) {
           log('Failed to register compiler for moduleDescriptor[]:', i, moduleDescriptor);
         }
       }
diff --git a/resolvers/webpack/package.json b/resolvers/webpack/package.json
index 32650c07..1e9fdd3a 100644
--- a/resolvers/webpack/package.json
+++ b/resolvers/webpack/package.json
@@ -38,8 +38,8 @@
     "find-root": "^1.1.0",
     "has": "^1.0.3",
     "interpret": "^1.4.0",
-    "is-core-module": "^2.4.0",
-    "is-regex": "^1.1.3",
+    "is-core-module": "^2.6.0",
+    "is-regex": "^1.1.4",
     "lodash": "^4.17.21",
     "resolve": "^1.20.0",
     "semver": "^5.7.1"
diff --git a/src/ExportMap.js b/src/ExportMap.js
index 76b07f9d..f4984183 100644
--- a/src/ExportMap.js
+++ b/src/ExportMap.js
@@ -351,6 +351,7 @@ ExportMap.for = function (context) {
 
 ExportMap.parse = function (path, content, context) {
   const m = new ExportMap(path);
+  const isEsModuleInteropTrue = isEsModuleInterop();
 
   let ast;
   try {
@@ -413,6 +414,39 @@ ExportMap.parse = function (path, content, context) {
     return object;
   }
 
+  function processSpecifier(s, n, m) {
+    const nsource = n.source && n.source.value;
+    const exportMeta = {};
+    let local;
+
+    switch (s.type) {
+    case 'ExportDefaultSpecifier':
+      if (!n.source) return;
+      local = 'default';
+      break;
+    case 'ExportNamespaceSpecifier':
+      m.namespace.set(s.exported.name, Object.defineProperty(exportMeta, 'namespace', {
+        get() { return resolveImport(nsource); },
+      }));
+      return;
+    case 'ExportAllDeclaration':
+      local = s.exported ? s.exported.name : s.local.name;
+      break;
+    case 'ExportSpecifier':
+      if (!n.source) {
+        m.namespace.set(s.exported.name, addNamespace(exportMeta, s.local));
+        return;
+      }
+      // else falls through
+    default:
+      local = s.local.name;
+      break;
+    }
+
+    // todo: JSDoc
+    m.reexports.set(s.exported.name, { local, getImport: () => resolveImport(nsource) });
+  }
+
   function captureDependency({ source }, isOnlyImportingTypes, importedSpecifiers = new Set()) {
     if (source == null) return null;
 
@@ -488,6 +522,9 @@ ExportMap.parse = function (path, content, context) {
     if (n.type === 'ExportAllDeclaration') {
       const getter = captureDependency(n, n.exportKind === 'type');
       if (getter) m.dependencies.add(getter);
+      if (n.exported) {
+        processSpecifier(n, n.exported, m);
+      }
       return;
     }
 
@@ -545,39 +582,9 @@ ExportMap.parse = function (path, content, context) {
         }
       }
 
-      const nsource = n.source && n.source.value;
-      n.specifiers.forEach((s) => {
-        const exportMeta = {};
-        let local;
-
-        switch (s.type) {
-        case 'ExportDefaultSpecifier':
-          if (!n.source) return;
-          local = 'default';
-          break;
-        case 'ExportNamespaceSpecifier':
-          m.namespace.set(s.exported.name, Object.defineProperty(exportMeta, 'namespace', {
-            get() { return resolveImport(nsource); },
-          }));
-          return;
-        case 'ExportSpecifier':
-          if (!n.source) {
-            m.namespace.set(s.exported.name, addNamespace(exportMeta, s.local));
-            return;
-          }
-          // else falls through
-        default:
-          local = s.local.name;
-          break;
-        }
-
-        // todo: JSDoc
-        m.reexports.set(s.exported.name, { local, getImport: () => resolveImport(nsource) });
-      });
+      n.specifiers.forEach((s) => processSpecifier(s, n, m));
     }
 
-    const isEsModuleInteropTrue = isEsModuleInterop();
-
     const exports = ['TSExportAssignment'];
     if (isEsModuleInteropTrue) {
       exports.push('TSNamespaceExportDeclaration');
@@ -606,8 +613,11 @@ ExportMap.parse = function (path, content, context) {
         m.namespace.set('default', captureDoc(source, docStyleParsers, n));
         return;
       }
-      if (isEsModuleInteropTrue) {
-        m.namespace.set('default', {});
+      if (
+        isEsModuleInteropTrue // esModuleInterop is on in tsconfig
+        && !m.namespace.has('default') // and default isn't added already
+      ) {
+        m.namespace.set('default', {}); // add default export
       }
       exportedDecls.forEach((decl) => {
         if (decl.type === 'TSModuleDeclaration') {
@@ -627,8 +637,8 @@ ExportMap.parse = function (path, content, context) {
                 namespaceDecl.declarations.forEach((d) =>
                   recursivePatternCapture(d.id, (id) => m.namespace.set(
                     id.name,
-                    captureDoc(source, docStyleParsers, decl, namespaceDecl, moduleBlockNode)
-                  ))
+                    captureDoc(source, docStyleParsers, decl, namespaceDecl, moduleBlockNode),
+                  )),
                 );
               } else {
                 m.namespace.set(
@@ -645,6 +655,14 @@ ExportMap.parse = function (path, content, context) {
     }
   });
 
+  if (
+    isEsModuleInteropTrue // esModuleInterop is on in tsconfig
+    && m.namespace.size > 0 // anything is exported
+    && !m.namespace.has('default') // and default isn't added already
+  ) {
+    m.namespace.set('default', {}); // add default export
+  }
+
   return m;
 };
 
diff --git a/src/rules/dynamic-import-chunkname.js b/src/rules/dynamic-import-chunkname.js
index 7a21ec62..16cd85a4 100644
--- a/src/rules/dynamic-import-chunkname.js
+++ b/src/rules/dynamic-import-chunkname.js
@@ -69,7 +69,7 @@ module.exports = {
 
         try {
           // just like webpack itself does
-          vm.runInNewContext(`(function(){return {${comment.value}}})()`);
+          vm.runInNewContext(`(function() {return {${comment.value}}})()`);
         }
         catch (error) {
           context.report({
diff --git a/src/rules/first.js b/src/rules/first.js
index a3b7f24e..93e9fc55 100644
--- a/src/rules/first.js
+++ b/src/rules/first.js
@@ -42,7 +42,7 @@ module.exports = {
         const errorInfos = [];
         let shouldSort = true;
         let lastSortNodesIndex = 0;
-        body.forEach(function (node, index){
+        body.forEach(function (node, index) {
           if (!anyExpressions && isPossibleDirective(node)) {
             return;
           }
diff --git a/src/rules/namespace.js b/src/rules/namespace.js
index a23cfeac..74ee9dae 100644
--- a/src/rules/namespace.js
+++ b/src/rules/namespace.js
@@ -60,7 +60,7 @@ module.exports = {
               if (!imports.size) {
                 context.report(
                   specifier,
-                  `No exported names found in module '${declaration.source.value}'.`
+                  `No exported names found in module '${declaration.source.value}'.`,
                 );
               }
               namespaces.set(specifier.local.name, imports);
@@ -69,7 +69,7 @@ module.exports = {
             case 'ImportSpecifier': {
               const meta = imports.get(
                 // default to 'default' for default http://i.imgur.com/nj6qAWy.jpg
-                specifier.imported ? specifier.imported.name : 'default'
+                specifier.imported ? specifier.imported.name : 'default',
               );
               if (!meta || !meta.namespace) { break; }
               namespaces.set(specifier.local.name, meta.namespace);
@@ -96,7 +96,7 @@ module.exports = {
         if (!imports.size) {
           context.report(
             namespace,
-            `No exported names found in module '${declaration.source.value}'.`
+            `No exported names found in module '${declaration.source.value}'.`,
           );
         }
       },
@@ -111,7 +111,7 @@ module.exports = {
         if (dereference.parent.type === 'AssignmentExpression' && dereference.parent.left === dereference) {
           context.report(
             dereference.parent,
-            `Assignment to member of namespace '${dereference.object.name}'.`
+            `Assignment to member of namespace '${dereference.object.name}'.`,
           );
         }
 
@@ -125,7 +125,7 @@ module.exports = {
             if (!allowComputed) {
               context.report(
                 dereference.property,
-                `Unable to validate computed reference to imported namespace '${dereference.object.name}'.`
+                `Unable to validate computed reference to imported namespace '${dereference.object.name}'.`,
               );
             }
             return;
@@ -134,7 +134,7 @@ module.exports = {
           if (!namespace.has(dereference.property.name)) {
             context.report(
               dereference.property,
-              makeMessage(dereference.property, namepath)
+              makeMessage(dereference.property, namepath),
             );
             break;
           }
diff --git a/src/rules/no-duplicates.js b/src/rules/no-duplicates.js
index 43a29506..63441019 100644
--- a/src/rules/no-duplicates.js
+++ b/src/rules/no-duplicates.js
@@ -276,13 +276,22 @@ module.exports = {
 
     const imported = new Map();
     const nsImported = new Map();
-    const typesImported = new Map();
+    const defaultTypesImported = new Map();
+    const namedTypesImported = new Map();
+
+    function getImportMap(n) {
+      if (n.importKind === 'type') {
+        return n.specifiers[0].type === 'ImportDefaultSpecifier' ? defaultTypesImported : namedTypesImported;
+      }
+
+      return hasNamespace(n) ? nsImported : imported;
+    }
+
     return {
-      'ImportDeclaration': function (n) {
+      ImportDeclaration(n) {
         // resolved path will cover aliased duplicates
         const resolvedPath = resolver(n.source.value);
-        const importMap = n.importKind === 'type' ? typesImported :
-          (hasNamespace(n) ? nsImported : imported);
+        const importMap = getImportMap(n);
 
         if (importMap.has(resolvedPath)) {
           importMap.get(resolvedPath).push(n);
@@ -291,10 +300,11 @@ module.exports = {
         }
       },
 
-      'Program:exit': function () {
+      'Program:exit'() {
         checkImports(imported, context);
         checkImports(nsImported, context);
-        checkImports(typesImported, context);
+        checkImports(defaultTypesImported, context);
+        checkImports(namedTypesImported, context);
       },
     };
   },
diff --git a/src/rules/no-unresolved.js b/src/rules/no-unresolved.js
index 61dc0b6c..719bbded 100644
--- a/src/rules/no-unresolved.js
+++ b/src/rules/no-unresolved.js
@@ -15,35 +15,36 @@ module.exports = {
       url: docsUrl('no-unresolved'),
     },
 
-    schema: [ makeOptionsSchema({
-      caseSensitive: { type: 'boolean', default: true },
-    })],
+    schema: [
+      makeOptionsSchema({
+        caseSensitive: { type: 'boolean', default: true },
+      }),
+    ],
   },
 
   create: function (context) {
-
     function checkSourceValue(source) {
-      const shouldCheckCase = !CASE_SENSITIVE_FS &&
-        (!context.options[0] || context.options[0].caseSensitive !== false);
+      const shouldCheckCase = !CASE_SENSITIVE_FS
+        && (!context.options[0] || context.options[0].caseSensitive !== false);
 
       const resolvedPath = resolve(source.value, context);
 
       if (resolvedPath === undefined) {
-        context.report(source,
-          `Unable to resolve path to module '${source.value}'.`);
-      }
-
-      else if (shouldCheckCase) {
+        context.report(
+          source,
+          `Unable to resolve path to module '${source.value}'.`
+        );
+      } else if (shouldCheckCase) {
         const cacheSettings = ModuleCache.getSettings(context.settings);
         if (!fileExistsWithCaseSync(resolvedPath, cacheSettings)) {
-          context.report(source,
-            `Casing of ${source.value} does not match the underlying filesystem.`);
+          context.report(
+            source,
+            `Casing of ${source.value} does not match the underlying filesystem.`
+          );
         }
-
       }
     }
 
     return moduleVisitor(checkSourceValue, context.options[0]);
-
   },
 };
diff --git a/src/rules/no-unused-modules.js b/src/rules/no-unused-modules.js
index 205259ee..d49674e7 100644
--- a/src/rules/no-unused-modules.js
+++ b/src/rules/no-unused-modules.js
@@ -540,7 +540,7 @@ module.exports = {
 
       const value = exportsKey === IMPORT_DEFAULT_SPECIFIER ? DEFAULT : exportsKey;
 
-      if (typeof exportStatement !== 'undefined'){
+      if (typeof exportStatement !== 'undefined') {
         if (exportStatement.whereUsed.size < 1) {
           context.report(
             node,
diff --git a/src/rules/order.js b/src/rules/order.js
index ce34604c..857a46e3 100644
--- a/src/rules/order.js
+++ b/src/rules/order.js
@@ -47,8 +47,7 @@ function takeTokensAfterWhile(sourceCode, node, condition) {
   for (let i = 0; i < tokens.length; i++) {
     if (condition(tokens[i])) {
       result.push(tokens[i]);
-    }
-    else {
+    } else {
       break;
     }
   }
@@ -61,8 +60,7 @@ function takeTokensBeforeWhile(sourceCode, node, condition) {
   for (let i = tokens.length - 1; i >= 0; i--) {
     if (condition(tokens[i])) {
       result.push(tokens[i]);
-    }
-    else {
+    } else {
       break;
     }
   }
diff --git a/src/rules/prefer-default-export.js b/src/rules/prefer-default-export.js
index 5e77126d..3cd2224c 100644
--- a/src/rules/prefer-default-export.js
+++ b/src/rules/prefer-default-export.js
@@ -69,8 +69,7 @@ module.exports = {
           node.declaration.declarations.forEach(function(declaration) {
             captureDeclaration(declaration.id);
           });
-        }
-        else {
+        } else {
           // captures 'export function foo() {}' syntax
           specifierExportCount++;
         }
diff --git a/utils/moduleVisitor.js b/utils/moduleVisitor.js
index 69269985..7f783624 100644
--- a/utils/moduleVisitor.js
+++ b/utils/moduleVisitor.js
@@ -131,7 +131,7 @@ function makeOptionsSchema(additionalProperties) {
     'additionalProperties': false,
   };
 
-  if (additionalProperties){
+  if (additionalProperties) {
     for (const key in additionalProperties) {
       base.properties[key] = additionalProperties[key];
     }


Test patch:
diff --git a/resolvers/node/test/package-mains/module-broken/main.js b/resolvers/node/test/package-mains/module-broken/main.js
new file mode 100644
index 00000000..f053ebf7
--- /dev/null
+++ b/resolvers/node/test/package-mains/module-broken/main.js
@@ -0,0 +1,1 @@
+module.exports = {};
diff --git a/resolvers/node/test/package-mains/module-broken/package.json b/resolvers/node/test/package-mains/module-broken/package.json
new file mode 100644
index 00000000..36a31838
--- /dev/null
+++ b/resolvers/node/test/package-mains/module-broken/package.json
@@ -0,0 +1,4 @@
+{
+  "main": "./main.js",
+  "module": "./doesNotExist.js"
+}
diff --git a/resolvers/node/test/packageMains.js b/resolvers/node/test/packageMains.js
index 0a7d9463..caac6221 100644
--- a/resolvers/node/test/packageMains.js
+++ b/resolvers/node/test/packageMains.js
@@ -4,24 +4,29 @@ const chai = require('chai');
 const expect = chai.expect;
 const path = require('path');
 
-const webpack = require('../');
+const resolver = require('../');
 
 const file = path.join(__dirname, 'package-mains', 'dummy.js');
 
 
 describe('packageMains', function () {
   it('captures module', function () {
-    expect(webpack.resolve('./module', file)).property('path')
+    expect(resolver.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')
+    expect(resolver.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')
+    expect(resolver.resolve('./module-and-jsnext', file)).property('path')
       .to.equal(path.join(__dirname, 'package-mains', 'module-and-jsnext', 'src', 'index.js'));
   });
+
+  it('falls back from a missing "module" to "main"', function () {
+    expect(resolver.resolve('./module-broken', file)).property('path')
+      .to.equal(path.join(__dirname, 'package-mains', 'module-broken', 'main.js'));
+  });
 });
diff --git a/resolvers/webpack/test/package-mains/module-broken/main.js b/resolvers/webpack/test/package-mains/module-broken/main.js
new file mode 100644
index 00000000..f053ebf7
--- /dev/null
+++ b/resolvers/webpack/test/package-mains/module-broken/main.js
@@ -0,0 +1,1 @@
+module.exports = {};
diff --git a/resolvers/webpack/test/package-mains/module-broken/package.json b/resolvers/webpack/test/package-mains/module-broken/package.json
new file mode 100644
index 00000000..36a31838
--- /dev/null
+++ b/resolvers/webpack/test/package-mains/module-broken/package.json
@@ -0,0 +1,4 @@
+{
+  "main": "./main.js",
+  "module": "./doesNotExist.js"
+}
diff --git a/resolvers/webpack/test/packageMains.js b/resolvers/webpack/test/packageMains.js
index 96becbc8..fef3dde0 100644
--- a/resolvers/webpack/test/packageMains.js
+++ b/resolvers/webpack/test/packageMains.js
@@ -4,7 +4,7 @@ const chai = require('chai');
 const expect = chai.expect;
 const path = require('path');
 
-const webpack = require('../');
+const resolver = require('../');
 
 const file = path.join(__dirname, 'package-mains', 'dummy.js');
 
@@ -12,43 +12,47 @@ const file = path.join(__dirname, 'package-mains', 'dummy.js');
 describe('packageMains', function () {
 
   it('captures module', function () {
-    expect(webpack.resolve('./module', file)).property('path')
+    expect(resolver.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')
+    expect(resolver.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')
+    expect(resolver.resolve('./module-and-jsnext', file)).property('path')
       .to.equal(path.join(__dirname, 'package-mains', 'module-and-jsnext', 'src', 'index.js'));
   });
 
+  it('falls back from a missing "module" to "main"', function () {
+    expect(resolver.resolve('./module-broken', file)).property('path')
+      .to.equal(path.join(__dirname, 'package-mains', 'module-broken', 'main.js'));
+  });
+
   it('captures webpack', function () {
-    expect(webpack.resolve('./webpack', file)).property('path')
+    expect(resolver.resolve('./webpack', file)).property('path')
       .to.equal(path.join(__dirname, 'package-mains', 'webpack', 'webpack.js'));
   });
 
   it('captures jam (array path)', function () {
-    expect(webpack.resolve('./jam', file)).property('path')
+    expect(resolver.resolve('./jam', file)).property('path')
       .to.equal(path.join(__dirname, 'package-mains', 'jam', 'jam.js'));
   });
 
   it('uses configured packageMains, if provided', function () {
-    expect(webpack.resolve('./webpack', file, { config: 'webpack.alt.config.js' })).property('path')
+    expect(resolver.resolve('./webpack', file, { config: 'webpack.alt.config.js' })).property('path')
       .to.equal(path.join(__dirname, 'package-mains', 'webpack', 'index.js'));
   });
 
   it('always defers to module, regardless of config', function () {
-    expect(webpack.resolve('./module', file, { config: 'webpack.alt.config.js' })).property('path')
+    expect(resolver.resolve('./module', file, { config: 'webpack.alt.config.js' })).property('path')
       .to.equal(path.join(__dirname, 'package-mains', 'module', 'src', 'index.js'));
   });
 
   it('always defers to jsnext:main, regardless of config', function () {
-    expect(webpack.resolve('./jsnext', file, { config: 'webpack.alt.config.js' })).property('path')
+    expect(resolver.resolve('./jsnext', file, { config: 'webpack.alt.config.js' })).property('path')
       .to.equal(path.join(__dirname, 'package-mains', 'jsnext', 'src', 'index.js'));
   });
-
 });
diff --git a/tests/files/export-star-2/middle.js b/tests/files/export-star-2/middle.js
new file mode 100644
index 00000000..2fc07cd9
--- /dev/null
+++ b/tests/files/export-star-2/middle.js
@@ -0,0 +1,1 @@
+export * as myName from './upstream';
diff --git a/tests/files/export-star-2/upstream.js b/tests/files/export-star-2/upstream.js
new file mode 100644
index 00000000..cc798ff5
--- /dev/null
+++ b/tests/files/export-star-2/upstream.js
@@ -0,0 +1,1 @@
+export const a = 1;
diff --git a/tests/files/export-star/extfield.js b/tests/files/export-star/extfield.js
new file mode 100644
index 00000000..7a4e8a72
--- /dev/null
+++ b/tests/files/export-star/extfield.js
@@ -0,0 +1,1 @@
+export default 42;
diff --git a/tests/files/export-star/extfield2.js b/tests/files/export-star/extfield2.js
new file mode 100644
index 00000000..5f2610af
--- /dev/null
+++ b/tests/files/export-star/extfield2.js
@@ -0,0 +1,1 @@
+export default NaN;
diff --git a/tests/files/export-star/models.js b/tests/files/export-star/models.js
new file mode 100644
index 00000000..1091770f
--- /dev/null
+++ b/tests/files/export-star/models.js
@@ -0,0 +1,2 @@
+export * as ExtfieldModel from './extfield';
+export * as Extfield2Model from './extfield2';
diff --git a/tests/files/foo-bar-resolver-no-version.js b/tests/files/foo-bar-resolver-no-version.js
index 89d4eb13..f0019856 100644
--- a/tests/files/foo-bar-resolver-no-version.js
+++ b/tests/files/foo-bar-resolver-no-version.js
@@ -5,10 +5,8 @@ exports.resolveImport = function (modulePath, sourceFile, config) {
   if (sourceFileName === 'foo.js') {
     return path.join(__dirname, 'bar.jsx')
   }
-  else if (sourceFileName === 'exception.js') {
+  if (sourceFileName === 'exception.js') {
     throw new Error('foo-bar-resolver-v1 resolveImport test exception')
   }
-  else {
-    return undefined
-  }
+  return undefined;
 }
diff --git a/tests/files/foo-bar-resolver-v1.js b/tests/files/foo-bar-resolver-v1.js
index 8aafe7aa..af9da1b7 100644
--- a/tests/files/foo-bar-resolver-v1.js
+++ b/tests/files/foo-bar-resolver-v1.js
@@ -3,14 +3,12 @@ var path = require('path')
 exports.resolveImport = function (modulePath, sourceFile, config) {
   var sourceFileName = path.basename(sourceFile)
   if (sourceFileName === 'foo.js') {
-    return path.join(__dirname, 'bar.jsx')
+    return path.join(__dirname, 'bar.jsx');
   }
-  else if (sourceFileName === 'exception.js') {
-    throw new Error('foo-bar-resolver-v1 resolveImport test exception')
+  if (sourceFileName === 'exception.js') {
+    throw new Error('foo-bar-resolver-v1 resolveImport test exception');
   }
-  else {
-    return undefined
-  }
-}
+  return undefined;
+};
 
-exports.interfaceVersion = 1
+exports.interfaceVersion = 1;
diff --git a/tests/files/foo-bar-resolver-v2.js b/tests/files/foo-bar-resolver-v2.js
index 9bb68171..7f8bcc0f 100644
--- a/tests/files/foo-bar-resolver-v2.js
+++ b/tests/files/foo-bar-resolver-v2.js
@@ -5,12 +5,10 @@ exports.resolve = function (modulePath, sourceFile, config) {
   if (sourceFileName === 'foo.js') {
     return { found: true, path: path.join(__dirname, 'bar.jsx') }
   }
-  else if (sourceFileName === 'exception.js') {
+  if (sourceFileName === 'exception.js') {
     throw new Error('foo-bar-resolver-v2 resolve test exception')
   }
-  else {
-    return { found: false }
-  }
-}
+  return { found: false };
+};
 
-exports.interfaceVersion = 2
+exports.interfaceVersion = 2;
diff --git a/tests/files/typescript-export-react-test-renderer/index.d.ts b/tests/files/typescript-export-react-test-renderer/index.d.ts
new file mode 100644
index 00000000..ff70c713
--- /dev/null
+++ b/tests/files/typescript-export-react-test-renderer/index.d.ts
@@ -0,0 +1,19 @@
+// case from @types/react-test-renderer
+
+export {};
+
+export interface ReactTestRendererJSON {
+    type: string;
+    props: { [propName: string]: any };
+    children: null | ReactTestRendererNode[];
+}
+export type ReactTestRendererNode = ReactTestRendererJSON | string;
+export interface ReactTestRendererTree extends ReactTestRendererJSON {
+    nodeType: 'component' | 'host';
+    instance: any;
+    rendered: null | ReactTestRendererTree | ReactTestRendererTree[];
+}
+
+export function create(nextElement: any, options?: any): any;
+
+export function act(callback: () => Promise<any>): Promise<undefined>;
diff --git a/tests/files/typescript-export-react-test-renderer/tsconfig.json b/tests/files/typescript-export-react-test-renderer/tsconfig.json
new file mode 100644
index 00000000..a72ee3e8
--- /dev/null
+++ b/tests/files/typescript-export-react-test-renderer/tsconfig.json
@@ -0,0 +1,5 @@
+{
+    "compilerOptions": {
+        "esModuleInterop": true
+    }
+}
diff --git a/tests/files/typescript.ts b/tests/files/typescript.ts
index 7f90314e..f8fe2e8e 100644
--- a/tests/files/typescript.ts
+++ b/tests/files/typescript.ts
@@ -23,14 +23,14 @@ export function getFoo() : MyType {
 }
 
 export module MyModule {
-  export function ModuleFunction(){}
+  export function ModuleFunction() {}
 }
 
 export namespace MyNamespace {
-  export function NamespaceFunction(){}
+  export function NamespaceFunction() {}
 
   export module NSModule {
-    export function NSModuleFunction(){}
+    export function NSModuleFunction() {}
   }
 }
 
diff --git a/tests/src/cli.js b/tests/src/cli.js
index 91d3dfc1..b0285593 100644
--- a/tests/src/cli.js
+++ b/tests/src/cli.js
@@ -7,6 +7,7 @@ import { expect } from 'chai';
 import { CLIEngine } from 'eslint';
 import eslintPkg from 'eslint/package.json';
 import semver from 'semver';
+import * as importPlugin from '../../src/index';
 
 describe('CLI regression tests', function () {
   describe('issue #210', function () {
@@ -20,6 +21,7 @@ describe('CLI regression tests', function () {
           'named': 2,
         },
       });
+      cli.addPlugin('eslint-plugin-import', importPlugin);
     });
     it("doesn't throw an error on gratuitous, erroneous self-reference", function () {
       expect(() => cli.executeOnFiles(['./tests/files/issue210.js'])).not.to.throw();
@@ -38,6 +40,7 @@ describe('CLI regression tests', function () {
           rulePaths: ['./src/rules'],
           ignore: false,
         });
+        cli.addPlugin('eslint-plugin-import', importPlugin);
       }
     });
 
diff --git a/tests/src/rules/default.js b/tests/src/rules/default.js
index c7eb780d..a861fff7 100644
--- a/tests/src/rules/default.js
+++ b/tests/src/rules/default.js
@@ -220,6 +220,17 @@ context('TypeScript', function () {
             tsconfigRootDir: path.resolve(__dirname, '../../files/typescript-export-as-default-namespace/'),
           },
         }),
+        test({
+          code: `import Foo from "./typescript-export-react-test-renderer"`,
+          parser: parser,
+          settings: {
+            'import/parsers': { [parser]: ['.ts'] },
+            'import/resolver': { 'eslint-import-resolver-typescript': true },
+          },
+          parserOptions: {
+            tsconfigRootDir: path.resolve(__dirname, '../../files/typescript-export-react-test-renderer/'),
+          },
+        }),
         test({
           code: `import foobar from "./typescript-export-assign-property"`,
           parser: parser,
diff --git a/tests/src/rules/first.js b/tests/src/rules/first.js
index 3f730131..9d278706 100644
--- a/tests/src/rules/first.js
+++ b/tests/src/rules/first.js
@@ -7,60 +7,71 @@ const rule = require('rules/first');
 
 ruleTester.run('first', rule, {
   valid: [
-    test({ code: "import { x } from './foo'; import { y } from './bar';\
-                  export { x, y }" }),
+    test({
+      code: "import { x } from './foo'; import { y } from './bar';\
+            export { x, y }",
+    }),
     test({ code: "import { x } from 'foo'; import { y } from './bar'" }),
     test({ code: "import { x } from './foo'; import { y } from 'bar'" }),
-    test({ code: "import { x } from './foo'; import { y } from 'bar'",
+    test({
+      code: "import { x } from './foo'; import { y } from 'bar'",
       options: ['disable-absolute-first'],
     }),
-    test({ code: "'use directive';\
-                  import { x } from 'foo';" }),  
+    test({
+      code: "'use directive';\
+            import { x } from 'foo';",
+    }),
   ],
   invalid: [
-    test({ code: "import { x } from './foo';\
-                  export { x };\
-                  import { y } from './bar';",
-    errors: 1,
-    output: "import { x } from './foo';\
-                  import { y } from './bar';\
-                  export { x };",
+    test({
+      code: "import { x } from './foo';\
+              export { x };\
+              import { y } from './bar';",
+      errors: 1,
+      output: "import { x } from './foo';\
+              import { y } from './bar';\
+              export { x };",
     }),
-    test({ code: "import { x } from './foo';\
-                  export { x };\
-                  import { y } from './bar';\
-                  import { z } from './baz';",
-    errors: 2,
-    output: "import { x } from './foo';\
-                  import { y } from './bar';\
-                  import { z } from './baz';\
-                  export { x };",
+    test({
+      code: "import { x } from './foo';\
+              export { x };\
+              import { y } from './bar';\
+              import { z } from './baz';",
+      errors: 2,
+      output: "import { x } from './foo';\
+              import { y } from './bar';\
+              import { z } from './baz';\
+              export { x };",
     }),
-    test({ code: "import { x } from './foo'; import { y } from 'bar'",
+    test({
+      code: "import { x } from './foo'; import { y } from 'bar'",
       options: ['absolute-first'],
       errors: 1,
     }),
-    test({ code: "import { x } from 'foo';\
-                  'use directive';\
-                  import { y } from 'bar';",
-    errors: 1,
-    output: "import { x } from 'foo';\
-                  import { y } from 'bar';\
-                  'use directive';",
+    test({
+      code: "import { x } from 'foo';\
+              'use directive';\
+              import { y } from 'bar';",
+      errors: 1,
+      output: "import { x } from 'foo';\
+              import { y } from 'bar';\
+              'use directive';",
     }),
-    test({ code: "var a = 1;\
-                  import { y } from './bar';\
-                  if (true) { x() };\
-                  import { x } from './foo';\
-                  import { z } from './baz';",
-    errors: 3,
-    output: "import { y } from './bar';\
-                  var a = 1;\
-                  if (true) { x() };\
-                  import { x } from './foo';\
-                  import { z } from './baz';",
+    test({
+      code: "var a = 1;\
+              import { y } from './bar';\
+              if (true) { x() };\
+              import { x } from './foo';\
+              import { z } from './baz';",
+      errors: 3,
+      output: "import { y } from './bar';\
+              var a = 1;\
+              if (true) { x() };\
+              import { x } from './foo';\
+              import { z } from './baz';",
     }),
-    test({ code: "if (true) { console.log(1) }import a from 'b'",
+    test({
+      code: "if (true) { console.log(1) }import a from 'b'",
       errors: 1,
       output: "import a from 'b'\nif (true) { console.log(1) }",
     }),  
@@ -72,7 +83,7 @@ context('TypeScript', function () {
     .filter((parser) => parser !== require.resolve('typescript-eslint-parser'))
     .forEach((parser) => {
       const parserConfig = {
-        parser: parser,
+        parser,
         settings: {
           'import/parsers': { [parser]: ['.ts'] },
           'import/resolver': { 'eslint-import-resolver-typescript': true },
@@ -81,35 +92,29 @@ context('TypeScript', function () {
 
       ruleTester.run('order', rule, {
         valid: [
-          test(
-            {
-              code: `
-                import y = require('bar');
-                import { x } from 'foo';
-                import z = require('baz');
-              `,
-              parser,
-            },
-            parserConfig,
-          ),
+          test({
+            code: `
+              import y = require('bar');
+              import { x } from 'foo';
+              import z = require('baz');
+            `,
+            ...parserConfig,
+          }),
         ],
         invalid: [
-          test(
-            {
-              code: `
-                import { x } from './foo';
-                import y = require('bar');
-              `,
-              options: ['absolute-first'],
-              parser,
-              errors: [
-                {
-                  message: 'Absolute imports should come before relative imports.',
-                },
-              ],
-            },
-            parserConfig,
-          ),
+          test({
+            code: `
+              import { x } from './foo';
+              import y = require('bar');
+            `,
+            options: ['absolute-first'],
+            ...parserConfig,
+            errors: [
+              {
+                message: 'Absolute imports should come before relative imports.',
+              },
+            ],
+          }),
         ],
       });
     });
diff --git a/tests/src/rules/named.js b/tests/src/rules/named.js
index 57e40c91..0d8c0b7e 100644
--- a/tests/src/rules/named.js
+++ b/tests/src/rules/named.js
@@ -1,4 +1,4 @@
-import { test, SYNTAX_CASES, getTSParsers } from '../utils';
+import { test, SYNTAX_CASES, getTSParsers, testFilePath, testVersion } from '../utils';
 import { RuleTester } from 'eslint';
 
 import { CASE_SENSITIVE_FS } from 'eslint-module-utils/resolve';
@@ -182,10 +182,18 @@ ruleTester.run('named', rule, {
     }),
 
     ...SYNTAX_CASES,
+
+    ...[].concat(testVersion('>= 6', () => ({
+      code: `import { ExtfieldModel, Extfield2Model } from './models';`,
+      filename: testFilePath('./export-star/downstream.js'),
+      parserOptions: {
+        sourceType: 'module',
+        ecmaVersion: 2020,
+      },
+    })) || []),
   ],
 
   invalid: [
-
     test({ code: 'import { somethingElse } from "./test-module"',
       errors: [ error('somethingElse', './test-module') ] }),
 
diff --git a/tests/src/rules/namespace.js b/tests/src/rules/namespace.js
index ce55bccc..802d5b44 100644
--- a/tests/src/rules/namespace.js
+++ b/tests/src/rules/namespace.js
@@ -1,4 +1,4 @@
-import { test, SYNTAX_CASES, getTSParsers } from '../utils';
+import { test, SYNTAX_CASES, getTSParsers, testVersion, testFilePath } from '../utils';
 import { RuleTester } from 'eslint';
 import flatMap from 'array.prototype.flatmap';
 
@@ -172,6 +172,18 @@ const valid = [
     export const getExampleColor = () => color.example
     `,
   }),
+
+  ...[].concat(testVersion('>= 6', () => ({
+    code: `
+      import * as middle from './middle';
+
+      console.log(middle.myName);
+    `,
+    filename: testFilePath('export-star-2/downstream.js'),
+    parserOptions: {
+      ecmaVersion: 2020,
+    },
+  })) || []),
 ];
 
 const invalid = [
diff --git a/tests/src/rules/newline-after-import.js b/tests/src/rules/newline-after-import.js
index 867a6485..39f4c429 100644
--- a/tests/src/rules/newline-after-import.js
+++ b/tests/src/rules/newline-after-import.js
@@ -26,7 +26,7 @@ ruleTester.run('newline-after-import', require('rules/newline-after-import'), {
       code: `const x = () => require('baz') && require('bar')`,
       parserOptions: { ecmaVersion: 6 } ,
     },
-    `function x(){ require('baz'); }`,
+    `function x() { require('baz'); }`,
     `a(require('b'), require('c'), require('d'));`,
     `function foo() {
       switch (renderData.modalViewKey) {
diff --git a/tests/src/rules/no-amd.js b/tests/src/rules/no-amd.js
index 74c89c41..91e29234 100644
--- a/tests/src/rules/no-amd.js
+++ b/tests/src/rules/no-amd.js
@@ -2,7 +2,7 @@ import { RuleTester } from 'eslint';
 import eslintPkg from 'eslint/package.json';
 import semver from 'semver';
 
-const ruleTester = new RuleTester();
+const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2015, sourceType: 'module' } });
 
 ruleTester.run('no-amd', require('rules/no-amd'), {
   valid: [
diff --git a/tests/src/rules/no-commonjs.js b/tests/src/rules/no-commonjs.js
index b1d8c03c..a2e3464c 100644
--- a/tests/src/rules/no-commonjs.js
+++ b/tests/src/rules/no-commonjs.js
@@ -5,7 +5,7 @@ import semver from 'semver';
 const EXPORT_MESSAGE = 'Expected "export" or "export default"';
 const IMPORT_MESSAGE = 'Expected "import" instead of "require()"';
 
-const ruleTester = new RuleTester();
+const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2015, sourceType: 'module' } });
 
 ruleTester.run('no-commonjs', require('rules/no-commonjs'), {
   valid: [
diff --git a/tests/src/rules/no-cycle.js b/tests/src/rules/no-cycle.js
index 11fc515f..c4e3235e 100644
--- a/tests/src/rules/no-cycle.js
+++ b/tests/src/rules/no-cycle.js
@@ -61,7 +61,7 @@ ruleTester.run('no-cycle', rule, {
         options: [{ maxDepth: 1 }],
       }),
       test({
-        code: `import("./${testDialect}/depth-two").then(function({ foo }){})`,
+        code: `import("./${testDialect}/depth-two").then(function({ foo }) {})`,
         options: [{ maxDepth: 1 }],
         parser: require.resolve('babel-eslint'),
       }),
diff --git a/tests/src/rules/no-duplicates.js b/tests/src/rules/no-duplicates.js
index d16f37b1..c6b355ab 100644
--- a/tests/src/rules/no-duplicates.js
+++ b/tests/src/rules/no-duplicates.js
@@ -420,7 +420,7 @@ context('TypeScript', function() {
     .filter((parser) => parser !== require.resolve('typescript-eslint-parser'))
     .forEach((parser) => {
       const parserConfig = {
-        parser: parser,
+        parser,
         settings: {
           'import/parsers': { [parser]: ['.ts'] },
           'import/resolver': { 'eslint-import-resolver-typescript': true },
@@ -430,15 +430,75 @@ context('TypeScript', function() {
       ruleTester.run('no-duplicates', rule, {
         valid: [
         // #1667: ignore duplicate if is a typescript type import
-          test(
-            {
-              code: "import type { x } from './foo'; import y from './foo'",
-              parser,
-            },
-            parserConfig,
-          ),
+          test({
+            code: "import type { x } from './foo'; import y from './foo'",
+            ...parserConfig,
+          }),
+          test({
+            code: "import type x from './foo'; import type y from './bar'",
+            ...parserConfig,
+          }),
+          test({
+            code: "import type {x} from './foo'; import type {y} from './bar'",
+            ...parserConfig,
+          }),
+          test({
+            code: "import type x from './foo'; import type {y} from './foo'",
+            ...parserConfig,
+          }),
+        ],
+        invalid: [
+          test({
+            code: "import type x from './foo'; import type y from './foo'",
+            ...parserConfig,
+            errors: [
+              {
+                line: 1,
+                column: 20,
+                message: "'./foo' imported multiple times.",
+              },
+              {
+                line: 1,
+                column: 48,
+                message: "'./foo' imported multiple times.",
+              },
+            ],
+          }),
+          test({
+            code: "import type x from './foo'; import type x from './foo'",
+            output: "import type x from './foo'; ",
+            ...parserConfig,
+            errors: [
+              {
+                line: 1,
+                column: 20,
+                message: "'./foo' imported multiple times.",
+              },
+              {
+                line: 1,
+                column: 48,
+                message: "'./foo' imported multiple times.",
+              },
+            ],
+          }),
+          test({
+            code: "import type {x} from './foo'; import type {y} from './foo'",
+            ...parserConfig,
+            output: `import type {x,y} from './foo'; `,
+            errors: [
+              {
+                line: 1,
+                column: 22,
+                message: "'./foo' imported multiple times.",
+              },
+              {
+                line: 1,
+                column: 52,
+                message: "'./foo' imported multiple times.",
+              },
+            ],
+          }),
         ],
-        invalid: [],
       });
     });
 });
diff --git a/tests/src/rules/no-unresolved.js b/tests/src/rules/no-unresolved.js
index a8694ddf..d21ee2fd 100644
--- a/tests/src/rules/no-unresolved.js
+++ b/tests/src/rules/no-unresolved.js
@@ -122,7 +122,7 @@ function runResolverTests(resolver) {
         type: 'Literal',
         }] }),
       rest({
-        code: "import('in-alternate-root').then(function({DEEP}){});",
+        code: "import('in-alternate-root').then(function({DEEP}) {});",
         errors: [{
           message: 'Unable to resolve path to module \'in-alternate-root\'.',
           type: 'Literal',
@@ -138,7 +138,7 @@ function runResolverTests(resolver) {
 
       // check with eslint parser
       testVersion('>= 7', () => rest({
-        code: "import('in-alternate-root').then(function({DEEP}){});",
+        code: "import('in-alternate-root').then(function({DEEP}) {});",
         errors: [{
           message: 'Unable to resolve path to module \'in-alternate-root\'.',
           type: 'Literal',
diff --git a/tests/src/rules/no-unused-modules.js b/tests/src/rules/no-unused-modules.js
index 283fa3e9..17e52b41 100644
--- a/tests/src/rules/no-unused-modules.js
+++ b/tests/src/rules/no-unused-modules.js
@@ -4,8 +4,8 @@ import typescriptConfig from '../../../config/typescript';
 
 import { RuleTester } from 'eslint';
 import fs from 'fs';
-import semver from 'semver';
 import eslintPkg from 'eslint/package.json';
+import semver from 'semver';
 
 // TODO: figure out why these tests fail in eslint 4
 const isESLint4TODO = semver.satisfies(eslintPkg.version, '^4');
@@ -108,34 +108,50 @@ ruleTester.run('no-unused-modules', rule, {
 // tests for  exports
 ruleTester.run('no-unused-modules', rule, {
   valid: [
-
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: 'import { o2 } from "./file-o";export default () => 12',
-      filename: testFilePath('./no-unused-modules/file-a.js') }),
-    test({ options: unusedExportsOptions,
+      filename: testFilePath('./no-unused-modules/file-a.js'),
+    }),
+    test({
+      options: unusedExportsOptions,
       code: 'export const b = 2',
-      filename: testFilePath('./no-unused-modules/file-b.js') }),
-    test({ options: unusedExportsOptions,
+      filename: testFilePath('./no-unused-modules/file-b.js'),
+    }),
+    test({
+      options: unusedExportsOptions,
       code: 'const c1 = 3; function c2() { return 3 }; export { c1, c2 }',
-      filename: testFilePath('./no-unused-modules/file-c.js') }),
-    test({ options: unusedExportsOptions,
+      filename: testFilePath('./no-unused-modules/file-c.js'),
+    }),
+    test({
+      options: unusedExportsOptions,
       code: 'export function d() { return 4 }',
-      filename: testFilePath('./no-unused-modules/file-d.js') }),
-    test({ options: unusedExportsOptions,
+      filename: testFilePath('./no-unused-modules/file-d.js'),
+    }),
+    test({
+      options: unusedExportsOptions,
       code: 'export class q { q0() {} }',
-      filename: testFilePath('./no-unused-modules/file-q.js') }),
-    test({ options: unusedExportsOptions,
+      filename: testFilePath('./no-unused-modules/file-q.js'),
+    }),
+    test({
+      options: unusedExportsOptions,
       code: 'const e0 = 5; export { e0 as e }',
-      filename: testFilePath('./no-unused-modules/file-e.js') }),
-    test({ options: unusedExportsOptions,
+      filename: testFilePath('./no-unused-modules/file-e.js'),
+    }),
+    test({
+      options: unusedExportsOptions,
       code: 'const l0 = 5; const l = 10; export { l0 as l1, l }; export default () => {}',
-      filename: testFilePath('./no-unused-modules/file-l.js') }),
-    test({ options: unusedExportsOptions,
+      filename: testFilePath('./no-unused-modules/file-l.js'),
+    }),
+    test({
+      options: unusedExportsOptions,
       code: 'const o0 = 0; const o1 = 1; export { o0, o1 as o2 }; export default () => {}',
-      filename: testFilePath('./no-unused-modules/file-o.js') }),
+      filename: testFilePath('./no-unused-modules/file-o.js'),
+    }),
   ],
   invalid: [
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: `import eslint from 'eslint'
            import fileA from './file-a'
            import { b } from './file-b'
@@ -155,11 +171,14 @@ ruleTester.run('no-unused-modules', rule, {
         error(`exported declaration 'o0' not used within other modules`),
         error(`exported declaration 'o3' not used within other modules`),
         error(`exported declaration 'p' not used within other modules`),
-      ] }),
-    test({ options: unusedExportsOptions,
+      ],
+    }),
+    test({
+      options: unusedExportsOptions,
       code: `const n0 = 'n0'; const n1 = 42; export { n0, n1 }; export default () => {}`,
       filename: testFilePath('./no-unused-modules/file-n.js'),
-      errors: [error(`exported declaration 'default' not used within other modules`)] }),
+      errors: [error(`exported declaration 'default' not used within other modules`)],
+    }),
   ],
 });
 
@@ -167,60 +186,80 @@ ruleTester.run('no-unused-modules', rule, {
 ruleTester.run('no-unused-modules', rule, {
   valid: [],
   invalid: [
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: 'export default () => 13',
       filename: testFilePath('./no-unused-modules/file-f.js'),
-      errors: [error(`exported declaration 'default' not used within other modules`)] }),
-    test({ options: unusedExportsOptions,
+      errors: [error(`exported declaration 'default' not used within other modules`)],
+    }),
+    test({
+      options: unusedExportsOptions,
       code: 'export const g = 2',
       filename: testFilePath('./no-unused-modules/file-g.js'),
-      errors: [error(`exported declaration 'g' not used within other modules`)] }),
-    test({ options: unusedExportsOptions,
+      errors: [error(`exported declaration 'g' not used within other modules`)],
+    }),
+    test({
+      options: unusedExportsOptions,
       code: 'const h1 = 3; function h2() { return 3 }; const h3 = true; export { h1, h2, h3 }',
       filename: testFilePath('./no-unused-modules/file-h.js'),
-      errors: [error(`exported declaration 'h1' not used within other modules`)] }),
-    test({ options: unusedExportsOptions,
+      errors: [error(`exported declaration 'h1' not used within other modules`)],
+    }),
+    test({
+      options: unusedExportsOptions,
       code: 'const i1 = 3; function i2() { return 3 }; export { i1, i2 }',
       filename: testFilePath('./no-unused-modules/file-i.js'),
       errors: [
         error(`exported declaration 'i1' not used within other modules`),
         error(`exported declaration 'i2' not used within other modules`),
-      ] }),
-    test({ options: unusedExportsOptions,
+      ],
+    }),
+    test({
+      options: unusedExportsOptions,
       code: 'export function j() { return 4 }',
       filename: testFilePath('./no-unused-modules/file-j.js'),
-      errors: [error(`exported declaration 'j' not used within other modules`)] }),
-    test({ options: unusedExportsOptions,
+      errors: [error(`exported declaration 'j' not used within other modules`)],
+    }),
+    test({
+      options: unusedExportsOptions,
       code: 'export class q { q0() {} }',
       filename: testFilePath('./no-unused-modules/file-q.js'),
-      errors: [error(`exported declaration 'q' not used within other modules`)] }),
-    test({ options: unusedExportsOptions,
+      errors: [error(`exported declaration 'q' not used within other modules`)],
+    }),
+    test({
+      options: unusedExportsOptions,
       code: 'const k0 = 5; export { k0 as k }',
       filename: testFilePath('./no-unused-modules/file-k.js'),
-      errors: [error(`exported declaration 'k' not used within other modules`)] }),
+      errors: [error(`exported declaration 'k' not used within other modules`)],
+    }),
   ],
 });
 
-// // test for export from
+// test for export from
 ruleTester.run('no-unused-modules', rule, {
   valid: [
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: `export { default } from './file-o'`,
-      filename: testFilePath('./no-unused-modules/file-s.js') }),
+      filename: testFilePath('./no-unused-modules/file-s.js'),
+    }),
   ],
   invalid: [
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: `export { k } from '${testFilePath('./no-unused-modules/file-k.js')}'`,
       filename: testFilePath('./no-unused-modules/file-j.js'),
-      errors: [error(`exported declaration 'k' not used within other modules`)] }),
+      errors: [error(`exported declaration 'k' not used within other modules`)],
+    }),
   ],
 });
 
 ruleTester.run('no-unused-modules', rule, {
   valid: [
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: 'const k0 = 5; export { k0 as k }',
-      filename: testFilePath('./no-unused-modules/file-k.js') }),
+      filename: testFilePath('./no-unused-modules/file-k.js'),
+    }),
   ],
   invalid: [],
 });
@@ -228,24 +267,36 @@ ruleTester.run('no-unused-modules', rule, {
 // test for ignored files
 ruleTester.run('no-unused-modules', rule, {
   valid: [
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: 'export default () => 14',
-      filename: testFilePath('./no-unused-modules/file-ignored-a.js') }),
-    test({ options: unusedExportsOptions,
+      filename: testFilePath('./no-unused-modules/file-ignored-a.js'),
+    }),
+    test({
+      options: unusedExportsOptions,
       code: 'export const b = 2',
-      filename: testFilePath('./no-unused-modules/file-ignored-b.js') }),
-    test({ options: unusedExportsOptions,
+      filename: testFilePath('./no-unused-modules/file-ignored-b.js'),
+    }),
+    test({
+      options: unusedExportsOptions,
       code: 'const c1 = 3; function c2() { return 3 }; export { c1, c2 }',
-      filename: testFilePath('./no-unused-modules/file-ignored-c.js') }),
-    test({ options: unusedExportsOptions,
+      filename: testFilePath('./no-unused-modules/file-ignored-c.js'),
+    }),
+    test({
+      options: unusedExportsOptions,
       code: 'export function d() { return 4 }',
-      filename: testFilePath('./no-unused-modules/file-ignored-d.js') }),
-    test({ options: unusedExportsOptions,
+      filename: testFilePath('./no-unused-modules/file-ignored-d.js'),
+    }),
+    test({
+      options: unusedExportsOptions,
       code: 'const f = 5; export { f as e }',
-      filename: testFilePath('./no-unused-modules/file-ignored-e.js') }),
-    test({ options: unusedExportsOptions,
+      filename: testFilePath('./no-unused-modules/file-ignored-e.js'),
+    }),
+    test({
+      options: unusedExportsOptions,
       code: 'const l0 = 5; const l = 10; export { l0 as l1, l }; export default () => {}',
-      filename: testFilePath('./no-unused-modules/file-ignored-l.js') }),
+      filename: testFilePath('./no-unused-modules/file-ignored-l.js'),
+    }),
   ],
   invalid: [],
 });
@@ -253,27 +304,35 @@ ruleTester.run('no-unused-modules', rule, {
 // add named import for file with default export
 ruleTester.run('no-unused-modules', rule, {
   valid: [
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: `import { f } from '${testFilePath('./no-unused-modules/file-f.js')}'`,
-      filename: testFilePath('./no-unused-modules/file-0.js') }),
+      filename: testFilePath('./no-unused-modules/file-0.js'),
+    }),
   ],
   invalid: [
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: 'export default () => 15',
       filename: testFilePath('./no-unused-modules/file-f.js'),
-      errors: [error(`exported declaration 'default' not used within other modules`)] }),
+      errors: [error(`exported declaration 'default' not used within other modules`)],
+    }),
   ],
 });
 
 // add default import for file with default export
 ruleTester.run('no-unused-modules', rule, {
   valid: [
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: `import f from '${testFilePath('./no-unused-modules/file-f.js')}'`,
-      filename: testFilePath('./no-unused-modules/file-0.js') }),
-    test({ options: unusedExportsOptions,
+      filename: testFilePath('./no-unused-modules/file-0.js'),
+    }),
+    test({
+      options: unusedExportsOptions,
       code: 'export default () => 16',
-      filename: testFilePath('./no-unused-modules/file-f.js') }),
+      filename: testFilePath('./no-unused-modules/file-f.js'),
+    }),
   ],
   invalid: [],
 });
@@ -281,26 +340,34 @@ ruleTester.run('no-unused-modules', rule, {
 // add default import for file with named export
 ruleTester.run('no-unused-modules', rule, {
   valid: [
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: `import g from '${testFilePath('./no-unused-modules/file-g.js')}';import {h} from '${testFilePath('./no-unused-modules/file-gg.js')}'`,
-      filename: testFilePath('./no-unused-modules/file-0.js') }),
+      filename: testFilePath('./no-unused-modules/file-0.js'),
+    }),
   ],
   invalid: [
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: 'export const g = 2',
       filename: testFilePath('./no-unused-modules/file-g.js'),
-      errors: [error(`exported declaration 'g' not used within other modules`)] })],
+      errors: [error(`exported declaration 'g' not used within other modules`)],
+    })],
 });
 
 // add named import for file with named export
 ruleTester.run('no-unused-modules', rule, {
   valid: [
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: `import { g } from '${testFilePath('./no-unused-modules/file-g.js')}'; import eslint from 'eslint'`,
-      filename: testFilePath('./no-unused-modules/file-0.js') }),
-    test({ options: unusedExportsOptions,
+      filename: testFilePath('./no-unused-modules/file-0.js'),
+    }),
+    test({
+      options: unusedExportsOptions,
       code: 'export const g = 2',
-      filename: testFilePath('./no-unused-modules/file-g.js') }),
+      filename: testFilePath('./no-unused-modules/file-g.js'),
+    }),
   ],
   invalid: [],
 });
@@ -308,27 +375,35 @@ ruleTester.run('no-unused-modules', rule, {
 // add different named import for file with named export
 ruleTester.run('no-unused-modules', rule, {
   valid: [
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: `import { c } from '${testFilePath('./no-unused-modules/file-b.js')}'`,
-      filename: testFilePath('./no-unused-modules/file-0.js') }),
+      filename: testFilePath('./no-unused-modules/file-0.js'),
+    }),
   ],
   invalid: [
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: 'export const b = 2',
       filename: testFilePath('./no-unused-modules/file-b.js'),
-      errors: [error(`exported declaration 'b' not used within other modules`)] }),
+      errors: [error(`exported declaration 'b' not used within other modules`)],
+    }),
   ],
 });
 
 // add renamed named import for file with named export
 ruleTester.run('no-unused-modules', rule, {
   valid: [
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: `import { g as g1 } from '${testFilePath('./no-unused-modules/file-g.js')}'; import eslint from 'eslint'`,
-      filename: testFilePath('./no-unused-modules/file-0.js') }),
-    test({ options: unusedExportsOptions,
+      filename: testFilePath('./no-unused-modules/file-0.js'),
+    }),
+    test({
+      options: unusedExportsOptions,
       code: 'export const g = 2',
-      filename: testFilePath('./no-unused-modules/file-g.js') }),
+      filename: testFilePath('./no-unused-modules/file-g.js'),
+    }),
   ],
   invalid: [],
 });
@@ -336,30 +411,38 @@ ruleTester.run('no-unused-modules', rule, {
 // add different renamed named import for file with named export
 ruleTester.run('no-unused-modules', rule, {
   valid: [
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: `import { g1 as g } from '${testFilePath('./no-unused-modules/file-g.js')}'`,
-      filename: testFilePath('./no-unused-modules/file-0.js') }),
+      filename: testFilePath('./no-unused-modules/file-0.js'),
+    }),
   ],
   invalid: [
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: 'export const g = 2',
       filename: testFilePath('./no-unused-modules/file-g.js'),
-      errors: [error(`exported declaration 'g' not used within other modules`)] }),
+      errors: [error(`exported declaration 'g' not used within other modules`)],
+    }),
   ],
 });
 
 // remove default import for file with default export
 ruleTester.run('no-unused-modules', rule, {
   valid: [
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: `import { a1, a2 } from '${testFilePath('./no-unused-modules/file-a.js')}'`,
-      filename: testFilePath('./no-unused-modules/file-0.js') }),
+      filename: testFilePath('./no-unused-modules/file-0.js'),
+    }),
   ],
   invalid: [
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: 'export default () => 17',
       filename: testFilePath('./no-unused-modules/file-a.js'),
-      errors: [error(`exported declaration 'default' not used within other modules`)] }),
+      errors: [error(`exported declaration 'default' not used within other modules`)],
+    }),
   ],
 });
 
@@ -367,24 +450,30 @@ ruleTester.run('no-unused-modules', rule, {
 ruleTester.run('no-unused-modules', rule, {
   valid: [],
   invalid: [
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: 'const m0 = 5; const m = 10; export { m0 as m1, m }; export default () => {}',
       filename: testFilePath('./no-unused-modules/file-m.js'),
       errors: [
         error(`exported declaration 'm1' not used within other modules`),
         error(`exported declaration 'm' not used within other modules`),
         error(`exported declaration 'default' not used within other modules`),
-      ] }),
+      ],
+    }),
   ],
 });
 ruleTester.run('no-unused-modules', rule, {
   valid: [
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: `import * as m from '${testFilePath('./no-unused-modules/file-m.js')}'; import unknown from 'unknown-module'`,
-      filename: testFilePath('./no-unused-modules/file-0.js') }),
-    test({ options: unusedExportsOptions,
+      filename: testFilePath('./no-unused-modules/file-0.js'),
+    }),
+    test({
+      options: unusedExportsOptions,
       code: 'const m0 = 5; const m = 10; export { m0 as m1, m }; export default () => {}',
-      filename: testFilePath('./no-unused-modules/file-m.js') }),
+      filename: testFilePath('./no-unused-modules/file-m.js'),
+    }),
   ],
   invalid: [],
 });
@@ -392,82 +481,103 @@ ruleTester.run('no-unused-modules', rule, {
 // remove all exports
 ruleTester.run('no-unused-modules', rule, {
   valid: [
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: `/* import * as m from '${testFilePath('./no-unused-modules/file-m.js')}' */`,
-      filename: testFilePath('./no-unused-modules/file-0.js') }),
+      filename: testFilePath('./no-unused-modules/file-0.js'),
+    }),
   ],
   invalid: [
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: 'const m0 = 5; const m = 10; export { m0 as m1, m }; export default () => {}',
       filename: testFilePath('./no-unused-modules/file-m.js'),
       errors: [
         error(`exported declaration 'm1' not used within other modules`),
         error(`exported declaration 'm' not used within other modules`),
         error(`exported declaration 'default' not used within other modules`),
-      ] }),
+      ],
+    }),
   ],
 });
 
 ruleTester.run('no-unused-modules', rule, {
   valid: [
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: `export * from '${testFilePath('./no-unused-modules/file-m.js')}';`,
-      filename: testFilePath('./no-unused-modules/file-0.js') }),
+      filename: testFilePath('./no-unused-modules/file-0.js'),
+    }),
   ],
   invalid: [],
 });
 ruleTester.run('no-unused-modules', rule, {
   valid: [],
   invalid: [
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: 'const m0 = 5; const m = 10; export { m0 as m1, m }; export default () => {}',
       filename: testFilePath('./no-unused-modules/file-m.js'),
-      errors: [error(`exported declaration 'default' not used within other modules`)] }),
+      errors: [error(`exported declaration 'default' not used within other modules`)],
+    }),
   ],
 });
 
 ruleTester.run('no-unused-modules', rule, {
   valid: [],
   invalid: [
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: `export { m1, m} from '${testFilePath('./no-unused-modules/file-m.js')}';`,
       filename: testFilePath('./no-unused-modules/file-0.js'),
       errors: [
         error(`exported declaration 'm1' not used within other modules`),
         error(`exported declaration 'm' not used within other modules`),
-      ] }),
-    test({ options: unusedExportsOptions,
+      ],
+    }),
+    test({
+      options: unusedExportsOptions,
       code: 'const m0 = 5; const m = 10; export { m0 as m1, m }; export default () => {}',
       filename: testFilePath('./no-unused-modules/file-m.js'),
-      errors: [error(`exported declaration 'default' not used within other modules`)] }),
+      errors: [error(`exported declaration 'default' not used within other modules`)],
+    }),
   ],
 });
 
 ruleTester.run('no-unused-modules', rule, {
   valid: [
-    // test({ options: unusedExportsOptions,
-    //        code: `export { default, m1 } from '${testFilePath('./no-unused-modules/file-m.js')}';`,
-    //        filename: testFilePath('./no-unused-modules/file-0.js')}),
+    /* TODO:
+    test({
+      options: unusedExportsOptions,
+      code: `export { default, m1 } from '${testFilePath('./no-unused-modules/file-m.js')}';`,
+      filename: testFilePath('./no-unused-modules/file-0.js')
+    }),
+    */
   ],
   invalid: [
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: `export { default, m1 } from '${testFilePath('./no-unused-modules/file-m.js')}';`,
       filename: testFilePath('./no-unused-modules/file-0.js'),
       errors: [
         error(`exported declaration 'default' not used within other modules`),
         error(`exported declaration 'm1' not used within other modules`),
-      ] }),
-    test({ options: unusedExportsOptions,
+      ],
+    }),
+    test({
+      options: unusedExportsOptions,
       code: 'const m0 = 5; const m = 10; export { m0 as m1, m }; export default () => {}',
       filename: testFilePath('./no-unused-modules/file-m.js'),
-      errors: [error(`exported declaration 'm' not used within other modules`)] }),
+      errors: [error(`exported declaration 'm' not used within other modules`)],
+    }),
   ],
 });
 
 // Test that import and export in the same file both counts as usage
 ruleTester.run('no-unused-modules', rule, {
   valid: [
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: `export const a = 5;export const b = 't1'`,
       filename: testFilePath('./no-unused-modules/import-export-1.js'),
     }),
@@ -478,23 +588,31 @@ ruleTester.run('no-unused-modules', rule, {
 describe('renameDefault', () => {
   ruleTester.run('no-unused-modules', rule, {
     valid: [
-      test({ options: unusedExportsOptions,
+      test({
+        options: unusedExportsOptions,
         code: 'export { default as Component } from "./Component"',
-        filename: testFilePath('./no-unused-modules/renameDefault/components.js') }),
-      test({ options: unusedExportsOptions,
+        filename: testFilePath('./no-unused-modules/renameDefault/components.js'),
+      }),
+      test({
+        options: unusedExportsOptions,
         code: 'export default function Component() {}',
-        filename: testFilePath('./no-unused-modules/renameDefault/Component.js') }),
+        filename: testFilePath('./no-unused-modules/renameDefault/Component.js'),
+      }),
     ],
     invalid: [],
   });
   ruleTester.run('no-unused-modules', rule, {
     valid: [
-      test({ options: unusedExportsOptions,
+      test({
+        options: unusedExportsOptions,
         code: 'export { default as ComponentA } from "./ComponentA";export { default as ComponentB } from "./ComponentB";',
-        filename: testFilePath('./no-unused-modules/renameDefault-2/components.js') }),
-      test({ options: unusedExportsOptions,
+        filename: testFilePath('./no-unused-modules/renameDefault-2/components.js'),
+      }),
+      test({
+        options: unusedExportsOptions,
         code: 'export default function ComponentA() {};',
-        filename: testFilePath('./no-unused-modules/renameDefault-2/ComponentA.js') }),
+        filename: testFilePath('./no-unused-modules/renameDefault-2/ComponentA.js'),
+      }),
     ],
     invalid: [],
   });
@@ -508,12 +626,16 @@ describe('test behavior for new file', () => {
   // add import in newly created file
   ruleTester.run('no-unused-modules', rule, {
     valid: [
-      test({ options: unusedExportsOptions,
+      test({
+        options: unusedExportsOptions,
         code: `import * as m from '${testFilePath('./no-unused-modules/file-m.js')}'`,
-        filename: testFilePath('./no-unused-modules/file-added-0.js') }),
-      test({ options: unusedExportsOptions,
+        filename: testFilePath('./no-unused-modules/file-added-0.js'),
+      }),
+      test({
+        options: unusedExportsOptions,
         code: 'const m0 = 5; const m = 10; export { m0 as m1, m }; export default () => {}',
-        filename: testFilePath('./no-unused-modules/file-m.js') }),
+        filename: testFilePath('./no-unused-modules/file-m.js'),
+      }),
     ],
     invalid: [],
   });
@@ -522,21 +644,27 @@ describe('test behavior for new file', () => {
   ruleTester.run('no-unused-modules', rule, {
     valid: [],
     invalid: [
-      test({ options: unusedExportsOptions,
+      test({
+        options: unusedExportsOptions,
         code: `export default () => {2}`,
         filename: testFilePath('./no-unused-modules/file-added-0.js'),
-        errors: [error(`exported declaration 'default' not used within other modules`)] }),
+        errors: [error(`exported declaration 'default' not used within other modules`)],
+      }),
     ],
   });
 
   ruleTester.run('no-unused-modules', rule, {
     valid: [
-      test({ options: unusedExportsOptions,
+      test({
+        options: unusedExportsOptions,
         code: `import def from '${testFilePath('./no-unused-modules/file-added-0.js')}'`,
-        filename: testFilePath('./no-unused-modules/file-0.js') }),
-      test({ options: unusedExportsOptions,
+        filename: testFilePath('./no-unused-modules/file-0.js'),
+      }),
+      test({
+        options: unusedExportsOptions,
         code: `export default () => {}`,
-        filename: testFilePath('./no-unused-modules/file-added-0.js') }),
+        filename: testFilePath('./no-unused-modules/file-added-0.js'),
+      }),
     ],
     invalid: [],
   });
@@ -544,27 +672,34 @@ describe('test behavior for new file', () => {
   // export * only considers named imports. default imports still need to be reported
   ruleTester.run('no-unused-modules', rule, {
     valid: [
-      test({ options: unusedExportsOptions,
+      test({
+        options: unusedExportsOptions,
         code: `export * from '${testFilePath('./no-unused-modules/file-added-0.js')}'`,
-        filename: testFilePath('./no-unused-modules/file-0.js') }),
+        filename: testFilePath('./no-unused-modules/file-0.js'),
+      }),
       // Test export * from 'external-compiled-library'
-      test({ options: unusedExportsOptions,
+      test({
+        options: unusedExportsOptions,
         code: `export * from 'external-compiled-library'`,
         filename: testFilePath('./no-unused-modules/file-r.js'),
       }),
     ],
     invalid: [
-      test({ options: unusedExportsOptions,
+      test({
+        options: unusedExportsOptions,
         code: `export const z = 'z';export default () => {}`,
         filename: testFilePath('./no-unused-modules/file-added-0.js'),
-        errors: [error(`exported declaration 'default' not used within other modules`)] }),
+        errors: [error(`exported declaration 'default' not used within other modules`)],
+      }),
     ],
   });
   ruleTester.run('no-unused-modules', rule, {
     valid: [
-      test({ options: unusedExportsOptions,
+      test({
+        options: unusedExportsOptions,
         code: `export const a = 2`,
-        filename: testFilePath('./no-unused-modules/file-added-0.js') }),
+        filename: testFilePath('./no-unused-modules/file-added-0.js'),
+      }),
     ],
     invalid: [],
   });
@@ -573,17 +708,21 @@ describe('test behavior for new file', () => {
   ruleTester.run('no-unused-modules', rule, {
     valid: [],
     invalid: [
-      test({ options: unusedExportsOptions,
+      test({
+        options: unusedExportsOptions,
         code: `export { a } from '${testFilePath('./no-unused-modules/file-added-0.js')}'`,
         filename: testFilePath('./no-unused-modules/file-0.js'),
-        errors: [error(`exported declaration 'a' not used within other modules`)] }),
-      test({ options: unusedExportsOptions,
+        errors: [error(`exported declaration 'a' not used within other modules`)],
+      }),
+      test({
+        options: unusedExportsOptions,
         code: `export const z = 'z';export default () => {}`,
         filename: testFilePath('./no-unused-modules/file-added-0.js'),
         errors: [
           error(`exported declaration 'z' not used within other modules`),
           error(`exported declaration 'default' not used within other modules`),
-        ] }),
+        ],
+      }),
     ],
   });
 
@@ -594,15 +733,19 @@ describe('test behavior for new file', () => {
     });
     ruleTester.run('no-unused-modules', rule, {
       valid: [
-        test({ options: unusedExportsOptions,
+        test({
+          options: unusedExportsOptions,
           code: `export * from '${testFilePath('./no-unused-modules/file-added-1.js')}'`,
-          filename: testFilePath('./no-unused-modules/file-0.js') }),
+          filename: testFilePath('./no-unused-modules/file-0.js'),
+        }),
       ],
       invalid: [
-        test({ options: unusedExportsOptions,
+        test({
+          options: unusedExportsOptions,
           code: `export const z = 'z';export default () => {}`,
           filename: testFilePath('./no-unused-modules/file-added-1.js'),
-          errors: [error(`exported declaration 'default' not used within other modules`)] }),
+          errors: [error(`exported declaration 'default' not used within other modules`)],
+        }),
       ],
     });
     after(() => {
@@ -625,12 +768,16 @@ describe('test behavior for new file', () => {
   });
   ruleTester.run('no-unused-modules', rule, {
     valid: [
-      test({ options: unusedExportsOptions,
+      test({
+        options: unusedExportsOptions,
         code: `import added from '${testFilePath('./no-unused-modules/file-added-2.js')}'`,
-        filename: testFilePath('./no-unused-modules/file-added-1.js') }),
-      test({ options: unusedExportsOptions,
+        filename: testFilePath('./no-unused-modules/file-added-1.js'),
+      }),
+      test({
+        options: unusedExportsOptions,
         code: `export default () => {}`,
-        filename: testFilePath('./no-unused-modules/file-added-2.js') }),
+        filename: testFilePath('./no-unused-modules/file-added-2.js'),
+      }),
     ],
     invalid: [],
   });
@@ -647,12 +794,16 @@ describe('test behavior for new file', () => {
   });
   ruleTester.run('no-unused-modules', rule, {
     valid: [
-      test({ options: unusedExportsOptions,
+      test({
+        options: unusedExportsOptions,
         code: `import { added } from '${testFilePath('./no-unused-modules/file-added-3.js')}'`,
-        filename: testFilePath('./no-unused-modules/file-added-1.js') }),
-      test({ options: unusedExportsOptions,
+        filename: testFilePath('./no-unused-modules/file-added-1.js'),
+      }),
+      test({
+        options: unusedExportsOptions,
         code: `export const added = () => {}`,
-        filename: testFilePath('./no-unused-modules/file-added-3.js') }),
+        filename: testFilePath('./no-unused-modules/file-added-3.js'),
+      }),
     ],
     invalid: [],
   });
@@ -666,18 +817,24 @@ describe('test behavior for new file', () => {
 describe('test behavior for destructured exports', () => {
   ruleTester.run('no-unused-modules', rule, {
     valid: [
-      test({ options: unusedExportsOptions,
+      test({
+        options: unusedExportsOptions,
         code: `import { destructured } from '${testFilePath('./no-unused-modules/file-destructured-1.js')}'`,
-        filename: testFilePath('./no-unused-modules/file-destructured-2.js') }),
-      test({ options: unusedExportsOptions,
+        filename: testFilePath('./no-unused-modules/file-destructured-2.js'),
+      }),
+      test({
+        options: unusedExportsOptions,
         code: `export const { destructured } = {};`,
-        filename: testFilePath('./no-unused-modules/file-destructured-1.js') }),
+        filename: testFilePath('./no-unused-modules/file-destructured-1.js'),
+      }),
     ],
     invalid: [
-      test({ options: unusedExportsOptions,
+      test({
+        options: unusedExportsOptions,
         code: `export const { destructured2 } = {};`,
         filename: testFilePath('./no-unused-modules/file-destructured-1.js'),
-        errors: [`exported declaration 'destructured2' not used within other modules`] }),
+        errors: [`exported declaration 'destructured2' not used within other modules`],
+      }),
     ],
   });
 });
@@ -688,12 +845,16 @@ describe('test behavior for new file', () => {
   });
   ruleTester.run('no-unused-modules', rule, {
     valid: [
-      test({ options: unusedExportsOptions,
+      test({
+        options: unusedExportsOptions,
         code: `import * as added from '${testFilePath('./no-unused-modules/file-added-4.js.js')}'`,
-        filename: testFilePath('./no-unused-modules/file-added-1.js') }),
-      test({ options: unusedExportsOptions,
+        filename: testFilePath('./no-unused-modules/file-added-1.js'),
+      }),
+      test({
+        options: unusedExportsOptions,
         code: `export const added = () => {}; export default () => {}`,
-        filename: testFilePath('./no-unused-modules/file-added-4.js.js') }),
+        filename: testFilePath('./no-unused-modules/file-added-4.js.js'),
+      }),
     ],
     invalid: [],
   });
@@ -707,13 +868,15 @@ describe('test behavior for new file', () => {
 describe('do not report missing export for ignored file', () => {
   ruleTester.run('no-unused-modules', rule, {
     valid: [
-      test({ options: [{
-        src: [testFilePath('./no-unused-modules/**/*.js')],
-        ignoreExports: [testFilePath('./no-unused-modules/*ignored*.js')],
-        missingExports: true,
-      }],
-      code: 'export const test = true',
-      filename: testFilePath('./no-unused-modules/file-ignored-a.js') }),
+      test({
+        options: [{
+          src: [testFilePath('./no-unused-modules/**/*.js')],
+          ignoreExports: [testFilePath('./no-unused-modules/*ignored*.js')],
+          missingExports: true,
+        }],
+        code: 'export const test = true',
+        filename: testFilePath('./no-unused-modules/file-ignored-a.js'),
+      }),
     ],
     invalid: [],
   });
@@ -722,9 +885,11 @@ describe('do not report missing export for ignored file', () => {
 // lint file not available in `src`
 ruleTester.run('no-unused-modules', rule, {
   valid: [
-    test({ options: unusedExportsOptions,
+    test({
+      options: unusedExportsOptions,
       code: `export const jsxFoo = 'foo'; export const jsxBar = 'bar'`,
-      filename: testFilePath('../jsx/named.jsx') }),
+      filename: testFilePath('../jsx/named.jsx'),
+    }),
   ],
   invalid: [],
 });
@@ -732,27 +897,39 @@ ruleTester.run('no-unused-modules', rule, {
 describe('do not report unused export for files mentioned in package.json', () => {
   ruleTester.run('no-unused-modules', rule, {
     valid: [
-      test({ options: unusedExportsOptions,
+      test({
+        options: unusedExportsOptions,
         code: 'export const bin = "bin"',
-        filename: testFilePath('./no-unused-modules/bin.js') }),
-      test({ options: unusedExportsOptions,
+        filename: testFilePath('./no-unused-modules/bin.js'),
+      }),
+      test({
+        options: unusedExportsOptions,
         code: 'export const binObject = "binObject"',
-        filename: testFilePath('./no-unused-modules/binObject/index.js') }),
-      test({ options: unusedExportsOptions,
+        filename: testFilePath('./no-unused-modules/binObject/index.js'),
+      }),
+      test({
+        options: unusedExportsOptions,
         code: 'export const browser = "browser"',
-        filename: testFilePath('./no-unused-modules/browser.js') }),
-      test({ options: unusedExportsOptions,
+        filename: testFilePath('./no-unused-modules/browser.js'),
+      }),
+      test({
+        options: unusedExportsOptions,
         code: 'export const browserObject = "browserObject"',
-        filename: testFilePath('./no-unused-modules/browserObject/index.js') }),
-      test({ options: unusedExportsOptions,
+        filename: testFilePath('./no-unused-modules/browserObject/index.js'),
+      }),
+      test({
+        options: unusedExportsOptions,
         code: 'export const main = "main"',
-        filename: testFilePath('./no-unused-modules/main/index.js') }),
+        filename: testFilePath('./no-unused-modules/main/index.js'),
+      }),
     ],
     invalid: [
-      test({ options: unusedExportsOptions,
+      test({
+        options: unusedExportsOptions,
         code: 'export const privatePkg = "privatePkg"',
         filename: testFilePath('./no-unused-modules/privatePkg/index.js'),
-        errors: [error(`exported declaration 'privatePkg' not used within other modules`)] }),
+        errors: [error(`exported declaration 'privatePkg' not used within other modules`)],
+      }),
     ],
   });
 });
@@ -760,9 +937,11 @@ describe('do not report unused export for files mentioned in package.json', () =
 describe('Avoid errors if re-export all from umd compiled library', () => {
   ruleTester.run('no-unused-modules', rule, {
     valid: [
-      test({ options: unusedExportsOptions,
+      test({
+        options: unusedExportsOptions,
         code: `export * from '${testFilePath('./no-unused-modules/bin.js')}'`,
-        filename: testFilePath('./no-unused-modules/main/index.js') }),
+        filename: testFilePath('./no-unused-modules/main/index.js'),
+      }),
     ],
     invalid: [],
   });
diff --git a/tests/src/rules/no-useless-path-segments.js b/tests/src/rules/no-useless-path-segments.js
index 313424d3..21d9a5f7 100644
--- a/tests/src/rules/no-useless-path-segments.js
+++ b/tests/src/rules/no-useless-path-segments.js
@@ -32,7 +32,7 @@ function runResolverTests(resolver) {
         parser: require.resolve('babel-eslint') }),
       test({ code: 'import("..")',
         parser: require.resolve('babel-eslint') }),
-      test({ code: 'import("fs").then(function(fs){})',
+      test({ code: 'import("fs").then(function(fs) {})',
         parser: require.resolve('babel-eslint') }),
     ],
 
diff --git a/tests/src/rules/order.js b/tests/src/rules/order.js
index e7e6b056..61bf1bb7 100644
--- a/tests/src/rules/order.js
+++ b/tests/src/rules/order.js
@@ -2286,7 +2286,7 @@ context('TypeScript', function () {
     .filter((parser) => parser !== require.resolve('typescript-eslint-parser'))
     .forEach((parser) => {
       const parserConfig = {
-        parser: parser,
+        parser,
         settings: {
           'import/parsers': { [parser]: ['.ts'] },
           'import/resolver': { 'eslint-import-resolver-typescript': true },
@@ -2298,352 +2298,316 @@ context('TypeScript', function () {
           // #1667: typescript type import support
 
           // Option alphabetize: {order: 'asc'}
-          test(
-            {
-              code: `
-                import c from 'Bar';
-                import type { C } from 'Bar';
-                import b from 'bar';
-                import a from 'foo';
-                import type { A } from 'foo';
-
-                import index from './';
-              `,
-              parser,
-              options: [
-                {
-                  groups: ['external', 'index'],
-                  alphabetize: { order: 'asc' },
-                },
-              ],
-            },
-            parserConfig,
-          ),
+          test({
+            code: `
+              import c from 'Bar';
+              import type { C } from 'Bar';
+              import b from 'bar';
+              import a from 'foo';
+              import type { A } from 'foo';
+
+              import index from './';
+            `,
+            ...parserConfig,
+            options: [
+              {
+                groups: ['external', 'index'],
+                alphabetize: { order: 'asc' },
+              },
+            ],
+          }),
           // Option alphabetize: {order: 'desc'}
-          test(
-            {
-              code: `
-                import a from 'foo';
-                import type { A } from 'foo';
-                import b from 'bar';
-                import c from 'Bar';
-                import type { C } from 'Bar';
-
-                import index from './';
-              `,
-              parser,
-              options: [
-                {
-                  groups: ['external', 'index'],
-                  alphabetize: { order: 'desc' },
-                },
-              ],
-            },
-            parserConfig,
-          ),
+          test({
+            code: `
+              import a from 'foo';
+              import type { A } from 'foo';
+              import b from 'bar';
+              import c from 'Bar';
+              import type { C } from 'Bar';
+
+              import index from './';
+            `,
+            ...parserConfig,
+            options: [
+              {
+                groups: ['external', 'index'],
+                alphabetize: { order: 'desc' },
+              },
+            ],
+          }),
           // Option alphabetize: {order: 'asc'} with type group
-          test(
-            {
-              code: `
-                import c from 'Bar';
-                import b from 'bar';
-                import a from 'foo';
-
-                import index from './';
-
-                import type { C } from 'Bar';
-                import type { A } from 'foo';
-              `,
-              parser,
-              options: [
-                {
-                  groups: ['external', 'index', 'type'],
-                  alphabetize: { order: 'asc' },
-                },
-              ],
-            },
-            parserConfig,
-          ),
+          test({
+            code: `
+              import c from 'Bar';
+              import b from 'bar';
+              import a from 'foo';
+
+              import index from './';
+
+              import type { C } from 'Bar';
+              import type { A } from 'foo';
+            `,
+            ...parserConfig,
+            options: [
+              {
+                groups: ['external', 'index', 'type'],
+                alphabetize: { order: 'asc' },
+              },
+            ],
+          }),
           // Option alphabetize: {order: 'asc'} with type group & path group
-          test(
-            {
-              // only: true,
-              code: `
-                import c from 'Bar';
-                import a from 'foo';
-
-                import b from 'dirA/bar';
-
-                import index from './';
-
-                import type { C } from 'dirA/Bar';
-                import type { A } from 'foo';
-              `,
-              parser,
-              options: [
-                {
-                  alphabetize: { order: 'asc' },
-                  groups: ['external', 'internal', 'index', 'type'],
-                  pathGroups: [
-                    {
-                      pattern: 'dirA/**',
-                      group: 'internal',
-                    },
-                  ],
-                  'newlines-between': 'always',
-                  pathGroupsExcludedImportTypes: ['type'],
-                },
-              ],
-            },
-            parserConfig,
-          ),
+          test({
+            // only: true,
+            code: `
+              import c from 'Bar';
+              import a from 'foo';
+
+              import b from 'dirA/bar';
+
+              import index from './';
+
+              import type { C } from 'dirA/Bar';
+              import type { A } from 'foo';
+            `,
+            ...parserConfig,
+            options: [
+              {
+                alphabetize: { order: 'asc' },
+                groups: ['external', 'internal', 'index', 'type'],
+                pathGroups: [
+                  {
+                    pattern: 'dirA/**',
+                    group: 'internal',
+                  },
+                ],
+                'newlines-between': 'always',
+                pathGroupsExcludedImportTypes: ['type'],
+              },
+            ],
+          }),
           // Option alphabetize: {order: 'asc'} with path group
-          test(
-            {
-              // only: true,
-              code: `
-                import c from 'Bar';
-                import type { A } from 'foo';
-                import a from 'foo';
-
-                import type { C } from 'dirA/Bar';
-                import b from 'dirA/bar';
-
-                import index from './';
-              `,
-              parser,
-              options: [
-                {
-                  alphabetize: { order: 'asc' },
-                  groups: ['external', 'internal', 'index'],
-                  pathGroups: [
-                    {
-                      pattern: 'dirA/**',
-                      group: 'internal',
-                    },
-                  ],
-                  'newlines-between': 'always',
-                  pathGroupsExcludedImportTypes: [],
-                },
-              ],
-            },
-            parserConfig,
-          ),
+          test({
+            // only: true,
+            code: `
+              import c from 'Bar';
+              import type { A } from 'foo';
+              import a from 'foo';
+
+              import type { C } from 'dirA/Bar';
+              import b from 'dirA/bar';
+
+              import index from './';
+            `,
+            ...parserConfig,
+            options: [
+              {
+                alphabetize: { order: 'asc' },
+                groups: ['external', 'internal', 'index'],
+                pathGroups: [
+                  {
+                    pattern: 'dirA/**',
+                    group: 'internal',
+                  },
+                ],
+                'newlines-between': 'always',
+                pathGroupsExcludedImportTypes: [],
+              },
+            ],
+          }),
           // Option alphabetize: {order: 'desc'} with type group
-          test(
-            {
-              code: `
-                import a from 'foo';
-                import b from 'bar';
-                import c from 'Bar';
-
-                import index from './';
-
-                import type { A } from 'foo';
-                import type { C } from 'Bar';
-              `,
-              parser,
-              options: [
-                {
-                  groups: ['external', 'index', 'type'],
-                  alphabetize: { order: 'desc' },
-                },
-              ],
-            },
-            parserConfig,
-          ),
-          test(
-            {
-              code: `
-                import { Partner } from '@models/partner/partner';
-                import { PartnerId } from '@models/partner/partner-id';
-              `,
-              parser,
-              options: [
-                {
-                  alphabetize: { order: 'asc' },
-                },
-              ],
-            },
-            parserConfig,
-          ),
-          test(
-            {
-              code: `
-                import { serialize, parse, mapFieldErrors } from '@vtaits/form-schema';
-                import type { GetFieldSchema } from '@vtaits/form-schema';
-                import { useMemo, useCallback } from 'react';
-                import type { ReactElement, ReactNode } from 'react';
-                import { Form } from 'react-final-form';
-                import type { FormProps as FinalFormProps } from 'react-final-form';
-              `,
-              parser,
-              options: [
-                {
-                  alphabetize: { order: 'asc' },
-                },
-              ],
-            },
-            parserConfig,
-          ),
+          test({
+            code: `
+              import a from 'foo';
+              import b from 'bar';
+              import c from 'Bar';
+
+              import index from './';
+
+              import type { A } from 'foo';
+              import type { C } from 'Bar';
+            `,
+            ...parserConfig,
+            options: [
+              {
+                groups: ['external', 'index', 'type'],
+                alphabetize: { order: 'desc' },
+              },
+            ],
+          }),
+          test({
+            code: `
+              import { Partner } from '@models/partner/partner';
+              import { PartnerId } from '@models/partner/partner-id';
+            `,
+            ...parserConfig,
+            options: [
+              {
+                alphabetize: { order: 'asc' },
+              },
+            ],
+          }),
+          test({
+            code: `
+              import { serialize, parse, mapFieldErrors } from '@vtaits/form-schema';
+              import type { GetFieldSchema } from '@vtaits/form-schema';
+              import { useMemo, useCallback } from 'react';
+              import type { ReactElement, ReactNode } from 'react';
+              import { Form } from 'react-final-form';
+              import type { FormProps as FinalFormProps } from 'react-final-form';
+            `,
+            ...parserConfig,
+            options: [
+              {
+                alphabetize: { order: 'asc' },
+              },
+            ],
+          }),
         ],
         invalid: [
           // Option alphabetize: {order: 'asc'}
-          test(
-            {
-              code: `
-                import b from 'bar';
-                import c from 'Bar';
-                import type { C } from 'Bar';
-                import a from 'foo';
-                import type { A } from 'foo';
-
-                import index from './';
-              `,
-              output: `
-                import c from 'Bar';
-                import type { C } from 'Bar';
-                import b from 'bar';
-                import a from 'foo';
-                import type { A } from 'foo';
-
-                import index from './';
-              `,
-              parser,
-              options: [
-                {
-                  groups: ['external', 'index'],
-                  alphabetize: { order: 'asc' },
-                },
-              ],
-              errors: [
-                {
-                  message: semver.satisfies(eslintPkg.version, '< 3')
-                    ? '`bar` import should occur after import of `Bar`'
-                    : /(`bar` import should occur after import of `Bar`)|(`Bar` import should occur before import of `bar`)/,
-                },
-              ],
-            },
-            parserConfig,
-          ),
+          test({
+            code: `
+              import b from 'bar';
+              import c from 'Bar';
+              import type { C } from 'Bar';
+              import a from 'foo';
+              import type { A } from 'foo';
+
+              import index from './';
+            `,
+            output: `
+              import c from 'Bar';
+              import type { C } from 'Bar';
+              import b from 'bar';
+              import a from 'foo';
+              import type { A } from 'foo';
+
+              import index from './';
+            `,
+            ...parserConfig,
+            options: [
+              {
+                groups: ['external', 'index'],
+                alphabetize: { order: 'asc' },
+              },
+            ],
+            errors: [
+              {
+                message: semver.satisfies(eslintPkg.version, '< 3')
+                  ? '`bar` import should occur after import of `Bar`'
+                  : /(`bar` import should occur after import of `Bar`)|(`Bar` import should occur before import of `bar`)/,
+              },
+            ],
+          }),
           // Option alphabetize: {order: 'desc'}
-          test(
-            {
-              code: `
-                import a from 'foo';
-                import type { A } from 'foo';
-                import c from 'Bar';
-                import type { C } from 'Bar';
-                import b from 'bar';
-
-                import index from './';
-              `,
-              output: `
-                import a from 'foo';
-                import type { A } from 'foo';
-                import b from 'bar';
-                import c from 'Bar';
-                import type { C } from 'Bar';
-
-                import index from './';
-              `,
-              parser,
-              options: [
-                {
-                  groups: ['external', 'index'],
-                  alphabetize: { order: 'desc' },
-                },
-              ],
-              errors: [
-                {
-                  message: semver.satisfies(eslintPkg.version, '< 3')
-                    ? '`bar` import should occur before import of `Bar`'
-                    : /(`bar` import should occur before import of `Bar`)|(`Bar` import should occur after import of `bar`)/,
-                },
-              ],
-            },
-            parserConfig,
-          ),
+          test({
+            code: `
+              import a from 'foo';
+              import type { A } from 'foo';
+              import c from 'Bar';
+              import type { C } from 'Bar';
+              import b from 'bar';
+
+              import index from './';
+            `,
+            output: `
+              import a from 'foo';
+              import type { A } from 'foo';
+              import b from 'bar';
+              import c from 'Bar';
+              import type { C } from 'Bar';
+
+              import index from './';
+            `,
+            ...parserConfig,
+            options: [
+              {
+                groups: ['external', 'index'],
+                alphabetize: { order: 'desc' },
+              },
+            ],
+            errors: [
+              {
+                message: semver.satisfies(eslintPkg.version, '< 3')
+                  ? '`bar` import should occur before import of `Bar`'
+                  : /(`bar` import should occur before import of `Bar`)|(`Bar` import should occur after import of `bar`)/,
+              },
+            ],
+          }),
           // Option alphabetize: {order: 'asc'} with type group
-          test(
-            {
-              code: `
-                import b from 'bar';
-                import c from 'Bar';
-                import a from 'foo';
-
-                import index from './';
-
-                import type { A } from 'foo';
-                import type { C } from 'Bar';
-              `,
-              output: `
-                import c from 'Bar';
-                import b from 'bar';
-                import a from 'foo';
-
-                import index from './';
-
-                import type { C } from 'Bar';
-                import type { A } from 'foo';
-              `,
-              parser,
-              options: [
-                {
-                  groups: ['external', 'index', 'type'],
-                  alphabetize: { order: 'asc' },
-                },
-              ],
-              errors: semver.satisfies(eslintPkg.version, '< 3') ? [
-                { message: '`Bar` import should occur before import of `bar`' },
-                { message: '`Bar` import should occur before import of `foo`' },
-              ] : [
-                { message: /(`Bar` import should occur before import of `bar`)|(`bar` import should occur after import of `Bar`)/ },
-                { message: /(`Bar` import should occur before import of `foo`)|(`foo` import should occur after import of `Bar`)/ },
-              ],
-            },
-            parserConfig,
-          ),
+          test({
+            code: `
+              import b from 'bar';
+              import c from 'Bar';
+              import a from 'foo';
+
+              import index from './';
+
+              import type { A } from 'foo';
+              import type { C } from 'Bar';
+            `,
+            output: `
+              import c from 'Bar';
+              import b from 'bar';
+              import a from 'foo';
+
+              import index from './';
+
+              import type { C } from 'Bar';
+              import type { A } from 'foo';
+            `,
+            ...parserConfig,
+            options: [
+              {
+                groups: ['external', 'index', 'type'],
+                alphabetize: { order: 'asc' },
+              },
+            ],
+            errors: semver.satisfies(eslintPkg.version, '< 3') ? [
+              { message: '`Bar` import should occur before import of `bar`' },
+              { message: '`Bar` import should occur before import of `foo`' },
+            ] : [
+              { message: /(`Bar` import should occur before import of `bar`)|(`bar` import should occur after import of `Bar`)/ },
+              { message: /(`Bar` import should occur before import of `foo`)|(`foo` import should occur after import of `Bar`)/ },
+            ],
+          }),
           // Option alphabetize: {order: 'desc'} with type group
-          test(
-            {
-              code: `
-                import a from 'foo';
-                import c from 'Bar';
-                import b from 'bar';
-
-                import index from './';
-
-                import type { C } from 'Bar';
-                import type { A } from 'foo';
-              `,
-              output: `
-                import a from 'foo';
-                import b from 'bar';
-                import c from 'Bar';
-
-                import index from './';
-
-                import type { A } from 'foo';
-                import type { C } from 'Bar';
-              `,
-              parser,
-              options: [
-                {
-                  groups: ['external', 'index', 'type'],
-                  alphabetize: { order: 'desc' },
-                },
-              ],
-              errors: semver.satisfies(eslintPkg.version, '< 3') ? [
-                { message: '`bar` import should occur before import of `Bar`' },
-                { message: '`foo` import should occur before import of `Bar`' },
-              ] : [
-                { message: /(`bar` import should occur before import of `Bar`)|(`Bar` import should occur after import of `bar`)/ },
-                { message: /(`foo` import should occur before import of `Bar`)|(`Bar` import should occur after import of `foo`)/ },
-              ],
-            },
-            parserConfig,
-          ),
+          test({
+            code: `
+              import a from 'foo';
+              import c from 'Bar';
+              import b from 'bar';
+
+              import index from './';
+
+              import type { C } from 'Bar';
+              import type { A } from 'foo';
+            `,
+            output: `
+              import a from 'foo';
+              import b from 'bar';
+              import c from 'Bar';
+
+              import index from './';
+
+              import type { A } from 'foo';
+              import type { C } from 'Bar';
+            `,
+            ...parserConfig,
+            options: [
+              {
+                groups: ['external', 'index', 'type'],
+                alphabetize: { order: 'desc' },
+              },
+            ],
+            errors: semver.satisfies(eslintPkg.version, '< 3') ? [
+              { message: '`bar` import should occur before import of `Bar`' },
+              { message: '`foo` import should occur before import of `Bar`' },
+            ] : [
+              { message: /(`bar` import should occur before import of `Bar`)|(`Bar` import should occur after import of `bar`)/ },
+              { message: /(`foo` import should occur before import of `Bar`)|(`Bar` import should occur after import of `foo`)/ },
+            ],
+          }),
           // warns for out of order unassigned imports (warnOnUnassignedImports enabled)
           test({
             code: `
diff --git a/tests/src/rules/prefer-default-export.js b/tests/src/rules/prefer-default-export.js
index 4efa47f5..34323fe5 100644
--- a/tests/src/rules/prefer-default-export.js
+++ b/tests/src/rules/prefer-default-export.js
@@ -151,7 +151,7 @@ ruleTester.run('prefer-default-export', rule, {
 context('TypeScript', function() {
   getNonDefaultParsers().forEach((parser) => {
     const parserConfig = {
-      parser: parser,
+      parser,
       settings: {
         'import/parsers': { [parser]: ['.ts'] },
         'import/resolver': { 'eslint-import-resolver-typescript': true },
@@ -161,52 +161,34 @@ context('TypeScript', function() {
     ruleTester.run('prefer-default-export', rule, {
       valid: [
         // Exporting types
-        test(
-          {
-            code: `
-        export type foo = string;
-        export type bar = number;`,
-            parser,
-          },
-          parserConfig,
-        ),
-        test(
-          {
-            code: `
-        export type foo = string;
-        export type bar = number;`,
-            parser,
-          },
-          parserConfig,
-        ),
-        test(
-          {
-            code: 'export type foo = string',
-            parser,
-          },
-          parserConfig,
-        ),
-        test(
-          {
-            code: 'export type foo = string',
-            parser,
-          },
-          parserConfig,
-        ),
-        test(
-          {
-            code: 'export interface foo { bar: string; }',
-            parser,
-          },
-          parserConfig,
-        ),
-        test(
-          {
-            code: 'export interface foo { bar: string; }; export function goo() {}',
-            parser,
-          },
-          parserConfig,
-        ),
+        test({
+          code: `
+          export type foo = string;
+          export type bar = number;`,
+          ...parserConfig,
+        }),
+        test({
+          code: `
+          export type foo = string;
+          export type bar = number;`,
+          ...parserConfig,
+        }),
+        test({
+          code: 'export type foo = string',
+          ...parserConfig,
+        }),
+        test({
+          code: 'export type foo = string',
+          ...parserConfig,
+        }),
+        test({
+          code: 'export interface foo { bar: string; }',
+          ...parserConfig,
+        }),
+        test({
+          code: 'export interface foo { bar: string; }; export function goo() {}',
+          ...parserConfig,
+        }),
       ],
       invalid: [],
     });
diff --git a/tests/src/utils.js b/tests/src/utils.js
index a76826de..e805e954 100644
--- a/tests/src/utils.js
+++ b/tests/src/utils.js
@@ -32,6 +32,9 @@ export function testVersion(specifier, t) {
 }
 
 export function test(t) {
+  if (arguments.length !== 1) {
+    throw new SyntaxError('`test` requires exactly one object argument');
+  }
   return Object.assign({
     filename: FILENAME,
   }, t, {