From 2c73046aa8c5434854c4b7d8e6bf5f8877ca6705 Mon Sep 17 00:00:00 2001 From: Eric Olkowski <70952936+thatblindgeye@users.noreply.github.com> Date: Wed, 29 May 2024 03:17:01 -0400 Subject: [PATCH] feat(Toolbar): replaced spacer props with gap (#648) * feat(Toolbar): replaced spacer props with gap * PR feedback --- .../toolbar-replaced-spacer-spaceItems.md | 19 ++++ ...toolbar-replaced-spacer-spaceItems.test.ts | 97 +++++++++++++++++++ .../toolbar-replaced-spacer-spaceItems.ts | 74 ++++++++++++++ .../toolbarReplacedSpacerSpaceItemsInput.tsx | 29 ++++++ .../toolbarReplacedSpacerSpaceItemsOutput.tsx | 21 ++++ 5 files changed, 240 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..f44283327 --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarReplacedSpacerSpaceItems/toolbar-replaced-spacer-spaceItems.test.ts @@ -0,0 +1,97 @@ +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} } from '@patternfly/react-core'; const NO_SPACER = "spacerNone"; <${component} spacer={{default: NO_SPACER}} />`, + `import { ${component} } from '@patternfly/react-core'; const NO_SPACER = "spacerNone"; <${component} gap={{default: NO_SPACER}} />`, + 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..f31838469 --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarReplacedSpacerSpaceItems/toolbar-replaced-spacer-spaceItems.ts @@ -0,0 +1,74 @@ +import { Rule } from "eslint"; +import { JSXOpeningElement } 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"); + + newValue && + 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 = () => ( + <> + + + + +);