From 6a81538b59c5709168c2bf670a174a0f01e46742 Mon Sep 17 00:00:00 2001 From: adamviktora Date: Tue, 5 Mar 2024 14:14:48 +0100 Subject: [PATCH 1/5] fix(EmptyState): getChildrenText works on all kinds of children - previously the switch would unintentionally handle most cases under JSXText, as the first few whitespaces count as JSXText of children --- ...tyStateHeader-move-into-emptyState.test.ts | 108 +++++++++++++++++- .../emptyStateHeader-move-into-emptyState.ts | 40 ++++--- 2 files changed, 129 insertions(+), 19 deletions(-) diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/emptyStateHeaderMoveIntoEmptyState/emptyStateHeader-move-into-emptyState.test.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/emptyStateHeaderMoveIntoEmptyState/emptyStateHeader-move-into-emptyState.test.ts index 8591677a1..974cc63d0 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/emptyStateHeaderMoveIntoEmptyState/emptyStateHeader-move-into-emptyState.test.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/emptyStateHeaderMoveIntoEmptyState/emptyStateHeader-move-into-emptyState.test.ts @@ -119,7 +119,7 @@ ruleTester.run("emptyStateHeader-move-into-emptyState", rule, { ], }, { - // without any EmptyStateHeader props but with children + // without any EmptyStateHeader props but with children as text code: `import { EmptyState, EmptyStateHeader, @@ -148,6 +148,112 @@ ruleTester.run("emptyStateHeader-move-into-emptyState", rule, { }, ], }, + { + // without any EmptyStateHeader props but with children as single JSXElement + code: `import { + EmptyState, + EmptyStateHeader, + } from "@patternfly/react-core"; + + export const EmptyStateHeaderMoveIntoEmptyStateInput = () => ( + + +

Foo bar

+
+
+ ); + `, + output: `import { + EmptyState, + EmptyStateHeader, + } from "@patternfly/react-core"; + + export const EmptyStateHeaderMoveIntoEmptyStateInput = () => ( + Foo bar}> + + ); + `, + errors: [ + { + message: `EmptyStateHeader has been moved inside of the EmptyState component and is now only customizable using props, and the EmptyStateIcon component now wraps content passed to the icon prop automatically. Additionally, the titleText prop is now required on EmptyState.`, + type: "JSXElement", + }, + ], + }, + { + // without any EmptyStateHeader props but with children as single JSXExpressionContainer + code: `import { + EmptyState, + EmptyStateHeader, + } from "@patternfly/react-core"; + + const title = "Some title"; + + export const EmptyStateHeaderMoveIntoEmptyStateInput = () => ( + + + {title} + + + ); + `, + output: `import { + EmptyState, + EmptyStateHeader, + } from "@patternfly/react-core"; + + const title = "Some title"; + + export const EmptyStateHeaderMoveIntoEmptyStateInput = () => ( + + + ); + `, + errors: [ + { + message: `EmptyStateHeader has been moved inside of the EmptyState component and is now only customizable using props, and the EmptyStateIcon component now wraps content passed to the icon prop automatically. Additionally, the titleText prop is now required on EmptyState.`, + type: "JSXElement", + }, + ], + }, + { + // without any EmptyStateHeader props but with children consisting of multiple elements + code: `import { + EmptyState, + EmptyStateHeader, + } from "@patternfly/react-core"; + + const title = "Some title"; + + export const EmptyStateHeaderMoveIntoEmptyStateInput = () => ( + + + {title} followed by some text + + + ); + `, + output: `import { + EmptyState, + EmptyStateHeader, + } from "@patternfly/react-core"; + + const title = "Some title"; + + export const EmptyStateHeaderMoveIntoEmptyStateInput = () => ( + + {title} followed by some text + }> + + ); + `, + errors: [ + { + message: `EmptyStateHeader has been moved inside of the EmptyState component and is now only customizable using props, and the EmptyStateIcon component now wraps content passed to the icon prop automatically. Additionally, the titleText prop is now required on EmptyState.`, + type: "JSXElement", + }, + ], + }, { // without an EmptyStateHeader or titleText code: `import { EmptyState } from "@patternfly/react-core"; diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/emptyStateHeaderMoveIntoEmptyState/emptyStateHeader-move-into-emptyState.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/emptyStateHeaderMoveIntoEmptyState/emptyStateHeader-move-into-emptyState.ts index 3c8e8e699..c7f5f5ff9 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/emptyStateHeaderMoveIntoEmptyState/emptyStateHeader-move-into-emptyState.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/emptyStateHeaderMoveIntoEmptyState/emptyStateHeader-move-into-emptyState.ts @@ -101,28 +101,33 @@ module.exports = { .join(""); }; - const getElementChildText = (children: JSXElement["children"]) => { + const getChildrenText = (children: JSXElement["children"]) => { if (!children.length) { return ""; } - switch (children[0].type) { - case "JSXText": - return (children as JSXText[]).map((child) => child.value).join(""); - case "JSXExpressionContainer": - case "JSXSpreadChild": - return getNodesText( - children.map( - (child) => - (child as JSXExpressionContainer | JSXSpreadChild).expression - ) + if (children.length === 1 && children[0].type === "JSXText") { + return `"${children[0].value.trim()}"`; + } + + const potentialSingleChild = children.filter( + (child) => !(child.type === "JSXText" && child.value.trim() === "") + ); + + if (potentialSingleChild.length === 1) { + const singleChild = potentialSingleChild[0]; + const singleChildText = context + .getSourceCode() + .getText( + singleChild as JSXExpressionContainer | JSXElement | JSXFragment ); - case "JSXElement": - case "JSXFragment": - return getNodesText(children as JSXElement[] | JSXFragment[]); - default: - return ""; + + return singleChild.type === "JSXExpressionContainer" + ? singleChildText + : `{${singleChildText}}`; } + + return `{<>${getNodesText(children as Node[])}}`; }; return { @@ -182,8 +187,7 @@ module.exports = { const titleTextPropValue = getAttributeText(titleTextAttribute); const titleText = - titleTextPropValue || - `titleText="${getElementChildText(headerChildren)}"`; + titleTextPropValue || `titleText=${getChildrenText(headerChildren)}`; const iconPropValue = getExpressionValue(headerIconAttribute?.value); From f51f7e1800b0226ee2b59368775f5fe0e9a4271d Mon Sep 17 00:00:00 2001 From: adamviktora Date: Tue, 5 Mar 2024 14:26:59 +0100 Subject: [PATCH 2/5] refactor(EmptyState): extract small helpers --- .../src/rules/helpers/JSXAttributes.ts | 18 ++ .../src/rules/helpers/JSXElements.ts | 18 ++ .../src/rules/helpers/getText.ts | 29 +++ .../src/rules/helpers/includesImport.ts | 10 + .../emptyStateHeader-move-into-emptyState.ts | 174 ++++++------------ 5 files changed, 132 insertions(+), 117 deletions(-) create mode 100644 packages/eslint-plugin-pf-codemods/src/rules/helpers/JSXAttributes.ts create mode 100644 packages/eslint-plugin-pf-codemods/src/rules/helpers/JSXElements.ts create mode 100644 packages/eslint-plugin-pf-codemods/src/rules/helpers/getText.ts create mode 100644 packages/eslint-plugin-pf-codemods/src/rules/helpers/includesImport.ts diff --git a/packages/eslint-plugin-pf-codemods/src/rules/helpers/JSXAttributes.ts b/packages/eslint-plugin-pf-codemods/src/rules/helpers/JSXAttributes.ts new file mode 100644 index 000000000..8d196f5f1 --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/JSXAttributes.ts @@ -0,0 +1,18 @@ +import { JSXElement, JSXAttribute } from "estree-jsx"; + +export function getAttribute(node: JSXElement, attributeName: string) { + const attributes = node.openingElement.attributes.filter( + (attr) => attr.type === "JSXAttribute" + ) as JSXAttribute[]; + return attributes.find((attr) => attr.name.name === attributeName); +} + +export function getExpression(node?: JSXAttribute["value"]) { + if (!node) { + return; + } + + if (node.type === "JSXExpressionContainer") { + return node.expression; + } +} diff --git a/packages/eslint-plugin-pf-codemods/src/rules/helpers/JSXElements.ts b/packages/eslint-plugin-pf-codemods/src/rules/helpers/JSXElements.ts new file mode 100644 index 000000000..5703bf355 --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/JSXElements.ts @@ -0,0 +1,18 @@ +import { JSXElement } from "estree-jsx"; + +export function getChildElementByName(node: JSXElement, name: string) { + return node.children?.find( + (child) => + child.type === "JSXElement" && + child.openingElement.name.type === "JSXIdentifier" && + child.openingElement.name.name === name + ) as JSXElement | undefined; +} + +export function nodeIsComponentNamed(node: JSXElement, componentName: string) { + if (node.openingElement.name.type === "JSXIdentifier") { + return node.openingElement.name.name === componentName; + } + + return false; +} diff --git a/packages/eslint-plugin-pf-codemods/src/rules/helpers/getText.ts b/packages/eslint-plugin-pf-codemods/src/rules/helpers/getText.ts new file mode 100644 index 000000000..53d5b09e8 --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/getText.ts @@ -0,0 +1,29 @@ +import { Rule } from "eslint"; + +import { JSXAttribute, Node } from "estree-jsx"; + +export function getAttributeText( + context: Rule.RuleContext, + attribute?: JSXAttribute +) { + if (!attribute) { + return ""; + } + + return context.getSourceCode().getText(attribute); +} + +export function getAttributeValueText( + context: Rule.RuleContext, + attribute?: JSXAttribute +) { + if (!attribute || !attribute.value) { + return ""; + } + + return context.getSourceCode().getText(attribute.value); +} + +export function getNodesText(context: Rule.RuleContext, nodes: Node[]) { + return nodes.map((node) => context.getSourceCode().getText(node)).join(""); +} diff --git a/packages/eslint-plugin-pf-codemods/src/rules/helpers/includesImport.ts b/packages/eslint-plugin-pf-codemods/src/rules/helpers/includesImport.ts new file mode 100644 index 000000000..145356beb --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/includesImport.ts @@ -0,0 +1,10 @@ +import { ImportSpecifier } from "estree-jsx"; + +export function includesImport( + importSpecifiers: ImportSpecifier[], + targetImport: string +) { + return importSpecifiers.some( + (specifier) => specifier.imported.name === targetImport + ); +} diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/emptyStateHeaderMoveIntoEmptyState/emptyStateHeader-move-into-emptyState.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/emptyStateHeaderMoveIntoEmptyState/emptyStateHeader-move-into-emptyState.ts index c7f5f5ff9..64fb830cc 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/emptyStateHeaderMoveIntoEmptyState/emptyStateHeader-move-into-emptyState.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/emptyStateHeaderMoveIntoEmptyState/emptyStateHeader-move-into-emptyState.ts @@ -1,16 +1,23 @@ import { AST, Rule } from "eslint"; import { - JSXElement, - ImportDeclaration, ImportSpecifier, - JSXAttribute, - Node, - JSXText, + JSXElement, JSXExpressionContainer, - JSXSpreadChild, JSXFragment, + Node, } from "estree-jsx"; -import { getFromPackage, pfPackageMatches } from "../../helpers"; +import { getFromPackage } from "../../helpers"; +import { + getAttributeText, + getAttributeValueText, + getNodesText, +} from "../../helpers/getText"; +import { includesImport } from "../../helpers/includesImport"; +import { + getChildElementByName, + nodeIsComponentNamed, +} from "../../helpers/JSXElements"; +import { getAttribute, getExpression } from "../../helpers/JSXAttributes"; const baseMessage = "EmptyStateHeader has been moved inside of the EmptyState component and is now only customizable using props, and the EmptyStateIcon component now wraps content passed to the icon prop automatically. Additionally, the titleText prop is now required on EmptyState."; @@ -22,121 +29,17 @@ module.exports = { const pkg = "@patternfly/react-core"; const { imports } = getFromPackage(context, pkg); - const allOfType = (nodes: Node[], type: string) => - nodes.every((specifier) => specifier.type === type); - - const includesImport = ( - arr: ImportDeclaration["specifiers"], - targetImport: string - ) => { - if (!allOfType(arr, "ImportSpecifier")) { - return false; - } - - return arr.some( - (specifier) => - (specifier as ImportSpecifier).imported.name === targetImport - ); - }; - if (!includesImport(imports, "EmptyState")) { return {}; } - const getChildElementByName = (name: string, node: JSXElement) => - node.children?.find( - (child) => - child.type === "JSXElement" && - child.openingElement.name.type === "JSXIdentifier" && - child.openingElement.name.name === name - ); - - const isComponentNode = (node: JSXElement, componentName: string) => { - if (node.openingElement.name.type === "JSXIdentifier") { - return node.openingElement.name.name === componentName; - } - - return false; - }; - - const getAttribute = ( - node: JSXElement, - attributeName: string - ): JSXAttribute | undefined => { - const attributes = node.openingElement.attributes.filter( - (attr) => attr.type === "JSXAttribute" - ) as JSXAttribute[]; - return attributes.find((attr) => attr.name.name === attributeName); - }; - - const getExpressionValue = (node?: JSXAttribute["value"]) => { - if (!node) { - return; - } - - if (node.type === "JSXExpressionContainer") { - return node.expression; - } - }; - - const getAttributeText = (attribute?: JSXAttribute) => { - if (!attribute) { - return ""; - } - - return context.getSourceCode().getText(attribute); - }; - - const getAttributeValueText = (attribute?: JSXAttribute) => { - if (!attribute || !attribute.value) { - return ""; - } - - return context.getSourceCode().getText(attribute.value); - }; - - const getNodesText = (nodes: Node[]) => { - return nodes - .map((node) => context.getSourceCode().getText(node)) - .join(""); - }; - - const getChildrenText = (children: JSXElement["children"]) => { - if (!children.length) { - return ""; - } - - if (children.length === 1 && children[0].type === "JSXText") { - return `"${children[0].value.trim()}"`; - } - - const potentialSingleChild = children.filter( - (child) => !(child.type === "JSXText" && child.value.trim() === "") - ); - - if (potentialSingleChild.length === 1) { - const singleChild = potentialSingleChild[0]; - const singleChildText = context - .getSourceCode() - .getText( - singleChild as JSXExpressionContainer | JSXElement | JSXFragment - ); - - return singleChild.type === "JSXExpressionContainer" - ? singleChildText - : `{${singleChildText}}`; - } - - return `{<>${getNodesText(children as Node[])}}`; - }; - return { JSXElement(node: JSXElement) { - if (!isComponentNode(node, "EmptyState")) { + if (!nodeIsComponentNamed(node, "EmptyState")) { return; } - const header = getChildElementByName("EmptyStateHeader", node); + const header = getChildElementByName(node, "EmptyStateHeader"); const emptyStateTitleTextAttribute = getAttribute(node, "titleText"); if (!header && !emptyStateTitleTextAttribute) { @@ -176,20 +79,56 @@ module.exports = { } const headingClassNameValue = getAttributeValueText( + context, headingClassNameAttribute ); const headingClassName = headingClassNameValue ? `headerClassName=${headingClassNameValue}` : ""; - const headingLevel = getAttributeText(headingLevelAttribute); - const titleClassName = getAttributeText(titleClassNameAttribute); - const titleTextPropValue = getAttributeText(titleTextAttribute); + const headingLevel = getAttributeText(context, headingLevelAttribute); + const titleClassName = getAttributeText( + context, + titleClassNameAttribute + ); + const titleTextPropValue = getAttributeText( + context, + titleTextAttribute + ); + + const getChildrenText = (children: JSXElement["children"]) => { + if (!children.length) { + return ""; + } + + if (children.length === 1 && children[0].type === "JSXText") { + return `"${children[0].value.trim()}"`; + } + + const potentialSingleChild = children.filter( + (child) => !(child.type === "JSXText" && child.value.trim() === "") + ); + + if (potentialSingleChild.length === 1) { + const singleChild = potentialSingleChild[0]; + const singleChildText = context + .getSourceCode() + .getText( + singleChild as JSXExpressionContainer | JSXElement | JSXFragment + ); + + return singleChild.type === "JSXExpressionContainer" + ? singleChildText + : `{${singleChildText}}`; + } + + return `{<>${getNodesText(context, children as Node[])}}`; + }; const titleText = titleTextPropValue || `titleText=${getChildrenText(headerChildren)}`; - const iconPropValue = getExpressionValue(headerIconAttribute?.value); + const iconPropValue = getExpression(headerIconAttribute?.value); const emptyStateIconComponent = iconPropValue?.type === "JSXElement" ? iconPropValue : undefined; @@ -202,6 +141,7 @@ module.exports = { emptyStateIconComponent && getAttribute(emptyStateIconComponent, "color"); const emptyStateIconComponentColor = getAttributeText( + context, emptyStateIconComponentColorAttribute ); From c1136d4670504d0e81b299fbebfc0f5f6c745718 Mon Sep 17 00:00:00 2001 From: adamviktora Date: Tue, 5 Mar 2024 16:33:54 +0100 Subject: [PATCH 3/5] refactor(imports): export helpers and clean imports --- .../src/rules/helpers/index.ts | 6 +++++- .../emptyStateHeader-move-into-emptyState.ts | 13 ++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) 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 999c2b481..80a263541 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/helpers/index.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/index.ts @@ -1,4 +1,8 @@ export * from "./findAncestor"; export * from "./helpers"; -export * from "./pfPackageMatches"; export * from "./getFromPackage"; +export * from "./getText"; +export * from "./includesImport"; +export * from "./JSXAttributes"; +export * from "./JSXElements"; +export * from "./pfPackageMatches"; diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/emptyStateHeaderMoveIntoEmptyState/emptyStateHeader-move-into-emptyState.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/emptyStateHeaderMoveIntoEmptyState/emptyStateHeader-move-into-emptyState.ts index 64fb830cc..fdf025c92 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/emptyStateHeaderMoveIntoEmptyState/emptyStateHeader-move-into-emptyState.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/emptyStateHeaderMoveIntoEmptyState/emptyStateHeader-move-into-emptyState.ts @@ -6,18 +6,17 @@ import { JSXFragment, Node, } from "estree-jsx"; -import { getFromPackage } from "../../helpers"; import { + getAttribute, getAttributeText, getAttributeValueText, - getNodesText, -} from "../../helpers/getText"; -import { includesImport } from "../../helpers/includesImport"; -import { getChildElementByName, + getNodesText, + getExpression, + getFromPackage, + includesImport, nodeIsComponentNamed, -} from "../../helpers/JSXElements"; -import { getAttribute, getExpression } from "../../helpers/JSXAttributes"; +} from "../../helpers"; const baseMessage = "EmptyStateHeader has been moved inside of the EmptyState component and is now only customizable using props, and the EmptyStateIcon component now wraps content passed to the icon prop automatically. Additionally, the titleText prop is now required on EmptyState."; From 5e6ff93beeca31916b2f20af758202348da5da7e Mon Sep 17 00:00:00 2001 From: adamviktora Date: Thu, 21 Mar 2024 10:34:59 +0100 Subject: [PATCH 4/5] refactor(EmptyState): extract getChildrenAsAttributeValueText helper --- .../src/rules/helpers/getText.ts | 47 ++++++++++++++++++- .../emptyStateHeader-move-into-emptyState.ts | 45 +++--------------- 2 files changed, 53 insertions(+), 39 deletions(-) diff --git a/packages/eslint-plugin-pf-codemods/src/rules/helpers/getText.ts b/packages/eslint-plugin-pf-codemods/src/rules/helpers/getText.ts index 53d5b09e8..14f96b2e1 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/helpers/getText.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/getText.ts @@ -1,6 +1,12 @@ import { Rule } from "eslint"; -import { JSXAttribute, Node } from "estree-jsx"; +import { + JSXAttribute, + JSXElement, + JSXExpressionContainer, + JSXFragment, + Node, +} from "estree-jsx"; export function getAttributeText( context: Rule.RuleContext, @@ -27,3 +33,42 @@ export function getAttributeValueText( export function getNodesText(context: Rule.RuleContext, nodes: Node[]) { return nodes.map((node) => context.getSourceCode().getText(node)).join(""); } + +export function getChildrenAsAttributeValueText( + context: Rule.RuleContext, + children: JSXElement["children"] +) { + if (!children.length) { + return `""`; + } + + // is a single text-only child + if (children.length === 1 && children[0].type === "JSXText") { + const childText = children[0].value.trim(); + + if (childText.includes(`"`)) { + return `{<>${childText}}`; + } + + return `"${childText}"`; + } + + const nonEmptyChildrenNodes = children.filter( + (child) => !(child.type === "JSXText" && child.value.trim() === "") + ); + + if (nonEmptyChildrenNodes.length === 1) { + const singleChild = nonEmptyChildrenNodes[0]; + const singleChildText = context + .getSourceCode() + .getText( + singleChild as JSXExpressionContainer | JSXElement | JSXFragment + ); + + return singleChild.type === "JSXExpressionContainer" + ? singleChildText + : `{${singleChildText}}`; + } + + return `{<>${getNodesText(context, children as Node[])}}`; +} diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/emptyStateHeaderMoveIntoEmptyState/emptyStateHeader-move-into-emptyState.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/emptyStateHeaderMoveIntoEmptyState/emptyStateHeader-move-into-emptyState.ts index fdf025c92..7ec3c5afa 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/emptyStateHeaderMoveIntoEmptyState/emptyStateHeader-move-into-emptyState.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/emptyStateHeaderMoveIntoEmptyState/emptyStateHeader-move-into-emptyState.ts @@ -1,21 +1,15 @@ import { AST, Rule } from "eslint"; -import { - ImportSpecifier, - JSXElement, - JSXExpressionContainer, - JSXFragment, - Node, -} from "estree-jsx"; +import { ImportSpecifier, JSXElement } from "estree-jsx"; import { getAttribute, getAttributeText, getAttributeValueText, getChildElementByName, - getNodesText, getExpression, getFromPackage, includesImport, nodeIsComponentNamed, + getChildrenAsAttributeValueText, } from "../../helpers"; const baseMessage = @@ -95,37 +89,12 @@ module.exports = { titleTextAttribute ); - const getChildrenText = (children: JSXElement["children"]) => { - if (!children.length) { - return ""; - } - - if (children.length === 1 && children[0].type === "JSXText") { - return `"${children[0].value.trim()}"`; - } - - const potentialSingleChild = children.filter( - (child) => !(child.type === "JSXText" && child.value.trim() === "") - ); - - if (potentialSingleChild.length === 1) { - const singleChild = potentialSingleChild[0]; - const singleChildText = context - .getSourceCode() - .getText( - singleChild as JSXExpressionContainer | JSXElement | JSXFragment - ); - - return singleChild.type === "JSXExpressionContainer" - ? singleChildText - : `{${singleChildText}}`; - } - - return `{<>${getNodesText(context, children as Node[])}}`; - }; - const titleText = - titleTextPropValue || `titleText=${getChildrenText(headerChildren)}`; + titleTextPropValue || + `titleText=${getChildrenAsAttributeValueText( + context, + headerChildren + )}`; const iconPropValue = getExpression(headerIconAttribute?.value); From 0ec813023680b47fd7d3ae5c749b3e30ae8801c2 Mon Sep 17 00:00:00 2001 From: adamviktora <84135613+adamviktora@users.noreply.github.com> Date: Thu, 21 Mar 2024 16:30:05 +0100 Subject: [PATCH 5/5] refactor: getAttribute helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Dominik Petřík <77832970+Dominik-Petrik@users.noreply.github.com> --- .../src/rules/helpers/JSXAttributes.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/eslint-plugin-pf-codemods/src/rules/helpers/JSXAttributes.ts b/packages/eslint-plugin-pf-codemods/src/rules/helpers/JSXAttributes.ts index 8d196f5f1..99d85b62e 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/helpers/JSXAttributes.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/JSXAttributes.ts @@ -1,10 +1,9 @@ import { JSXElement, JSXAttribute } from "estree-jsx"; export function getAttribute(node: JSXElement, attributeName: string) { - const attributes = node.openingElement.attributes.filter( - (attr) => attr.type === "JSXAttribute" - ) as JSXAttribute[]; - return attributes.find((attr) => attr.name.name === attributeName); + return node.openingElement.attributes.find( + (attr) => attr.type === "JSXAttribute" && attr.name.name === attributeName + ) as JSXAttribute | undefined; } export function getExpression(node?: JSXAttribute["value"]) {