diff --git a/packages/eslint-plugin-pf-codemods/index.js b/packages/eslint-plugin-pf-codemods/index.js index f981627ac..053210a51 100644 --- a/packages/eslint-plugin-pf-codemods/index.js +++ b/packages/eslint-plugin-pf-codemods/index.js @@ -33,6 +33,7 @@ const rules = { "tab-title-text": require('./lib/rules/tab-title-text'), "table-removed-transforms": require('./lib/rules/table-removed-transforms'), "select-rename-checkbox": require('./lib/rules/select-rename-checkbox'), + "use-page-header-tools": require('./lib/rules/use-page-header-tools'), }; module.exports = { diff --git a/packages/eslint-plugin-pf-codemods/lib/rules/use-page-header-tools.js b/packages/eslint-plugin-pf-codemods/lib/rules/use-page-header-tools.js new file mode 100644 index 000000000..3f6e87324 --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/lib/rules/use-page-header-tools.js @@ -0,0 +1,81 @@ +const { getPackageImports } = require('../helpers'); + +const renames = { + 'Toolbar': 'PageHeaderTools', + 'ToolbarGroup': 'PageHeaderToolsGroup', + 'ToolbarItem': 'PageHeaderToolsItem' +}; + +const propMap = { + toolbar: 'headerTools', + avatar: '' +} + +module.exports = { + create: function(context) { + const imports = getPackageImports(context, '@patternfly/react-core') + .filter(specifier => Object.keys(renames).includes(specifier.imported.name)); + const pageHeaderImports = getPackageImports(context, '@patternfly/react-core') + .filter(specifier => specifier.imported.name === 'PageHeader'); + + return !imports && !pageHeaderImports ? {} : { + ImportSpecifier(node) { + if (node.parent.source.value === '@patternfly/react-core' + //renamed imports would go here ? + ) { + context.report({ + node, + message: `${node.name} has been renamed ${renames[node.name]}`, + fix(fixer) { + return fixer.replaceText(node, `${renames[node.name]}`); + } + }); + } + }, + // For Toolbar -> PageHeaderTools, ToolbarGroup -> PageHeaderToolsGroup, and ToolbarItem -> PageHeaderToolsItem + JSXIdentifier(node) { + + // For PageHeader prop renames + const imp = pageHeaderImports + .filter(imp => imp.imported.name === 'PageHeader') + .find(imp => imp.local.name === node.name.name); + if (imp) { + const alreadyFixed = node.attributes + .map(attr => attr.name.name) + .includes('data-codemods'); + if (!alreadyFixed) { + const isOpeningPageHeader = node.parent.type === 'JSXIdentifier' && node.name === 'PageHeader'; + node.attributes + .filter(node => propMap.hasOwnProperty(node.name.name)) + .forEach(attribute => { + const newName = propMap[attribute.name.name]; + context.report({ + node, + message: `${node.name.name} has replaced ${attribute.name.name} prop with ${newName}`, + fix(fixer) { + // Delete entire prop if newName is empty + return fixer.replaceText( + !newName ? attribute : attribute.name + `${isOpeningPageHeader ? ' data-codemods="true" ' : ''}`, + newName + ); + } + }) + }); + } + } + }, + // For Toolbar -> PageHeaderTools, ToolbarGroup -> PageHeaderToolsGroup, and ToolbarItem -> PageHeaderToolsItem + JSXIdentifier(node) { + if (imports.map(imp => imp.local.name).includes(node.name)) { + context.report({ + node, + message: `${node.name} renamed to ${renames[node.name]}`, + fix(fixer) { + return fixer.replaceText(node, `${renames[node.name]}`); + } + }); + } + } + }; + } +}; \ No newline at end of file diff --git a/packages/eslint-plugin-pf-codemods/test/rules/use-page-header-tools.js b/packages/eslint-plugin-pf-codemods/test/rules/use-page-header-tools.js new file mode 100644 index 000000000..b7c732391 --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/test/rules/use-page-header-tools.js @@ -0,0 +1,102 @@ +const ruleTester = require("./ruletester"); +const rule = require("../../lib/rules/use-page-header-tools"); + +ruleTester.run("card-rename-components", rule, { + valid: [ + { + code: `import { Page, PageHeader, PageHeaderTools, PageHeaderToolsGroup, PageHeaderToolsItem } from '@patternfly/react-core'; + + + + + + + } + /> +` + }, + { + // no @patternfly import + code: ` + + + + + + +} +/> +` + } + ], + invalid: [ + { + code: `import { Page, PageHeader, Toolbar, ToolbarGroup, ToolbarItem } from '@patternfly/react-core'; + + + + + + + } + /> +`, + output: `import { Page, PageHeader, PageHeaderTools, PageHeaderToolsGroup, PageHeaderToolsItem } from '@patternfly/react-core'; + + + + + + + } + /> +`, + errors: [ + { + message: 'add missing imports CardTitle, CardHeaderMain from @patternfly/react-core', + type: 'ImportSpecifier' + }, + { + message: "PageHeader has replaced toolbar prop with headerTools", + type: "JSXIdentifier" + }, + { + message: "Toolbar renamed to PageHeaderTools", + type: "JSXIdentifier" + }, + { + message: "ToolbarGroup renamed to PageHeaderToolsGroup", + type: "JSXIdentifier" + }, + { + message: "ToolbarItem renamed to PageHeaderToolsItem", + type: "JSXIdentifier" + }, + { + message: "ToolbarGroup renamed to PageHeaderToolsGroup", + type: "JSXIdentifier" + }, + { + message: "Toolbar renamed to PageHeaderTools", + type: "JSXIdentifier" + }, + ] + }, + { + code: `import { Avatar, PageHeader } from '@patternfly/react-core'; + } />`, + output: `import { Card, PageHeader, PageHeaderTools } from '@patternfly/react-core'; + } />`, + errors: [ + { + message: "avatar prop has been removed for PageHeader", + type: "JSXIdentifier" + }, + ] + } + ] +});