Skip to content

Commit a943fd0

Browse files
Michael Hayesljharb
Michael Hayes
authored andcommitted
[New] order: Add warnOnUnassignedImports option to enable warnings for out of order unassigned imports
Fixes #1639
1 parent ad2a619 commit a943fd0

File tree

4 files changed

+136
-7
lines changed

4 files changed

+136
-7
lines changed

Diff for: CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
1313
- add [`no-import-module-exports`] rule: report import declarations with CommonJS exports ([#804], thanks [@kentcdodds] and [@ttmarek])
1414
- [`no-unused-modules`]: Support destructuring assignment for `export`. ([#1997], thanks [@s-h-a-d-o-w])
1515
- [`order`]: support type imports ([#2021], thanks [@grit96])
16+
- [`order`]: Add `warnOnUnassignedImports` option to enable warnings for out of order unassigned imports ([#1990], thanks [@hayes])
1617

1718
### Fixed
1819
- [`export`]/TypeScript: properly detect export specifiers as children of a TS module block ([#1889], thanks [@andreubotella])
@@ -773,6 +774,7 @@ for info on changes for earlier releases.
773774
[#2012]: https://github.com/benmosher/eslint-plugin-import/pull/2012
774775
[#1997]: https://github.com/benmosher/eslint-plugin-import/pull/1997
775776
[#1993]: https://github.com/benmosher/eslint-plugin-import/pull/1993
777+
[#1990]: https://github.com/benmosher/eslint-plugin-import/pull/1990
776778
[#1985]: https://github.com/benmosher/eslint-plugin-import/pull/1985
777779
[#1983]: https://github.com/benmosher/eslint-plugin-import/pull/1983
778780
[#1974]: https://github.com/benmosher/eslint-plugin-import/pull/1974
@@ -1363,3 +1365,4 @@ for info on changes for earlier releases.
13631365
[@silviogutierrez]: https://github.com/silviogutierrez
13641366
[@aladdin-add]: https://github.com/aladdin-add
13651367
[@davidbonnet]: https://github.com/davidbonnet
1368+
[@hayes]: https://github.com/hayes

Diff for: docs/rules/order.md

+27
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,33 @@ import React, { PureComponent } from 'react';
256256
import { compose, apply } from 'xcompose';
257257
```
258258

259+
### `warnOnUnassignedImports: true|false`:
260+
261+
* default: `false`
262+
263+
Warns when unassigned imports are out of order. These warning will not be fixed
264+
with `--fix` because unassigned imports are used for side-effects and changing the
265+
import of order of modules with side effects can not be done automatically in a
266+
way that is safe.
267+
268+
This will fail the rule check:
269+
270+
```js
271+
/* eslint import/order: ["error", {"warnOnUnassignedImports": true}] */
272+
import fs from 'fs';
273+
import './styles.css';
274+
import path from 'path';
275+
```
276+
277+
While this will pass:
278+
279+
```js
280+
/* eslint import/order: ["error", {"warnOnUnassignedImports": true}] */
281+
import fs from 'fs';
282+
import path from 'path';
283+
import './styles.css';
284+
```
285+
259286
## Related
260287

261288
- [`import/external-module-folders`] setting

Diff for: src/rules/order.js

+8-3
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ function isModuleLevelRequire(node) {
339339
let n = node;
340340
// Handle cases like `const baz = require('foo').bar.baz`
341341
// and `const foo = require('foo')()`
342-
while (
342+
while (
343343
(n.parent.type === 'MemberExpression' && n.parent.object === n) ||
344344
(n.parent.type === 'CallExpression' && n.parent.callee === n)
345345
) {
@@ -348,7 +348,7 @@ function isModuleLevelRequire(node) {
348348
return (
349349
n.parent.type === 'VariableDeclarator' &&
350350
n.parent.parent.type === 'VariableDeclaration' &&
351-
n.parent.parent.parent.type === 'Program'
351+
n.parent.parent.parent.type === 'Program'
352352
);
353353
}
354354

@@ -568,6 +568,10 @@ module.exports = {
568568
},
569569
additionalProperties: false,
570570
},
571+
warnOnUnassignedImports: {
572+
type: 'boolean',
573+
default: false,
574+
},
571575
},
572576
additionalProperties: false,
573577
},
@@ -600,7 +604,8 @@ module.exports = {
600604

601605
return {
602606
ImportDeclaration: function handleImports(node) {
603-
if (node.specifiers.length) { // Ignoring unassigned imports
607+
// Ignoring unassigned imports unless warnOnUnassignedImports is set
608+
if (node.specifiers.length || options.warnOnUnassignedImports) {
604609
const name = node.source.value;
605610
registerNode(
606611
context,

Diff for: tests/src/rules/order.js

+98-4
Original file line numberDiff line numberDiff line change
@@ -854,10 +854,10 @@ ruleTester.run('order', rule, {
854854
test({
855855
code:
856856
`/* comment0 */ /* comment1 */ var async = require('async'); /* comment2 */` + `\r\n` +
857-
`/* comment3 */ var fs = require('fs'); /* comment4 */` + `\r\n`,
857+
`/* comment3 */ var fs = require('fs'); /* comment4 */` + `\r\n`,
858858
output:
859859
`/* comment3 */ var fs = require('fs'); /* comment4 */` + `\r\n` +
860-
`/* comment0 */ /* comment1 */ var async = require('async'); /* comment2 */` + `\r\n`,
860+
`/* comment0 */ /* comment1 */ var async = require('async'); /* comment2 */` + `\r\n`,
861861
errors: [{
862862
message: '`fs` import should occur before import of `async`',
863863
}],
@@ -1530,7 +1530,8 @@ ruleTester.run('order', rule, {
15301530
},
15311531
],
15321532
}),
1533-
// Option newlines-between: 'never' cannot fix if there are other statements between imports
1533+
// Option newlines-between: 'never' with unassigned imports and warnOnUnassignedImports disabled
1534+
// newline is preserved to match existing behavior
15341535
test({
15351536
code: `
15361537
import path from 'path';
@@ -1546,6 +1547,53 @@ ruleTester.run('order', rule, {
15461547
import 'something-else';
15471548
import _ from 'lodash';
15481549
`,
1550+
options: [{ 'newlines-between': 'never', warnOnUnassignedImports: false }],
1551+
errors: [
1552+
{
1553+
line: 2,
1554+
message: 'There should be no empty line between import groups',
1555+
},
1556+
],
1557+
}),
1558+
// Option newlines-between: 'never' with unassigned imports and warnOnUnassignedImports enabled
1559+
test({
1560+
code: `
1561+
import path from 'path';
1562+
import 'loud-rejection';
1563+
1564+
import 'something-else';
1565+
import _ from 'lodash';
1566+
`,
1567+
output: `
1568+
import path from 'path';
1569+
import 'loud-rejection';
1570+
import 'something-else';
1571+
import _ from 'lodash';
1572+
`,
1573+
options: [{ 'newlines-between': 'never', warnOnUnassignedImports: true }],
1574+
errors: [
1575+
{
1576+
line: 3,
1577+
message: 'There should be no empty line between import groups',
1578+
},
1579+
],
1580+
}),
1581+
// Option newlines-between: 'never' cannot fix if there are other statements between imports
1582+
test({
1583+
code: `
1584+
import path from 'path';
1585+
export const abc = 123;
1586+
1587+
import 'something-else';
1588+
import _ from 'lodash';
1589+
`,
1590+
output: `
1591+
import path from 'path';
1592+
export const abc = 123;
1593+
1594+
import 'something-else';
1595+
import _ from 'lodash';
1596+
`,
15491597
options: [{ 'newlines-between': 'never' }],
15501598
errors: [
15511599
{
@@ -1764,7 +1812,6 @@ ruleTester.run('order', rule, {
17641812
'`./local2` import should occur after import of `global4`',
17651813
],
17661814
}),
1767-
17681815
// pathGroup with position 'after'
17691816
test({
17701817
code: `
@@ -2309,6 +2356,53 @@ context('TypeScript', function () {
23092356
},
23102357
parserConfig,
23112358
),
2359+
// warns for out of order unassigned imports (warnOnUnassignedImports enabled)
2360+
test({
2361+
code: `
2362+
import './local1';
2363+
import global from 'global1';
2364+
import local from './local2';
2365+
import 'global2';
2366+
`,
2367+
output: `
2368+
import './local1';
2369+
import global from 'global1';
2370+
import local from './local2';
2371+
import 'global2';
2372+
`,
2373+
errors: [
2374+
{
2375+
message: '`global1` import should occur before import of `./local1`',
2376+
},
2377+
{
2378+
message: '`global2` import should occur before import of `./local1`',
2379+
},
2380+
],
2381+
options: [{ warnOnUnassignedImports: true }],
2382+
}),
2383+
// fix cannot move below unassigned import (warnOnUnassignedImports enabled)
2384+
test({
2385+
code: `
2386+
import local from './local';
2387+
2388+
import 'global1';
2389+
2390+
import global2 from 'global2';
2391+
import global3 from 'global3';
2392+
`,
2393+
output: `
2394+
import local from './local';
2395+
2396+
import 'global1';
2397+
2398+
import global2 from 'global2';
2399+
import global3 from 'global3';
2400+
`,
2401+
errors: [{
2402+
message: '`./local` import should occur after import of `global3`',
2403+
}],
2404+
options: [{ warnOnUnassignedImports: true }],
2405+
}),
23122406
],
23132407
});
23142408
});

0 commit comments

Comments
 (0)