diff --git a/packages/eslint-plugin-pf-codemods/src/rules/helpers/index.ts b/packages/eslint-plugin-pf-codemods/src/rules/helpers/index.ts index d428715be..5ef2822a9 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/helpers/index.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/index.ts @@ -20,6 +20,7 @@ export * from "./helpers"; export * from "./importAndExport"; export * from "./includesImport"; export * from "./interfaces"; +export * from "./isReactIcon"; export * from "./JSXAttributes"; export * from "./nodeMatches"; export * from "./pfPackageMatches"; diff --git a/packages/eslint-plugin-pf-codemods/src/rules/helpers/isReactIcon.ts b/packages/eslint-plugin-pf-codemods/src/rules/helpers/isReactIcon.ts new file mode 100644 index 000000000..66e53e789 --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/isReactIcon.ts @@ -0,0 +1,31 @@ +import { Rule } from "eslint"; +import { JSXElement } from "estree-jsx"; +import { getFromPackage, getDefaultImportsFromPackage } from "./index"; + +/** Returns true if an element is a patternfly/react-icons import, false if it isn't, and undefined + * if no element is passed (for type safety) */ +export function isReactIcon(context: Rule.RuleContext, element?: JSXElement) { + if (!element) { + return; + } + + const openingElementIdentifier = element.openingElement.name; + + // TODO: update this to use the appropriate getNodeName helper once it lands + if (openingElementIdentifier.type !== "JSXIdentifier") { + return; + } + const elementName = openingElementIdentifier.name; + + const pfIconsPackage = "@patternfly/react-icons"; + const { imports: iconImports } = getFromPackage(context, pfIconsPackage); + const iconDefaultImports = getDefaultImportsFromPackage( + context, + pfIconsPackage + ); + const allIconImports = [...iconImports, ...iconDefaultImports]; + + return allIconImports.some( + (iconImport) => iconImport.local.name === elementName + ); +} diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/buttonMoveIconsIconProp/button-moveIcons-icon-prop.test.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/buttonMoveIconsIconProp/button-moveIcons-icon-prop.test.ts index 56557f4d8..957aeee01 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/buttonMoveIconsIconProp/button-moveIcons-icon-prop.test.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/buttonMoveIconsIconProp/button-moveIcons-icon-prop.test.ts @@ -9,6 +9,10 @@ ruleTester.run("button-moveIcons-icon-prop", rule, { { code: `import { Button } from '@patternfly/react-core'; `, + }, ], invalid: [ { @@ -81,5 +85,49 @@ ruleTester.run("button-moveIcons-icon-prop", rule, { }, ], }, + // with Icon component child + { + code: `import { Button, Icon } from '@patternfly/react-core'; `, + output: `import { Button, Icon } from '@patternfly/react-core'; `, + errors: [ + { + message: `Icons must now be passed to the \`icon\` prop of Button instead of as children. If you are passing anything other than an icon as children, ignore this rule when running fixes.`, + type: "JSXElement", + }, + ], + }, + // with react-icons icon child + { + code: `import { Button } from '@patternfly/react-core'; import { SomeIcon } from "@patternfly/react-icons"; `, + output: `import { Button } from '@patternfly/react-core'; import { SomeIcon } from "@patternfly/react-icons"; `, + errors: [ + { + message: `Icons must now be passed to the \`icon\` prop of Button instead of as children. If you are passing anything other than an icon as children, ignore this rule when running fixes.`, + type: "JSXElement", + }, + ], + }, + // with react-icons icon child and another child + { + code: `import { Button } from '@patternfly/react-core'; import { SomeIcon } from "@patternfly/react-icons"; `, + output: `import { Button } from '@patternfly/react-core'; import { SomeIcon } from "@patternfly/react-icons"; `, + errors: [ + { + message: `Icons must now be passed to the \`icon\` prop of Button instead of as children. If you are passing anything other than an icon as children, ignore this rule when running fixes.`, + type: "JSXElement", + }, + ], + }, + // with children prop + { + code: `import { Button } from '@patternfly/react-core'; + <> + + + + ); diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/buttonMoveIconsIconProp/buttonMoveIconsIconPropOutput.tsx b/packages/eslint-plugin-pf-codemods/src/rules/v6/buttonMoveIconsIconProp/buttonMoveIconsIconPropOutput.tsx index 298b7fa59..f7db13bd6 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/buttonMoveIconsIconProp/buttonMoveIconsIconPropOutput.tsx +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/buttonMoveIconsIconProp/buttonMoveIconsIconPropOutput.tsx @@ -1,5 +1,16 @@ -import { Button } from "@patternfly/react-core"; +import { Button, Icon } from "@patternfly/react-core"; +import { SomeIcon } from "@patternfly/react-icons"; export const ButtonMoveIconsIconPropInput = () => ( - + <> + + + + );