Skip to content

Commit

Permalink
[New] no-duplicates: support inline type import with `inlineTypeImp…
Browse files Browse the repository at this point in the history
…ort` option
  • Loading branch information
snewcomer committed Jun 10, 2022
1 parent 3767479 commit 457c167
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 7 deletions.
4 changes: 2 additions & 2 deletions package.json
Expand Up @@ -72,7 +72,7 @@
"escope": "^3.6.0",
"eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8",
"eslint-import-resolver-node": "file:./resolvers/node",
"eslint-import-resolver-typescript": "^1.0.2 || ^1.1.1",
"eslint-import-resolver-typescript": "^1.0.2 || ^2.7.0",
"eslint-import-resolver-webpack": "file:./resolvers/webpack",
"eslint-import-test-order-redirect": "file:./tests/files/order-redirect",
"eslint-module-utils": "file:./utils",
Expand All @@ -92,7 +92,7 @@
"safe-publish-latest": "^2.0.0",
"semver": "^6.3.0",
"sinon": "^2.4.1",
"typescript": "^2.8.1 || ~3.9.5",
"typescript": "^2.8.1 || ^3.9.5 || ~4.7.3",
"typescript-eslint-parser": "^15 || ^20 || ^22"
},
"peerDependencies": {
Expand Down
20 changes: 16 additions & 4 deletions src/rules/no-duplicates.js
Expand Up @@ -7,7 +7,7 @@ function checkImports(imported, context) {
const message = `'${module}' imported multiple times.`;
const [first, ...rest] = nodes;
const sourceCode = context.getSourceCode();
const fix = getFix(first, rest, sourceCode);
const fix = getFix(first, rest, sourceCode, context);

context.report({
node: first.source,
Expand All @@ -25,7 +25,7 @@ function checkImports(imported, context) {
}
}

function getFix(first, rest, sourceCode) {
function getFix(first, rest, sourceCode, context) {
// Sorry ESLint <= 3 users, no autofix for you. Autofixing duplicate imports
// requires multiple `fixer.whatever()` calls in the `fix`: We both need to
// update the first one, and remove the rest. Support for multiple
Expand Down Expand Up @@ -108,10 +108,17 @@ function getFix(first, rest, sourceCode) {

const [specifiersText] = specifiers.reduce(
([result, needsComma], specifier) => {
let insertText = specifier.text;
const isTypeSpecifier = specifier.importNode.importKind === 'type';
const inlineTypeImport = context.options[0] &&
context.options[0]['inlineTypeImport'];
if (inlineTypeImport && isTypeSpecifier) {
insertText = `type ${insertText}`;
}
return [
needsComma && !specifier.isEmpty
? `${result},${specifier.text}`
: `${result}${specifier.text}`,
? `${result},${insertText}`
: `${result}${insertText}`,
specifier.isEmpty ? needsComma : true,
];
},
Expand Down Expand Up @@ -255,6 +262,9 @@ module.exports = {
considerQueryString: {
type: 'boolean',
},
inlineTypeImport: {
type: 'boolean',
},
},
additionalProperties: false,
},
Expand Down Expand Up @@ -288,6 +298,8 @@ module.exports = {
const map = moduleMaps.get(n.parent);
if (n.importKind === 'type') {
return n.specifiers.length > 0 && n.specifiers[0].type === 'ImportDefaultSpecifier' ? map.defaultTypesImported : map.namedTypesImported;
} else if (n.specifiers.some((spec) => spec.importKind === 'type')) {
return map.namedTypesImported;
}

return hasNamespace(n) ? map.nsImported : map.imported;
Expand Down
85 changes: 84 additions & 1 deletion tests/src/rules/no-duplicates.js
Expand Up @@ -430,7 +430,7 @@ context('TypeScript', function () {

ruleTester.run('no-duplicates', rule, {
valid: [
// #1667: ignore duplicate if is a typescript type import
// #1667: ignore duplicate if is a typescript type import
test({
code: "import type { x } from './foo'; import y from './foo'",
...parserConfig,
Expand Down Expand Up @@ -468,6 +468,19 @@ context('TypeScript', function () {
`,
...parserConfig,
}),
// #2470: ignore duplicate if is a typescript inline type import
test({
code: "import { type x } from './foo'; import y from './foo'",
...parserConfig,
}),
test({
code: "import { type x } from './foo'; import { y } from './foo'",
...parserConfig,
}),
test({
code: "import { type x } from './foo'; import type y from 'foo'",
...parserConfig,
}),
],
invalid: [
test({
Expand Down Expand Up @@ -520,6 +533,76 @@ context('TypeScript', function () {
},
],
}),
test({
code: "import {type x} from './foo'; import type {y} from './foo'",
...parserConfig,
options: [{ 'inlineTypeImport': false }],
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.",
},
],
}),
test({
code: "import {type x} from 'foo'; import type {y} from 'foo'",
...parserConfig,
options: [{ 'inlineTypeImport': true }],
output: `import {type x,type y} from 'foo'; `,
errors: [
{
line: 1,
column: 22,
message: "'foo' imported multiple times.",
},
{
line: 1,
column: 50,
message: "'foo' imported multiple times.",
},
],
}),
test({
code: "import {type x} from './foo'; import {type y} from './foo'",
...parserConfig,
output: `import {type x,type y} from './foo'; `,
errors: [
{
line: 1,
column: 22,
message: "'./foo' imported multiple times.",
},
{
line: 1,
column: 52,
message: "'./foo' imported multiple times.",
},
],
}),
test({
code: "import {AValue, type x, BValue} from './foo'; import {type y} from './foo'",
...parserConfig,
output: `import {AValue, type x, BValue,type y} from './foo'; `,
errors: [
{
line: 1,
column: 38,
message: "'./foo' imported multiple times.",
},
{
line: 1,
column: 68,
message: "'./foo' imported multiple times.",
},
],
}),
],
});
});
Expand Down

0 comments on commit 457c167

Please sign in to comment.