Skip to content

Commit 2035355

Browse files
committed
[Fix] no-empty-named-blocks: rewrite rule to only check import declarations
Fixes #2666
1 parent eee88e4 commit 2035355

File tree

3 files changed

+88
-51
lines changed

3 files changed

+88
-51
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
66

77
## [Unreleased]
88

9+
### Fixed
10+
- [`no-empty-named-blocks`]: rewrite rule to only check import declarations ([#2666])
11+
912
## [2.27.2] - 2023-01-11
1013

1114
### Fixed
@@ -1366,6 +1369,7 @@ for info on changes for earlier releases.
13661369
[#211]: https://github.com/import-js/eslint-plugin-import/pull/211
13671370
[#164]: https://github.com/import-js/eslint-plugin-import/pull/164
13681371
[#157]: https://github.com/import-js/eslint-plugin-import/pull/157
1372+
[#2666]: https://github.com/import-js/eslint-plugin-import/issues/2666
13691373
[#2665]: https://github.com/import-js/eslint-plugin-import/issues/2665
13701374
[#2444]: https://github.com/import-js/eslint-plugin-import/issues/2444
13711375
[#2412]: https://github.com/import-js/eslint-plugin-import/issues/2412

src/rules/no-empty-named-blocks.js

+63-48
Original file line numberDiff line numberDiff line change
@@ -29,63 +29,78 @@ module.exports = {
2929
},
3030

3131
create(context) {
32+
const importsWithoutNameds = [];
33+
3234
return {
33-
Program(node) {
34-
node.tokens.forEach((token, idx) => {
35-
const nextToken = node.tokens[idx + 1];
35+
ImportDeclaration(node) {
36+
if (!node.specifiers.some(x => x.type === 'ImportSpecifier')) {
37+
importsWithoutNameds.push(node);
38+
}
39+
},
40+
41+
'Program:exit': function (program) {
42+
const importsTokens = importsWithoutNameds.map((node) => {
43+
return [node, program.tokens.filter(x => x.range[0] >= node.range[0] && x.range[1] <= node.range[1])];
44+
});
45+
46+
importsTokens.forEach(([node, tokens]) => {
47+
tokens.forEach((token) => {
48+
const idx = program.tokens.indexOf(token);
49+
const nextToken = program.tokens[idx + 1];
3650

37-
if (nextToken && token.value === '{' && nextToken.value === '}') {
38-
const hasOtherIdentifiers = node.tokens.some((token) => (
39-
token.type === 'Identifier'
40-
&& token.value !== 'from'
41-
&& token.value !== 'type'
42-
&& token.value !== 'typeof'
43-
));
51+
if (nextToken && token.value === '{' && nextToken.value === '}') {
52+
const hasOtherIdentifiers = tokens.some((token) => (
53+
token.type === 'Identifier'
54+
&& token.value !== 'from'
55+
&& token.value !== 'type'
56+
&& token.value !== 'typeof'
57+
));
4458

45-
// If it has no other identifiers it's the only thing in the import, so we can either remove the import
46-
// completely or transform it in a side-effects only import
47-
if (!hasOtherIdentifiers) {
48-
context.report({
49-
node,
50-
message: 'Unexpected empty named import block',
51-
suggest: [
52-
{
53-
desc: 'Remove unused import',
54-
fix(fixer) {
55-
// Remove the whole import
56-
return fixer.remove(node);
59+
// If it has no other identifiers it's the only thing in the import, so we can either remove the import
60+
// completely or transform it in a side-effects only import
61+
if (!hasOtherIdentifiers) {
62+
context.report({
63+
node,
64+
message: 'Unexpected empty named import block',
65+
suggest: [
66+
{
67+
desc: 'Remove unused import',
68+
fix(fixer) {
69+
// Remove the whole import
70+
return fixer.remove(node);
71+
},
5772
},
58-
},
59-
{
60-
desc: 'Remove empty import block',
61-
fix(fixer) {
62-
// Remove the empty block and the 'from' token, leaving the import only for its side
63-
// effects, e.g. `import 'mod'`
64-
const sourceCode = context.getSourceCode();
65-
const fromToken = node.tokens.find(t => t.value === 'from');
66-
const importToken = node.tokens.find(t => t.value === 'import');
67-
const hasSpaceAfterFrom = sourceCode.isSpaceBetween(fromToken, sourceCode.getTokenAfter(fromToken));
68-
const hasSpaceAfterImport = sourceCode.isSpaceBetween(importToken, sourceCode.getTokenAfter(fromToken));
73+
{
74+
desc: 'Remove empty import block',
75+
fix(fixer) {
76+
// Remove the empty block and the 'from' token, leaving the import only for its side
77+
// effects, e.g. `import 'mod'`
78+
const sourceCode = context.getSourceCode();
79+
const fromToken = program.tokens.find(t => t.value === 'from');
80+
const importToken = program.tokens.find(t => t.value === 'import');
81+
const hasSpaceAfterFrom = sourceCode.isSpaceBetween(fromToken, sourceCode.getTokenAfter(fromToken));
82+
const hasSpaceAfterImport = sourceCode.isSpaceBetween(importToken, sourceCode.getTokenAfter(fromToken));
6983

70-
const [start] = getEmptyBlockRange(node.tokens, idx);
71-
const [, end] = fromToken.range;
72-
const range = [start, hasSpaceAfterFrom ? end + 1 : end];
84+
const [start] = getEmptyBlockRange(program.tokens, idx);
85+
const [, end] = fromToken.range;
86+
const range = [start, hasSpaceAfterFrom ? end + 1 : end];
7387

74-
return fixer.replaceTextRange(range, hasSpaceAfterImport ? '' : ' ');
88+
return fixer.replaceTextRange(range, hasSpaceAfterImport ? '' : ' ');
89+
},
7590
},
91+
],
92+
});
93+
} else {
94+
context.report({
95+
node,
96+
message: 'Unexpected empty named import block',
97+
fix(fixer) {
98+
return fixer.removeRange(getEmptyBlockRange(program.tokens, idx));
7699
},
77-
],
78-
});
79-
} else {
80-
context.report({
81-
node,
82-
message: 'Unexpected empty named import block',
83-
fix(fixer) {
84-
return fixer.removeRange(getEmptyBlockRange(node.tokens, idx));
85-
},
86-
});
100+
});
101+
}
87102
}
88-
}
103+
});
89104
});
90105
},
91106
};

tests/src/rules/no-empty-named-blocks.js

+21-3
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,27 @@ ruleTester.run('no-empty-named-blocks', rule, {
4242
] : [],
4343

4444
// Flow
45-
test({ code: `import typeof Default from 'mod';`, parser: parsers.BABEL_OLD }),
46-
test({ code: `import typeof { Named } from 'mod';`, parser: parsers.BABEL_OLD }),
47-
test({ code: `import typeof Default, { Named } from 'mod';`, parser: parsers.BABEL_OLD }),
45+
test({ code: `import typeof Default from 'mod'; // babel old`, parser: parsers.BABEL_OLD }),
46+
test({ code: `import typeof { Named } from 'mod'; // babel old`, parser: parsers.BABEL_OLD }),
47+
test({ code: `import typeof Default, { Named } from 'mod'; // babel old`, parser: parsers.BABEL_OLD }),
48+
test({
49+
code: `
50+
module.exports = {
51+
rules: {
52+
'keyword-spacing': ['error', {overrides: {}}],
53+
}
54+
};
55+
`,
56+
}),
57+
test({
58+
code: `
59+
import { DESCRIPTORS, NODE } from '../helpers/constants';
60+
// ...
61+
import { timeLimitedPromise } from '../helpers/helpers';
62+
// ...
63+
import { DESCRIPTORS2 } from '../helpers/constants';
64+
`,
65+
}),
4866
),
4967
invalid: [].concat(
5068
test({

0 commit comments

Comments
 (0)