From 1a7473558bad3747824ee050e292958a0f9af416 Mon Sep 17 00:00:00 2001 From: Eric Olkowski Date: Thu, 23 May 2024 13:51:35 -0400 Subject: [PATCH] feat(Toolbar): replaced spacer props with gap --- .../toolbar-replaced-spacer-spaceItems.md | 19 ++++ ...toolbar-replaced-spacer-spaceItems.test.ts | 90 +++++++++++++++++++ .../toolbar-replaced-spacer-spaceItems.ts | 73 +++++++++++++++ .../toolbarReplacedSpacerSpaceItemsInput.tsx | 29 ++++++ .../toolbarReplacedSpacerSpaceItemsOutput.tsx | 21 +++++ 5 files changed, 232 insertions(+) create mode 100644 packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarReplacedSpacerSpaceItems/toolbar-replaced-spacer-spaceItems.md create mode 100644 packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarReplacedSpacerSpaceItems/toolbar-replaced-spacer-spaceItems.test.ts create mode 100644 packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarReplacedSpacerSpaceItems/toolbar-replaced-spacer-spaceItems.ts create mode 100644 packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarReplacedSpacerSpaceItems/toolbarReplacedSpacerSpaceItemsInput.tsx create mode 100644 packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarReplacedSpacerSpaceItems/toolbarReplacedSpacerSpaceItemsOutput.tsx diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarReplacedSpacerSpaceItems/toolbar-replaced-spacer-spaceItems.md b/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarReplacedSpacerSpaceItems/toolbar-replaced-spacer-spaceItems.md new file mode 100644 index 000000000..0a564e658 --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarReplacedSpacerSpaceItems/toolbar-replaced-spacer-spaceItems.md @@ -0,0 +1,19 @@ +### toolbar-replaced-spacer-spaceItems [(#10418)](https://github.com/patternfly/patternfly-react/pull/10418) + +The `spacer` property has been removed from ToolbarGroup, ToolbarItem, and ToolbarToggleGroup. We recommend instead using our new `gap`, `columnGap`, or `rowGap` properties. + +Additionally, the `spaceItems` property has been removed from ToolbarGroup and ToolbarToggleGroup. + +#### Examples + +In: + +```jsx +%inputExample% +``` + +Out: + +```jsx +%outputExample% +``` diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarReplacedSpacerSpaceItems/toolbar-replaced-spacer-spaceItems.test.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarReplacedSpacerSpaceItems/toolbar-replaced-spacer-spaceItems.test.ts new file mode 100644 index 000000000..b1d9c42ee --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarReplacedSpacerSpaceItems/toolbar-replaced-spacer-spaceItems.test.ts @@ -0,0 +1,90 @@ +const ruleTester = require("../../ruletester"); +import * as rule from "./toolbar-replaced-spacer-spaceItems"; +import { RuleTester } from "eslint"; + +const toolbarComponents = ["ToolbarGroup", "ToolbarToggleGroup", "ToolbarItem"]; +const validTests: Array = []; +const invalidTests: RuleTester.InvalidTestCase[] = []; +const createValidTest = (code: string) => ({ + code, +}); +const createInvalidTest = (code: string, output: string, message: string) => ({ + code, + output, + errors: [ + { + message, + type: "JSXOpeningElement", + }, + ], +}); + +toolbarComponents.forEach((component) => { + validTests.push(createValidTest(`<${component} spacer />`)); + validTests.push(createValidTest(`<${component} spaceItems />`)); + validTests.push( + createValidTest( + `import { ${component} } from '@patternfly/react-core'; <${component} />` + ) + ); + + const spacerErrorMessage = `The spacer property has been removed from ${component}. We recommend instead using our new gap, columnGap, or rowGap properties.`; + const spaceItemsErrorMessage = `spaceItems property has been removed from ${component}.`; + invalidTests.push( + createInvalidTest( + `import { ${component} } from '@patternfly/react-core'; <${component} spacer={{default: "spacerNone"}} />`, + `import { ${component} } from '@patternfly/react-core'; <${component} gap={{default: "gapNone"}} />`, + spacerErrorMessage + ) + ); + invalidTests.push( + createInvalidTest( + `import { ${component} as CustomComponent } from '@patternfly/react-core'; `, + `import { ${component} as CustomComponent } from '@patternfly/react-core'; `, + `The spacer property has been removed from CustomComponent. We recommend instead using our new gap, columnGap, or rowGap properties.` + ) + ); + invalidTests.push( + createInvalidTest( + `import { ${component} } from '@patternfly/react-core'; <${component} spacer={{default: "spacerNone", md: "spacerLg", lg: "spacerSm"}} />`, + `import { ${component} } from '@patternfly/react-core'; <${component} gap={{default: "gapNone", md: "gapLg", lg: "gapSm"}} />`, + spacerErrorMessage + ) + ); + createInvalidTest( + `import { ${component} } from '@patternfly/react-core'; <${component} spaceItems={{default: "spaceItemsNone"}} />`, + `import { ${component} } from '@patternfly/react-core'; <${component} />`, + `The ${spaceItemsErrorMessage}` + ); + createInvalidTest( + `import { ${component} } from '@patternfly/react-core'; <${component} spacer={{default: "spacerNone"}} spaceItems={{default: "spaceItemsNone"}} />`, + `import { ${component} } from '@patternfly/react-core'; <${component} gap={{default: "gapNone"}} />`, + `${spacerErrorMessage} Additionally, the ${spaceItemsErrorMessage}` + ); + invalidTests.push( + createInvalidTest( + `import { ${component} } from '@patternfly/react-core/dist/esm/components/Toolbar/index.js'; <${component} spacer={{default: "spacerNone"}} />`, + `import { ${component} } from '@patternfly/react-core/dist/esm/components/Toolbar/index.js'; <${component} gap={{default: "gapNone"}} />`, + spacerErrorMessage + ) + ); + invalidTests.push( + createInvalidTest( + `import { ${component} } from '@patternfly/react-core/dist/js/components/Toolbar/index.js'; <${component} spacer={{default: "spacerNone"}} />`, + `import { ${component} } from '@patternfly/react-core/dist/js/components/Toolbar/index.js'; <${component} gap={{default: "gapNone"}} />`, + spacerErrorMessage + ) + ); + invalidTests.push( + createInvalidTest( + `import { ${component} } from '@patternfly/react-core/dist/dynamic/components/Toolbar/index.js'; <${component} spacer={{default: "spacerNone"}} />`, + `import { ${component} } from '@patternfly/react-core/dist/dynamic/components/Toolbar/index.js'; <${component} gap={{default: "gapNone"}} />`, + spacerErrorMessage + ) + ); +}); + +ruleTester.run("toolbar-replaced-spacer-spaceItems", rule, { + valid: validTests, + invalid: invalidTests, +}); diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarReplacedSpacerSpaceItems/toolbar-replaced-spacer-spaceItems.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarReplacedSpacerSpaceItems/toolbar-replaced-spacer-spaceItems.ts new file mode 100644 index 000000000..46d20ce72 --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarReplacedSpacerSpaceItems/toolbar-replaced-spacer-spaceItems.ts @@ -0,0 +1,73 @@ +import { Rule } from "eslint"; +import { JSXOpeningElement, JSXAttribute } from "estree-jsx"; +import { Property } from "estree-jsx"; +import { getFromPackage, getAttribute, getAttributeValue } from "../../helpers"; + +// https://github.com/patternfly/patternfly-react/pull/10418 +module.exports = { + meta: { fixable: "code" }, + create: function (context: Rule.RuleContext) { + const { imports } = getFromPackage(context, "@patternfly/react-core"); + + const toolbarImports = imports.filter((specifier) => + ["ToolbarGroup", "ToolbarToggleGroup", "ToolbarItem"].includes( + specifier.imported.name + ) + ); + + return !toolbarImports.length + ? {} + : { + JSXOpeningElement(node: JSXOpeningElement) { + if ( + node.name.type === "JSXIdentifier" && + toolbarImports + .map((imp) => imp.local.name) + .includes(node.name.name) + ) { + const spacerProp = getAttribute(node, "spacer"); + const spaceItemsProp = getAttribute(node, "spaceItems"); + if (!spacerProp && !spaceItemsProp) { + return; + } + const spacerPropMessage = `The spacer property has been removed from ${node.name.name}. We recommend instead using our new gap, columnGap, or rowGap properties.`; + const spaceItemsPropMessage = `${ + spacerProp ? " Additionally, the" : "The" + } spaceItems property has been removed from ${node.name.name}.`; + const spacerVal = + spacerProp && getAttributeValue(context, spacerProp.value); + + context.report({ + node, + message: `${spacerProp ? spacerPropMessage : ""}${ + spaceItemsProp ? spaceItemsPropMessage : "" + }`, + fix(fixer) { + const fixes = []; + + if (spacerProp) { + spacerVal && + spacerVal.forEach((val: Property) => { + const newValue = + val.value?.type === "Literal" && + (val.value.value as string).replace("spacer", "gap"); + + fixes.push( + fixer.replaceText(val.value, `"${newValue}"`) + ); + }); + + fixes.push(fixer.replaceText(spacerProp.name, "gap")); + } + if (spaceItemsProp) { + fixes.push(fixer.replaceText(spaceItemsProp, "")); + } + + return fixes; + }, + }); + } + }, + }; + }, +}; diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarReplacedSpacerSpaceItems/toolbarReplacedSpacerSpaceItemsInput.tsx b/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarReplacedSpacerSpaceItems/toolbarReplacedSpacerSpaceItemsInput.tsx new file mode 100644 index 000000000..1e2f38b44 --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarReplacedSpacerSpaceItems/toolbarReplacedSpacerSpaceItemsInput.tsx @@ -0,0 +1,29 @@ +import { + ToolbarGroup, + ToolbarItem, + ToolbarToggleGroup, +} from "@patternfly/react-core"; + +export const ToolbarReplacedSpacerSpaceItemsInput = () => ( + <> + + + + +); diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarReplacedSpacerSpaceItems/toolbarReplacedSpacerSpaceItemsOutput.tsx b/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarReplacedSpacerSpaceItems/toolbarReplacedSpacerSpaceItemsOutput.tsx new file mode 100644 index 000000000..02da283ad --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarReplacedSpacerSpaceItems/toolbarReplacedSpacerSpaceItemsOutput.tsx @@ -0,0 +1,21 @@ +import { + ToolbarGroup, + ToolbarItem, + ToolbarToggleGroup, +} from "@patternfly/react-core"; + +export const ToolbarReplacedSpacerSpaceItemsInput = () => ( + <> + + + + +);