From d4490ab2b13ea422737e7f7cb32907a9e484bd5b Mon Sep 17 00:00:00 2001
From: zallen <47335686+redallen@users.noreply.github.com>
Date: Thu, 4 Jun 2020 17:16:35 -0400
Subject: [PATCH] add no-unused-imports (#90)
* add no-unused-imports
* fix bug
* add docs
---
.circleci/config.yml | 5 ++
packages/eslint-plugin-pf-codemods/index.js | 2 +-
.../lib/rules/no-unused-imports.js | 34 ++++++++
.../lib/rules/remove-unused-imports.js | 85 ------------------
.../test/rules/no-unused-imports.js | 20 +++++
.../test/rules/remove-unused-imports.js | 86 -------------------
packages/pf-codemods/README.md | 14 ++-
7 files changed, 72 insertions(+), 174 deletions(-)
create mode 100644 packages/eslint-plugin-pf-codemods/lib/rules/no-unused-imports.js
delete mode 100644 packages/eslint-plugin-pf-codemods/lib/rules/remove-unused-imports.js
create mode 100644 packages/eslint-plugin-pf-codemods/test/rules/no-unused-imports.js
delete mode 100644 packages/eslint-plugin-pf-codemods/test/rules/remove-unused-imports.js
diff --git a/.circleci/config.yml b/.circleci/config.yml
index bc9482024..52a691ce6 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -46,6 +46,11 @@ jobs:
- run:
name: Test rules
command: yarn test
+ - run:
+ name: Test single file
+ command: yarn test:single
+ when: always
+
deploy:
docker:
- image: circleci/node:12
diff --git a/packages/eslint-plugin-pf-codemods/index.js b/packages/eslint-plugin-pf-codemods/index.js
index 111fe1eb5..7021e3621 100644
--- a/packages/eslint-plugin-pf-codemods/index.js
+++ b/packages/eslint-plugin-pf-codemods/index.js
@@ -34,7 +34,7 @@ const rules = {
"nav-list-variant": require('./lib/rules/nav-list-variant'),
"table-removed-transforms": require('./lib/rules/table-removed-transforms'),
"select-rename-checkbox": require('./lib/rules/select-rename-checkbox'),
- "remove-unused-imports": require('./lib/rules/remove-unused-imports'),
+ "no-unused-imports": require('./lib/rules/no-unused-imports'),
"tab-rename-variant": require('./lib/rules/tab-rename-variant'),
"form-fix-isValid": require('./lib/rules/form-fix-isValid'),
"expandable-rename-expandablesection": require('./lib/rules/expandable-rename-expandablesection'),
diff --git a/packages/eslint-plugin-pf-codemods/lib/rules/no-unused-imports.js b/packages/eslint-plugin-pf-codemods/lib/rules/no-unused-imports.js
new file mode 100644
index 000000000..cd0c75dd5
--- /dev/null
+++ b/packages/eslint-plugin-pf-codemods/lib/rules/no-unused-imports.js
@@ -0,0 +1,34 @@
+// Cleanup from other rules
+module.exports = {
+ create: function(context) {
+ const allTokens = context.getSourceCode().ast.body
+ .filter(node => node.type !== 'ImportDeclaration')
+ .map(node => context.getSourceCode().getTokens(node).map(token => token.value))
+ .reduce((acc, val) => acc.concat(val), []);
+
+ return {
+ ImportDeclaration(node) {
+ // We should visit all nodes in the AST like eslint/lib/rules/no-unused-vars
+ // and add typescript nodes like @typescript-eslint/eslint-plugin/lib/rules/no-unused-vars
+ // ... but let's cheat and string compare to all tokens in the source file instead.
+ if (/@patternfly\/react/.test(node.source.value)) {
+ node.specifiers
+ .filter(spec => !allTokens.includes(spec.local.name))
+ .forEach(spec => context.report({
+ node,
+ message: `unused patternfly import ${spec.local.name}`,
+ fix(fixer) {
+ const fixes = [fixer.remove(spec)];
+ const prevToken = context.getSourceCode().getTokenBefore(spec);
+ if (prevToken && prevToken.value === ',') {
+ fixes.push(fixer.remove(prevToken));
+ }
+ return fixes;
+ }
+ })
+ );
+ }
+ }
+ };
+ }
+};
\ No newline at end of file
diff --git a/packages/eslint-plugin-pf-codemods/lib/rules/remove-unused-imports.js b/packages/eslint-plugin-pf-codemods/lib/rules/remove-unused-imports.js
deleted file mode 100644
index 8045d2780..000000000
--- a/packages/eslint-plugin-pf-codemods/lib/rules/remove-unused-imports.js
+++ /dev/null
@@ -1,85 +0,0 @@
-const removedImports = [
- 'NavVariants', // Use the variant prop on the Nav component with one of these values: 'default' | 'horizontal' | 'tertiary'
- 'CardHead', // See card-rename-components rule for more info
- 'CardHeadMain', // See card-rename-components rule for more info
- 'BackgroundImgSrc', // See background-image-src-enum rule for more info
- 'ChipButton', // See chipgroup-remove-chipbutton rule for more info
- 'ChipGroupToolbarItem', // See chipgroup-remove-chipgrouptoolbaritem rule for more info,
- 'cellHeightAuto', // See table-removed-transforms rule for more info
- 'TitleSize', // See title-size rule for more info
- 'FlexModifiers', // See refactor-breakpointmods rule for more info
- 'FlexBreakpoints', // See refactor-breakpointmods rule for more info
- 'FlexBreakpointMod', // See refactor-breakpointmods rule for more info
- 'FlexItemBreakpointMod' // See refactor-breakpointmods rule for more info
-];
-
-// https://github.com/patternfly/pf-codemods/issues/39
-module.exports = {
- create: function(context) {
- // return {};
- return {
- ImportDeclaration(node) {
- const sourceCode = context.getSourceCode();
- // console.log(context.getSourceCode().getTokens(node));
- if (/\@patternfly\/react-(core|table)/.test(node.source.value)) {
- context.getSourceCode().getTokens(node).forEach(token => {
- let removeFollowingComma = false;
- let aliasRemoveFollowingComma = false;
- let hasImportAlias = false; // i.e: NavVariants as MyThing
- let removePreviousComma = false;
- const tokenText = sourceCode.getText(token);
- if (removedImports.includes(tokenText)) {
- const previousToken = sourceCode.getTokenBefore(token);
- const nextToken = sourceCode.getTokenAfter(token);
- if (sourceCode.getText(nextToken) === ',') {
- removeFollowingComma = true;
- } else if (sourceCode.getText(nextToken) === '}' && sourceCode.getText(previousToken) === ',') {
- removePreviousComma = true;
- } else if (sourceCode.getText(nextToken) === 'as') {
- hasImportAlias = true;
- const whatFollowsAlias = sourceCode.getTokensAfter(token, {
- count: 3
- });
- if (sourceCode.getText(whatFollowsAlias[whatFollowsAlias.length - 1]) === ',') {
- aliasRemoveFollowingComma = true;
- } else if (sourceCode.getText(whatFollowsAlias[whatFollowsAlias.length - 1]) === '}' && sourceCode.getText(previousToken) === ',') {
- removePreviousComma = true;
- }
- }
- context.report({
- node,
- message: `${tokenText} was removed`,
- fix(fixer) {
- const fixes = [
- fixer.remove(token)
- ];
- if (removePreviousComma) {
- fixes.push(fixer.remove(previousToken));
- }
- if (hasImportAlias) {
- let additionalTokensToRemove;
- if (aliasRemoveFollowingComma) {
- // We have something like `NavVariants as MyVariants,` with a comma at the end
- additionalTokensToRemove = sourceCode.getTokensAfter(token, {
- count: 3
- });
- } else {
- // Without a comma
- additionalTokensToRemove = sourceCode.getTokensAfter(token, {
- count: 2
- });
- }
- additionalTokensToRemove.forEach(additionalToken => fixes.push(fixer.remove(additionalToken)));
- } else if (removeFollowingComma) {
- fixes.push(fixer.remove(nextToken));
- }
- return fixes;
- }
- });
- }
- });
- }
- }
- };
- }
-};
diff --git a/packages/eslint-plugin-pf-codemods/test/rules/no-unused-imports.js b/packages/eslint-plugin-pf-codemods/test/rules/no-unused-imports.js
new file mode 100644
index 000000000..485e40130
--- /dev/null
+++ b/packages/eslint-plugin-pf-codemods/test/rules/no-unused-imports.js
@@ -0,0 +1,20 @@
+const ruleTester = require('../ruletester');
+const rule = require('../../lib/rules/no-unused-imports');
+
+ruleTester.run("no-unused-imports", rule, {
+ valid: [
+ {
+ code: `import { Nav, NavVariants } from '@patternfly/react-core'; `,
+ }
+ ],
+ invalid: [
+ {
+ code: `import { Nav, NavVariants } from '@patternfly/react-core'; `,
+ output: `import { Nav } from '@patternfly/react-core'; `,
+ errors: [{
+ message: `unused patternfly import NavVariants`,
+ type: "ImportDeclaration",
+ }]
+ },
+ ]
+});
diff --git a/packages/eslint-plugin-pf-codemods/test/rules/remove-unused-imports.js b/packages/eslint-plugin-pf-codemods/test/rules/remove-unused-imports.js
deleted file mode 100644
index 38e5ea8f7..000000000
--- a/packages/eslint-plugin-pf-codemods/test/rules/remove-unused-imports.js
+++ /dev/null
@@ -1,86 +0,0 @@
-const ruleTester = require('../ruletester');
-const rule = require('../../lib/rules/remove-unused-imports');
-
-ruleTester.run("remove-unused-imports", rule, {
- valid: [
- {
- code: `import { Card } from '@patternfly/react-core';`,
- }
- ],
- invalid: [
- {
- code: `import { NavVariants } from '@patternfly/react-core';`,
- output: `import { } from '@patternfly/react-core';`,
- errors: [{
- message: `NavVariants was removed`,
- type: "ImportDeclaration",
- }]
- },
- {
- code: `import { Card, NavVariants } from '@patternfly/react-core';`,
- output: `import { Card } from '@patternfly/react-core';`,
- errors: [{
- message: `NavVariants was removed`,
- type: "ImportDeclaration",
- }]
- },
- {
- code: `import { NavVariants, Card } from '@patternfly/react-core';`,
- output: `import { Card } from '@patternfly/react-core';`,
- errors: [{
- message: `NavVariants was removed`,
- type: "ImportDeclaration",
- }]
- },
- {
- code: `import { Card, NavVariants, CardTitle } from '@patternfly/react-core';`,
- output: `import { Card, CardTitle } from '@patternfly/react-core';`,
- errors: [{
- message: `NavVariants was removed`,
- type: "ImportDeclaration",
- }]
- },
- {
- code: `import { NavVariants as MyVariants } from '@patternfly/react-core';`,
- output: `import { } from '@patternfly/react-core';`,
- errors: [{
- message: `NavVariants was removed`,
- type: "ImportDeclaration",
- }]
- },
- {
- code: `import { Card, NavVariants as MyVariants } from '@patternfly/react-core';`,
- output: `import { Card } from '@patternfly/react-core';`,
- errors: [{
- message: `NavVariants was removed`,
- type: "ImportDeclaration",
- }]
- },
- {
- code: `import { NavVariants as MyVariants, Card } from '@patternfly/react-core';`,
- output: `import { Card } from '@patternfly/react-core';`,
- errors: [{
- message: `NavVariants was removed`,
- type: "ImportDeclaration",
- }]
- },
- {
- code: `import { Card, NavVariants as MyVariants, CardTitle } from '@patternfly/react-core';`,
- output: `import { Card, CardTitle } from '@patternfly/react-core';`,
- errors: [{
- message: `NavVariants was removed`,
- type: "ImportDeclaration",
- }]
- },
- {
- code: `import { Card } from '@patternfly/react-core';
- import { cellHeightAuto } from '@patternfly/react-table';`,
- output: `import { Card } from '@patternfly/react-core';
- import { } from '@patternfly/react-table';`,
- errors: [{
- message: `cellHeightAuto was removed`,
- type: "ImportDeclaration",
- }]
- },
- ]
-});
diff --git a/packages/pf-codemods/README.md b/packages/pf-codemods/README.md
index 0dc47b65e..fb5b5c969 100644
--- a/packages/pf-codemods/README.md
+++ b/packages/pf-codemods/README.md
@@ -507,8 +507,8 @@ Out:
```jsx
```
-### remove-unused-imports
-This rule cleans up the following removed imports:
+### no-unused-imports
+This rule is meant to be run after all other rules to remove unneeded imports added or no longer necessary such as:
- 'NavVariants', Use the variant prop on the Nav component with one of these values: 'default' | 'horizontal' | 'tertiary'
- 'CardHead', See card-rename-components rule for more info
- 'CardHeadMain', See card-rename-components rule for more info
@@ -516,6 +516,16 @@ This rule cleans up the following removed imports:
- 'ChipButton', See chipgroup-remove-chipbutton rule for more info
- 'ChipGroupToolbarItem' See chipgroup-remove-chipgrouptoolbaritem rule for more info
+#### Examples
+In:
+```jsx
+import { Nav, NavVariants } from '@patternfly/react-core';
+```
+Out:
+```jsx
+import { Nav } from '@patternfly/react-core';
+```
+
### rename-noPadding [(#4133)](https://github.com/patternfly/patternfly-react/pull/4133)
We've renamed `noPadding` to `hasNoPadding` for DataListContent, DrawerHead, DrawerPanelBody, and PageSection components.