Skip to content

Commit 4bdf61a

Browse files
yesl-kimljharb
authored andcommitted
[Fix] no-duplicates: Removing duplicates breaks in TypeScript
Fixes #3016. Fixes #2792.
1 parent 98a0991 commit 4bdf61a

File tree

3 files changed

+35
-2
lines changed

3 files changed

+35
-2
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
1414
### Fixed
1515
- [`no-extraneous-dependencies`]: allow wrong path ([#3012], thanks [@chabb])
1616
- [`no-cycle`]: use scc algorithm to optimize ([#2998], thanks [@soryy708])
17+
- [`no-duplicates`]: Removing duplicates breaks in TypeScript ([#3033], thanks [@yesl-kim])
1718

1819
### Changed
1920
- [Docs] `no-extraneous-dependencies`: Make glob pattern description more explicit ([#2944], thanks [@mulztob])
@@ -1121,6 +1122,7 @@ for info on changes for earlier releases.
11211122

11221123
[`memo-parser`]: ./memo-parser/README.md
11231124

1125+
[#3033]: https://github.com/import-js/eslint-plugin-import/pull/3033
11241126
[#3012]: https://github.com/import-js/eslint-plugin-import/pull/3012
11251127
[#3011]: https://github.com/import-js/eslint-plugin-import/pull/3011
11261128
[#3004]: https://github.com/import-js/eslint-plugin-import/pull/3004
@@ -1962,6 +1964,7 @@ for info on changes for earlier releases.
19621964
[@wtgtybhertgeghgtwtg]: https://github.com/wtgtybhertgeghgtwtg
19631965
[@xM8WVqaG]: https://github.com/xM8WVqaG
19641966
[@xpl]: https://github.com/xpl
1967+
[@yesl-kim]: https://github.com/yesl-kim
19651968
[@yndajas]: https://github.com/yndajas
19661969
[@yordis]: https://github.com/yordis
19671970
[@Zamiell]: https://github.com/Zamiell

src/rules/no-duplicates.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ function getFix(first, rest, sourceCode, context) {
132132
const shouldAddDefault = getDefaultImportName(first) == null && defaultImportNames.size === 1;
133133
const shouldAddSpecifiers = specifiers.length > 0;
134134
const shouldRemoveUnnecessary = unnecessaryImports.length > 0;
135+
const preferInline = context.options[0] && context.options[0]['prefer-inline'];
135136

136137
if (!(shouldAddDefault || shouldAddSpecifiers || shouldRemoveUnnecessary)) {
137138
return undefined;
@@ -157,8 +158,7 @@ function getFix(first, rest, sourceCode, context) {
157158
([result, needsComma, existingIdentifiers], specifier) => {
158159
const isTypeSpecifier = specifier.importNode.importKind === 'type';
159160

160-
const preferInline = context.options[0] && context.options[0]['prefer-inline'];
161-
// a user might set prefer-inline but not have a supporting TypeScript version. Flow does not support inline types so this should fail in that case as well.
161+
// a user might set prefer-inline but not have a supporting TypeScript version. Flow does not support inline types so this should fail in that case as well.
162162
if (preferInline && (!typescriptPkg || !semver.satisfies(typescriptPkg.version, '>= 4.5'))) {
163163
throw new Error('Your version of TypeScript does not support inline type imports.');
164164
}
@@ -186,6 +186,18 @@ function getFix(first, rest, sourceCode, context) {
186186

187187
const fixes = [];
188188

189+
if (shouldAddSpecifiers && preferInline && first.importKind === 'type') {
190+
// `import type {a} from './foo'` → `import {type a} from './foo'`
191+
const typeIdentifierToken = tokens.find((token) => token.type === 'Identifier' && token.value === 'type');
192+
fixes.push(fixer.removeRange([typeIdentifierToken.range[0], typeIdentifierToken.range[1] + 1]));
193+
194+
tokens
195+
.filter((token) => firstExistingIdentifiers.has(token.value))
196+
.forEach((identifier) => {
197+
fixes.push(fixer.replaceTextRange([identifier.range[0], identifier.range[1]], `type ${identifier.value}`));
198+
});
199+
}
200+
189201
if (shouldAddDefault && openBrace == null && shouldAddSpecifiers) {
190202
// `import './foo'` → `import def, {...} from './foo'`
191203
fixes.push(

tests/src/rules/no-duplicates.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,24 @@ context('TypeScript', function () {
704704
},
705705
],
706706
}),
707+
test({
708+
code: "import type {x} from 'foo'; import {type y} from 'foo'",
709+
...parserConfig,
710+
options: [{ 'prefer-inline': true }],
711+
output: `import {type x,type y} from 'foo'; `,
712+
errors: [
713+
{
714+
line: 1,
715+
column: 22,
716+
message: "'foo' imported multiple times.",
717+
},
718+
{
719+
line: 1,
720+
column: 50,
721+
message: "'foo' imported multiple times.",
722+
},
723+
],
724+
}),
707725
test({
708726
code: "import {type x} from 'foo'; import type {y} from 'foo'",
709727
...parserConfig,

0 commit comments

Comments
 (0)