-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: No duplicate import specifiers rule (#713)
* feat: no-duplicate-import-specifiers cleanup rule * refactor: findDuplicates function * fix: don't update example with unrelated rule * test(noDuplicateImportSpecifiers): add tests of different packages
- Loading branch information
1 parent
f71a9bb
commit 8a09099
Showing
6 changed files
with
176 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
17 changes: 17 additions & 0 deletions
17
...mods/src/rules/v6/noDuplicateImportSpecifiers/no-duplicate-import-specifiers.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
### no-duplicate-import-specifiers | ||
|
||
Duplicate import specifiers should be removed. This is a cleanup rule which runs after other rules. | ||
|
||
#### Examples | ||
|
||
In: | ||
|
||
```jsx | ||
%inputExample% | ||
``` | ||
|
||
Out: | ||
|
||
```jsx | ||
%outputExample% | ||
``` |
94 changes: 94 additions & 0 deletions
94
...-codemods/src/rules/v6/noDuplicateImportSpecifiers/no-duplicate-import-specifiers.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
const ruleTester = require("../../ruletester"); | ||
import * as rule from "./no-duplicate-import-specifiers"; | ||
|
||
ruleTester.run("no-duplicate-import-specifiers", rule, { | ||
valid: [ | ||
{ | ||
// we care only about imports from "@patternfly/react-core" | ||
code: `import { Button, Button } from "somewhere"`, | ||
}, | ||
{ | ||
code: `import { Button, Button as AnotherButton } from "@patternfly/react-core"; | ||
<> | ||
<Button>Sample button</Button> | ||
<AnotherButton>Another one</AnotherButton> | ||
</>`, | ||
}, | ||
{ | ||
code: `import { Select } from '@patternfly/react-core/deprecated'; | ||
import { Select } from '@patternfly/react-core';` | ||
}, | ||
{ | ||
code: `import { Select } from '@patternfly/react-core/deprecated'; | ||
import { Select } from '@patternfly/react-core/dist/dynamic/components/Select';` | ||
}, | ||
{ | ||
code: `import { Select } from '@patternfly/react-core/next'; | ||
import { Select } from '@patternfly/react-core';` | ||
}, | ||
{ | ||
code: `import { Select } from '@patternfly/react-core/next'; | ||
import { Select } from '@patternfly/react-core/dist/dynamic/components/Select';` | ||
} | ||
], | ||
invalid: [ | ||
{ | ||
code: `import { Button, Button } from "@patternfly/react-core"; | ||
<Button>Sample button</Button>`, | ||
output: `import { Button, } from "@patternfly/react-core"; | ||
<Button>Sample button</Button>`, | ||
errors: [ | ||
{ | ||
message: `Duplicate import specifier Button imported from '@patternfly/react-core'.`, | ||
type: "ImportSpecifier", | ||
}, | ||
], | ||
}, | ||
{ | ||
code: `import { Button } from "@patternfly/react-core"; | ||
import { Button } from "@patternfly/react-core"; | ||
<Button>Sample button</Button>`, | ||
output: `import { Button } from "@patternfly/react-core"; | ||
<Button>Sample button</Button>`, | ||
errors: [ | ||
{ | ||
message: `Duplicate import specifier Button imported from '@patternfly/react-core'.`, | ||
type: "ImportSpecifier", | ||
}, | ||
], | ||
}, | ||
{ | ||
code: `import { Button } from "@patternfly/react-core"; | ||
import { Button } from '@patternfly/react-core/dist/dynamic/components/Button'; | ||
<Button>Sample button</Button>`, | ||
output: `import { Button } from "@patternfly/react-core"; | ||
<Button>Sample button</Button>`, | ||
errors: [ | ||
{ | ||
message: `Duplicate import specifier Button imported from '@patternfly/react-core/dist/dynamic/components/Button'.`, | ||
type: "ImportSpecifier", | ||
}, | ||
], | ||
}, | ||
{ | ||
code: `import { Button as BTN, TextInput, Button as BTN } from "@patternfly/react-core"; | ||
<> | ||
<BTN>Sample button</BTN> | ||
<TextInput>Text</TextInput> | ||
</>`, | ||
output: `import { Button as BTN, TextInput, } from "@patternfly/react-core"; | ||
<> | ||
<BTN>Sample button</BTN> | ||
<TextInput>Text</TextInput> | ||
</>`, | ||
errors: [ | ||
{ | ||
message: `Duplicate import specifier BTN imported from '@patternfly/react-core'.`, | ||
type: "ImportSpecifier", | ||
}, | ||
], | ||
}, | ||
], | ||
}); |
50 changes: 50 additions & 0 deletions
50
...in-pf-codemods/src/rules/v6/noDuplicateImportSpecifiers/no-duplicate-import-specifiers.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { Rule } from "eslint"; | ||
import { ImportDeclaration, ImportSpecifier } from "estree-jsx"; | ||
import { getFromPackage, removeSpecifierFromDeclaration } from "../../helpers"; | ||
|
||
// Cleanup from other rules | ||
module.exports = { | ||
meta: { fixable: "code" }, | ||
create: function (context: Rule.RuleContext) { | ||
const { imports } = getFromPackage(context, "@patternfly/react-core"); | ||
|
||
const findDuplicates = (specifiers: ImportSpecifier[]) => { | ||
const localNames = specifiers.map((spec) => spec.local.name); | ||
|
||
return specifiers.filter( | ||
(specifier, index) => localNames.indexOf(specifier.local.name) !== index | ||
); | ||
}; | ||
|
||
const duplicatesToRemove = findDuplicates(imports); | ||
|
||
return !duplicatesToRemove.length | ||
? {} | ||
: { | ||
ImportSpecifier(node: ImportSpecifier) { | ||
if (duplicatesToRemove.includes(node)) { | ||
const importDeclaration = context | ||
.getAncestors() | ||
.find( | ||
(ancestor) => ancestor.type === "ImportDeclaration" | ||
) as ImportDeclaration; | ||
|
||
if (importDeclaration) { | ||
context.report({ | ||
node, | ||
message: `Duplicate import specifier ${node.local.name} imported from '${importDeclaration.source.value}'.`, | ||
fix(fixer) { | ||
return removeSpecifierFromDeclaration( | ||
fixer, | ||
context, | ||
importDeclaration, | ||
node | ||
); | ||
}, | ||
}); | ||
} | ||
} | ||
}, | ||
}; | ||
}, | ||
}; |
5 changes: 5 additions & 0 deletions
5
...pf-codemods/src/rules/v6/noDuplicateImportSpecifiers/noDuplicateImportSpecifiersInput.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { Button, Button } from "@patternfly/react-core"; | ||
|
||
export const NoDuplicateImportSpecifiersInput = () => ( | ||
<Button>Sample button</Button> | ||
); |
5 changes: 5 additions & 0 deletions
5
...f-codemods/src/rules/v6/noDuplicateImportSpecifiers/noDuplicateImportSpecifiersOutput.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { Button } from "@patternfly/react-core"; | ||
|
||
export const NoDuplicateImportSpecifiersInput = () => ( | ||
<Button>Sample button</Button> | ||
); |