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';