From 016ba540967a51fa7850c8f42c6a7dd6967482e2 Mon Sep 17 00:00:00 2001 From: Austin Sullivan Date: Tue, 27 Feb 2024 12:28:12 -0500 Subject: [PATCH] chore(EmptyState): Address PR feedback --- .../emptyStateHeader-move-into-emptyState.md | 4 +- ...tyStateHeader-move-into-emptyState.test.ts | 25 +++++++++ .../emptyStateHeader-move-into-emptyState.ts | 54 ++++++++++--------- 3 files changed, 58 insertions(+), 25 deletions(-) diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/emptyStateHeaderMoveIntoEmptyState/emptyStateHeader-move-into-emptyState.md b/packages/eslint-plugin-pf-codemods/src/rules/v6/emptyStateHeaderMoveIntoEmptyState/emptyStateHeader-move-into-emptyState.md index adf5f73cb..95d61eae7 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/emptyStateHeaderMoveIntoEmptyState/emptyStateHeader-move-into-emptyState.md +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/emptyStateHeaderMoveIntoEmptyState/emptyStateHeader-move-into-emptyState.md @@ -1,6 +1,8 @@ ### emptyStateHeader-move-into-emptyState [(#9947)](https://github.com/patternfly/patternfly-react/pull/9947) -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. +EmptyStateHeader and EmptyStateIcon are now rendered internally within EmptyState and should only be customized using props. Content passed to the `icon` prop on EmptyState will also be wrapped by EmptyStateIcon automatically. + +Additionally, the `titleText` prop is now required on EmptyState. #### Examples 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 fe0b9d87c..eb4c7ea06 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 @@ -148,6 +148,31 @@ ruleTester.run("emptyStateHeader-move-into-emptyState", rule, { }, ], }, + { + // without an EmptyStateHeader or titleText + code: `import { EmptyState } from "@patternfly/react-core"; + + export const EmptyStateHeaderMoveIntoEmptyStateInput = () => ( + + Foo bar + + ); + `, + output: `import { EmptyState } 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. You must manually supply a titleText prop.`, + type: "JSXElement", + }, + ], + }, { // with both titleText and children code: `import { 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 a5b415fe7..6099f7f9c 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 @@ -4,10 +4,7 @@ import { ImportDeclaration, ImportSpecifier, JSXAttribute, - Literal, Node, - Expression, - ClassExpression, JSXText, JSXExpressionContainer, JSXSpreadChild, @@ -25,24 +22,24 @@ module.exports = { const pkg = "@patternfly/react-core"; const { imports } = getFromPackage(context, pkg); - function allOfType(nodes: Node[], type: string) { - return nodes.every((specifier) => specifier.type === type); - } + const allOfType = (nodes: Node[], type: string) => + nodes.every((specifier) => specifier.type === type); const includesImport = ( arr: ImportDeclaration["specifiers"], targetImport: string - ) => - arr.some( + ) => { + if (!allOfType(arr, "ImportSpecifier")) { + return false; + } + + return arr.some( (specifier) => - allOfType(arr, "ImportSpecifier") && (specifier as ImportSpecifier).imported.name === targetImport ); + }; - if ( - !includesImport(imports, "EmptyStateHeader") || - !includesImport(imports, "EmptyState") - ) { + if (!includesImport(imports, "EmptyState")) { return {}; } @@ -101,6 +98,10 @@ module.exports = { return value.value; } + if (value.type === "JSXExpressionContainer") { + return context.getSourceCode().getText(value.expression); + } + return ""; }; @@ -135,20 +136,21 @@ module.exports = { }; return { - ImportDeclaration(node: ImportDeclaration) { - if ( - !pfPackageMatches(pkg, node.source.value) || - !includesImport(node.specifiers, "EmptyStateHeader") - ) { - return; - } - }, JSXElement(node: JSXElement) { if (!isComponentNode(node, "EmptyState")) { return; } const header = getChildElementByName("EmptyStateHeader", node); + const emptyStateTitleTextAttribute = getAttribute(node, "titleText"); + + if (!header && !emptyStateTitleTextAttribute) { + context.report({ + node, + message: `${baseMessage} You must manually supply a titleText prop to EmptyState.`, + }); + return; + } if (!header || header.type !== "JSXElement") { return; @@ -165,7 +167,7 @@ module.exports = { if (!titleTextAttribute && !headerChildren.length) { context.report({ node, - message: `${baseMessage} You must manually supply a titleText prop, then you can rerun this codemod.`, + message: `${baseMessage} You must manually supply a titleText prop to EmptyState, then you can rerun this codemod.`, }); return; } @@ -202,8 +204,12 @@ module.exports = { emptyStateIconComponent && getAttribute(emptyStateIconComponent, "icon"); - const emptyStateIconComponentColorAttribute = emptyStateIconComponent && getAttribute(emptyStateIconComponent, "color"); - const emptyStateIconComponentColor = getAttributeText(emptyStateIconComponentColorAttribute); + const emptyStateIconComponentColorAttribute = + emptyStateIconComponent && + getAttribute(emptyStateIconComponent, "color"); + const emptyStateIconComponentColor = getAttributeText( + emptyStateIconComponentColorAttribute + ); if (emptyStateIconComponentColor) { context.report({