diff --git a/packages/eslint-plugin-pf-codemods/src/rules/helpers/findAncestor.ts b/packages/eslint-plugin-pf-codemods/src/rules/helpers/findAncestor.ts new file mode 100644 index 000000000..cbd6b2ca0 --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/findAncestor.ts @@ -0,0 +1,24 @@ +import { JSXElement, JSXOpeningElement } from "estree-jsx"; + +type NodeWithParent = (JSXOpeningElement | JSXElement) & { + parent?: NodeWithParent | null; +}; + +export function findAncestor( + node: NodeWithParent, + conditionCallback: (_current: NodeWithParent) => boolean +): NodeWithParent | undefined { + if (!node) { + return; + } + + let current = node.parent; + + while (current) { + if (conditionCallback(current)) { + return current; + } + + current = current.parent; + } +} diff --git a/packages/eslint-plugin-pf-codemods/src/rules/helpers/helpers.js b/packages/eslint-plugin-pf-codemods/src/rules/helpers/helpers.js index 4cd0375cf..c369cb084 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/helpers/helpers.js +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/helpers.js @@ -1,5 +1,6 @@ import { getFromPackage } from "./getFromPackage"; import { pfPackageMatches } from "./pfPackageMatches"; +import { findAncestor } from "./findAncestor"; const evk = require("eslint-visitor-keys"); @@ -880,17 +881,3 @@ export function findVariableDeclaration(name, scope) { } return undefined; } - -export function findAncestor(node, conditionCallback = (_current) => false) { - let current = node?.parent; - - while (current) { - if (conditionCallback(current)) { - return current; - } - - current = current.parent; - } - - return undefined; -} 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 ed9f266fd..999c2b481 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/helpers/index.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/index.ts @@ -1,3 +1,4 @@ -export * from './helpers'; -export * from './pfPackageMatches'; -export * from './getFromPackage'; \ No newline at end of file +export * from "./findAncestor"; +export * from "./helpers"; +export * from "./pfPackageMatches"; +export * from "./getFromPackage"; diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/accordionToggleMoveIsExpandedProp/accordionToggle-move-isExpanded-prop.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/accordionToggleMoveIsExpandedProp/accordionToggle-move-isExpanded-prop.ts index 74e8c3e26..69bee7da1 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/accordionToggleMoveIsExpandedProp/accordionToggle-move-isExpanded-prop.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/accordionToggleMoveIsExpandedProp/accordionToggle-move-isExpanded-prop.ts @@ -1,6 +1,6 @@ import { getFromPackage, findAncestor } from "../../helpers"; import { Rule } from "eslint"; -import { JSXOpeningElement } from "estree-jsx"; +import { JSXElement, JSXOpeningElement } from "estree-jsx"; // https://github.com/patternfly/patternfly-react/pull/9876 module.exports = { @@ -26,30 +26,39 @@ module.exports = { attr.type === "JSXAttribute" && attr.name.name === "isExpanded" ); - if (attribute) { - context.report({ - node, - message: - "The `isExpanded` prop for AccordionToggle has been moved to AccordionItem.", - fix(fixer) { - const accordionItemAncestor = findAncestor( - node, - (current) => - current?.openingElement?.name?.name === "AccordionItem" - ); - const attributeValue = context - .getSourceCode() - .getText(attribute); - return [ - fixer.replaceText(attribute, ""), - fixer.insertTextAfter( - accordionItemAncestor.openingElement.name, - ` ${attributeValue}` - ), - ]; - }, - }); + + if (!attribute) { + return; } + + context.report({ + node, + message: + "The `isExpanded` prop for AccordionToggle has been moved to AccordionItem.", + fix(fixer) { + const accordionItemAncestor = findAncestor( + node, + (current) => + current.type === "JSXElement" && + current.openingElement.name.type === "JSXIdentifier" && + current.openingElement.name.name === "AccordionItem" + ); + const attributeValue = context + .getSourceCode() + .getText(attribute); + + return accordionItemAncestor && + accordionItemAncestor.type === "JSXElement" + ? [ + fixer.replaceText(attribute, ""), + fixer.insertTextAfter( + accordionItemAncestor.openingElement.name, + ` ${attributeValue}` + ), + ] + : []; + }, + }); } }, };