From 0bb13f787f597785872fe0abc65063bcf64b8e14 Mon Sep 17 00:00:00 2001 From: adamviktora Date: Wed, 23 Oct 2024 15:11:44 +0200 Subject: [PATCH 1/9] fix: type getVariableValue helper --- .../src/rules/helpers/JSXAttributes.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 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 9ae2c1c9..bf5c80d3 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/helpers/JSXAttributes.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/JSXAttributes.ts @@ -7,6 +7,7 @@ import { JSXFragment, JSXOpeningElement, MemberExpression, + Property, } from "estree-jsx"; export function getAttribute( @@ -128,12 +129,12 @@ export function getVariableValue( ); } if (variableInit.type === "Literal") { - return variableInit.value; + return variableInit.value as string; } if (variableInit.type === "MemberExpression") { return getMemberExpression(variableInit); } if (variableInit.type === "ObjectExpression") { - return variableInit.properties; + return variableInit.properties as Property[]; } } From 589c02113a8dd4fdb9da2382bf345762d0941d2a Mon Sep 17 00:00:00 2001 From: adamviktora Date: Tue, 29 Oct 2024 17:49:24 +0100 Subject: [PATCH 2/9] feat(helpers): isEnumValue and propertyNameMatches helpers --- .../src/rules/helpers/index.ts | 2 ++ .../src/rules/helpers/isEnumValue.ts | 23 +++++++++++++ .../src/rules/helpers/propertyNameMatches.ts | 32 +++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 packages/eslint-plugin-pf-codemods/src/rules/helpers/isEnumValue.ts create mode 100644 packages/eslint-plugin-pf-codemods/src/rules/helpers/propertyNameMatches.ts 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 4770ebee..342f505c 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/helpers/index.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/index.ts @@ -22,12 +22,14 @@ export * from "./helpers"; export * from "./importAndExport"; export * from "./includesImport"; export * from "./interfaces"; +export * from "./isEnumValue"; export * from "./isReactIcon"; export * from "./JSXAttributes"; export * from "./makeJSXElementSelfClosing"; export * from "./nodeMatches/checkMatchingImportDeclaration"; export * from "./nodeMatches/checkMatchingJSXOpeningElement"; export * from "./pfPackageMatches"; +export * from "./propertyNameMatches"; export * from "./removeElement"; export * from "./removeEmptyLineAfter"; export * from "./removePropertiesFromObjectExpression"; diff --git a/packages/eslint-plugin-pf-codemods/src/rules/helpers/isEnumValue.ts b/packages/eslint-plugin-pf-codemods/src/rules/helpers/isEnumValue.ts new file mode 100644 index 00000000..c158335a --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/isEnumValue.ts @@ -0,0 +1,23 @@ +import { MemberExpression } from "estree-jsx"; +import { propertyNameMatches } from "./propertyNameMatches"; +import { Rule } from "eslint"; + +/** Checks whether an enum node (MemberExpression), e.g. ButtonVariant["primary"] + * has a given enumName ("ButtonVariant") and a given propertyName ("primary") */ +export function isEnumValue( + context: Rule.RuleContext, + enumExpression: MemberExpression, + enumName: string, + propertyName: string +) { + return ( + enumExpression.object?.type === "Identifier" && + enumExpression.object.name === enumName && + propertyNameMatches( + context, + enumExpression.property, + enumExpression.computed, + propertyName + ) + ); +} diff --git a/packages/eslint-plugin-pf-codemods/src/rules/helpers/propertyNameMatches.ts b/packages/eslint-plugin-pf-codemods/src/rules/helpers/propertyNameMatches.ts new file mode 100644 index 00000000..abc549df --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/propertyNameMatches.ts @@ -0,0 +1,32 @@ +import { Rule } from "eslint"; +import { Expression, Identifier, PrivateIdentifier } from "estree-jsx"; +import { getVariableDeclaration } from "./JSXAttributes"; + +/** Check whether a property name is of a given value. + * Property can either be of an ObjectExpression - {propName: "value"} or MemberExpression - someObject.propName */ +export function propertyNameMatches( + context: Rule.RuleContext, + key: Expression | PrivateIdentifier, + computed: boolean, + name: string +) { + const isIdentifier = key.type === "Identifier"; + + // E.g. const key = "key"; {[key]: value}; someObject[key] + if (isIdentifier && computed) { + const scope = context.getSourceCode().getScope(key); + const propertyName = (key as Identifier).name; + const propertyVariable = getVariableDeclaration(propertyName, scope); + return propertyVariable?.defs[0].node.init.value === name; + } + // E.g. {key: value}; someObject.key + if (isIdentifier && !computed) { + return (key as Identifier).name === name; + } + // E.g. {"key": value} or {["key"]: value}; someObject["key"] + if (key.type === "Literal") { + return key.value === name; + } + + return false; +} From a84ba10f5f7aeaf551b23f2c4540954b9e4385d7 Mon Sep 17 00:00:00 2001 From: adamviktora Date: Tue, 29 Oct 2024 17:51:26 +0100 Subject: [PATCH 3/9] refactor(helpers) --- .../src/rules/helpers/JSXAttributes.ts | 13 ++------- .../src/rules/helpers/getObjectProperty.ts | 27 ++++--------------- 2 files changed, 7 insertions(+), 33 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 bf5c80d3..22ca349d 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/helpers/JSXAttributes.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/JSXAttributes.ts @@ -59,7 +59,7 @@ export function getAttributeValue( return getVariableValue(node.expression.name, variableScope, context); } if (node.expression.type === "MemberExpression") { - return getMemberExpression(node.expression); + return node.expression; } if (node.expression.type === "Literal") { return node.expression.value; @@ -79,15 +79,6 @@ export function getExpression(node?: JSXAttribute["value"]) { } } -function getMemberExpression(node: MemberExpression) { - if (!node) { - return; - } - const { object, property } = node; - - return { object, property }; -} - export function getVariableDeclaration( name: string, scope: Scope.Scope | null @@ -132,7 +123,7 @@ export function getVariableValue( return variableInit.value as string; } if (variableInit.type === "MemberExpression") { - return getMemberExpression(variableInit); + return variableInit as MemberExpression; } if (variableInit.type === "ObjectExpression") { return variableInit.properties as Property[]; diff --git a/packages/eslint-plugin-pf-codemods/src/rules/helpers/getObjectProperty.ts b/packages/eslint-plugin-pf-codemods/src/rules/helpers/getObjectProperty.ts index 8446eaf2..c8f913f6 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/helpers/getObjectProperty.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/getObjectProperty.ts @@ -1,6 +1,6 @@ import { Rule } from "eslint"; -import { Property, Identifier } from "estree-jsx"; -import { getVariableDeclaration } from "./JSXAttributes"; +import { Property } from "estree-jsx"; +import { propertyNameMatches } from "./propertyNameMatches"; /** Can be used to run logic on the specified property of an ObjectExpression or * only if the specified property exists. @@ -14,26 +14,9 @@ export function getObjectProperty( return; } - const matchedProperty = properties.find((property) => { - const isIdentifier = property.key.type === "Identifier"; - const { computed } = property; - - // E.g. const key = "key"; {[key]: value} - if (isIdentifier && computed) { - const scope = context.getSourceCode().getScope(property); - const propertyName = (property.key as Identifier).name; - const propertyVariable = getVariableDeclaration(propertyName, scope); - return propertyVariable?.defs[0].node.init.value === name; - } - // E.g. {key: value} - if (isIdentifier && !computed) { - return (property.key as Identifier).name === name; - } - // E.g. {"key": value} or {["key"]: value} - if (property.key.type === "Literal") { - return property.key.value === name; - } - }); + const matchedProperty = properties.find((property) => + propertyNameMatches(context, property.key, property.computed, name) + ); return matchedProperty; } From c43d8a619fc6ea72fc9256499e1f171afea3c3d2 Mon Sep 17 00:00:00 2001 From: adamviktora Date: Wed, 30 Oct 2024 11:34:26 +0100 Subject: [PATCH 4/9] feat(helpers): getEnumPropertyName helper --- .../src/rules/helpers/getEnumPropertyName.ts | 28 +++++++++++++++++++ .../src/rules/helpers/index.ts | 1 + 2 files changed, 29 insertions(+) create mode 100644 packages/eslint-plugin-pf-codemods/src/rules/helpers/getEnumPropertyName.ts diff --git a/packages/eslint-plugin-pf-codemods/src/rules/helpers/getEnumPropertyName.ts b/packages/eslint-plugin-pf-codemods/src/rules/helpers/getEnumPropertyName.ts new file mode 100644 index 00000000..c4b2e0e8 --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/getEnumPropertyName.ts @@ -0,0 +1,28 @@ +import { Rule } from "eslint"; +import { Identifier, MemberExpression } from "estree-jsx"; +import { getVariableDeclaration } from "."; + +/** Used to get a property name on an enum (MemberExpression). */ +export function getEnumPropertyName( + context: Rule.RuleContext, + enumNode: MemberExpression +) { + const isIdentifier = enumNode.property.type === "Identifier"; + const computed = enumNode.computed; + + // E.g. const key = "key"; someEnum[key] + if (isIdentifier && computed) { + const scope = context.getSourceCode().getScope(enumNode); + const propertyName = (enumNode.property as Identifier).name; + const propertyVariable = getVariableDeclaration(propertyName, scope); + return propertyVariable?.defs[0].node.init.value as string; + } + // E.g. someEnum.key + if (isIdentifier && !computed) { + return (enumNode.property as Identifier).name; + } + // E.g. someEnum["key"] + if (enumNode.property.type === "Literal") { + return enumNode.property.value as string; + } +} 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 342f505c..1bdd9b08 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/helpers/index.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/index.ts @@ -8,6 +8,7 @@ export * from "./getChildJSXElementByName"; export * from "./getCodeModDataTag"; export * from "./getComponentImportName"; export * from "./getEndRange"; +export * from "./getEnumPropertyName"; export * from "./getFromPackage"; export * from "./getImportedName"; export * from "./getImportPath"; From 1d5507cbe123e0dc4ff28a151468e5aa4f6b3685 Mon Sep 17 00:00:00 2001 From: adamviktora Date: Wed, 30 Oct 2024 11:37:01 +0100 Subject: [PATCH 5/9] feat(helpers): update isEnumValue helper to support list of strings --- .../src/rules/helpers/isEnumValue.ts | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/packages/eslint-plugin-pf-codemods/src/rules/helpers/isEnumValue.ts b/packages/eslint-plugin-pf-codemods/src/rules/helpers/isEnumValue.ts index c158335a..398b0792 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/helpers/isEnumValue.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/isEnumValue.ts @@ -3,21 +3,31 @@ import { propertyNameMatches } from "./propertyNameMatches"; import { Rule } from "eslint"; /** Checks whether an enum node (MemberExpression), e.g. ButtonVariant["primary"] - * has a given enumName ("ButtonVariant") and a given propertyName ("primary") */ + * has a given enumName ("ButtonVariant") and a given propertyName ("primary"), or one of given property names. */ export function isEnumValue( context: Rule.RuleContext, enumExpression: MemberExpression, enumName: string, - propertyName: string + propertyName: string | string[] ) { - return ( + if ( enumExpression.object?.type === "Identifier" && - enumExpression.object.name === enumName && - propertyNameMatches( - context, - enumExpression.property, - enumExpression.computed, - propertyName - ) - ); + enumExpression.object.name === enumName + ) { + const nameMatches = (name: string) => + propertyNameMatches( + context, + enumExpression.property, + enumExpression.computed, + name + ); + + if (Array.isArray(propertyName)) { + return propertyName.some((name) => nameMatches(name)); + } + + return nameMatches(propertyName); + } + + return false; } From e9f85935a37e4fb8a7fff9e82b58f65996810666 Mon Sep 17 00:00:00 2001 From: adamviktora Date: Wed, 30 Oct 2024 11:40:50 +0100 Subject: [PATCH 6/9] feat(misc): don't use "any" type --- .../src/rules/helpers/isEnumValue.ts | 4 +- .../button-moveIcons-icon-prop.ts | 17 +++-- .../card-updated-clickable-markup.ts | 15 +++-- .../colorProps-replaced-colors.ts | 5 +- ...navailableContent-bodyText-props-update.ts | 8 ++- ...ntent-replace-noBackground-colorVariant.ts | 62 +++++++++++++------ .../pageSection-remove-nav-type.ts | 20 ++++-- .../pageSection-update-variant-values.ts | 46 +++++++++----- .../toolbarGroup-updated-variant.ts | 36 ++++++++--- .../toolbarItem-variant-prop-updates.ts | 24 +++++-- .../toolbar-replaced-spacer-spaceItems.ts | 14 ++++- .../toolbar-update-align-values.ts | 44 ++++++++----- 12 files changed, 209 insertions(+), 86 deletions(-) diff --git a/packages/eslint-plugin-pf-codemods/src/rules/helpers/isEnumValue.ts b/packages/eslint-plugin-pf-codemods/src/rules/helpers/isEnumValue.ts index 398b0792..f5cc0fad 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/helpers/isEnumValue.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/isEnumValue.ts @@ -11,8 +11,8 @@ export function isEnumValue( propertyName: string | string[] ) { if ( - enumExpression.object?.type === "Identifier" && - enumExpression.object.name === enumName + enumExpression?.object?.type === "Identifier" && + enumExpression?.object?.name === enumName ) { const nameMatches = (name: string) => propertyNameMatches( diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/buttonMoveIconsIconProp/button-moveIcons-icon-prop.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/buttonMoveIconsIconProp/button-moveIcons-icon-prop.ts index bb9c9d4b..0cd94bc5 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/buttonMoveIconsIconProp/button-moveIcons-icon-prop.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/buttonMoveIconsIconProp/button-moveIcons-icon-prop.ts @@ -1,5 +1,5 @@ import { Rule } from "eslint"; -import { JSXElement, JSXFragment } from "estree-jsx"; +import { JSXElement, JSXFragment, MemberExpression } from "estree-jsx"; import { childrenIsEmpty, getFromPackage, @@ -10,6 +10,8 @@ import { getChildJSXElementByName, isReactIcon, makeJSXElementSelfClosing, + propertyNameMatches, + isEnumValue, } from "../../helpers"; // https://github.com/patternfly/patternfly-react/pull/10663 @@ -47,11 +49,16 @@ module.exports = { variantProp?.value ); + const variantValueAsEnum = variantValue as MemberExpression; + const isEnumValuePlain = - buttonVariantEnumImport && - variantValue?.object?.name === - buttonVariantEnumImport.local.name && - variantValue?.property.name === "plain"; + !!buttonVariantEnumImport && + isEnumValue( + context, + variantValueAsEnum, + buttonVariantEnumImport.local.name, + "plain" + ); const isPlain = variantValue === "plain" || isEnumValuePlain; diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/cardUpdatedClickableMarkup/card-updated-clickable-markup.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/cardUpdatedClickableMarkup/card-updated-clickable-markup.ts index 5940c269..29972658 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/cardUpdatedClickableMarkup/card-updated-clickable-markup.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/cardUpdatedClickableMarkup/card-updated-clickable-markup.ts @@ -1,7 +1,6 @@ import { Rule } from "eslint"; -import { JSXElement, Property, Literal } from "estree-jsx"; +import { JSXElement, ObjectExpression, Property } from "estree-jsx"; import { - getAllImportsFromPackage, getFromPackage, checkMatchingJSXOpeningElement, getAttribute, @@ -54,19 +53,23 @@ module.exports = { const selectableActionsValue = getAttributeValue( context, selectableActionsProp.value - ); + ) as ObjectExpression["properties"]; if (!selectableActionsValue) { return; } + const selectableActionsProperties = selectableActionsValue.filter( + (val) => val.type === "Property" + ) as Property[]; + const nameProperty = getObjectProperty( context, - selectableActionsValue, + selectableActionsProperties, "name" ); const idProperty = getObjectProperty( context, - selectableActionsValue, + selectableActionsProperties, "selectableActionId" ); @@ -92,7 +95,7 @@ module.exports = { return []; } const propertiesToKeep = removePropertiesFromObjectExpression( - selectableActionsValue, + selectableActionsProperties, validPropertiesToRemove ); const replacementProperties = propertiesToKeep diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/colorPropsReplacedColors/colorProps-replaced-colors.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/colorPropsReplacedColors/colorProps-replaced-colors.ts index faa9e14f..b5753cbb 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/colorPropsReplacedColors/colorProps-replaced-colors.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/colorPropsReplacedColors/colorProps-replaced-colors.ts @@ -32,7 +32,10 @@ module.exports = { return; } - const colorValue = getAttributeValue(context, colorProp.value); + const colorValue = getAttributeValue( + context, + colorProp.value + ) as string; if (Object.keys(replacementMap).includes(colorValue)) { const newColorValue = replacementMap[colorValue]; const message = `The \`color\` prop on ${node.name.name} has been updated to replace "${colorValue}" with "${newColorValue}".`; diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/componentGroupsUnavailableContentBodyTextPropsUpdate/component-groups-unavailableContent-bodyText-props-update.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/componentGroupsUnavailableContentBodyTextPropsUpdate/component-groups-unavailableContent-bodyText-props-update.ts index 46d00c07..e0aa0abb 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/componentGroupsUnavailableContentBodyTextPropsUpdate/component-groups-unavailableContent-bodyText-props-update.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/componentGroupsUnavailableContentBodyTextPropsUpdate/component-groups-unavailableContent-bodyText-props-update.ts @@ -28,9 +28,11 @@ module.exports = { node, "statusPageLinkText" ); - const statusPageLinkTextString: string = - getAttributeValue(context, statusPageLinkTextProp?.value) ?? - "status page"; + const statusPageLinkTextString = + (getAttributeValue( + context, + statusPageLinkTextProp?.value + ) as string) ?? "status page"; if (statusPageLinkTextProp && statusPageLinkTextString.length) { const firstChar = statusPageLinkTextString.charAt(0); diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/drawerContentReplaceNoBackgroundColorVariant/drawerContent-replace-noBackground-colorVariant.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/drawerContentReplaceNoBackgroundColorVariant/drawerContent-replace-noBackground-colorVariant.ts index 7cca1076..4c0a4c59 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/drawerContentReplaceNoBackgroundColorVariant/drawerContent-replace-noBackground-colorVariant.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/drawerContentReplaceNoBackgroundColorVariant/drawerContent-replace-noBackground-colorVariant.ts @@ -1,6 +1,12 @@ import { Rule } from "eslint"; -import { JSXOpeningElement } from "estree-jsx"; -import { getFromPackage, getAttribute, getAttributeValue } from "../../helpers"; +import { JSXOpeningElement, MemberExpression } from "estree-jsx"; +import { + getFromPackage, + getAttribute, + getAttributeValue, + isEnumValue, + getEnumPropertyName, +} from "../../helpers"; // https://github.com/patternfly/patternfly-react/pull/10211 module.exports = { @@ -38,18 +44,30 @@ module.exports = { context, colorVariantProp.value ); - const drawerColorVariantLocalName = - drawerColorVariantEnumImport && - drawerColorVariantEnumImport.local.name; + + const colorVariantValueAsEnum = + colorVariantValue as MemberExpression; + const hasPatternFlyEnum = - colorVariantValue && - colorVariantValue.object && - colorVariantValue.object.name === drawerColorVariantLocalName; + drawerColorVariantEnumImport && + colorVariantValueAsEnum && + colorVariantValueAsEnum.object && + context + .getSourceCode() + .getText(colorVariantValueAsEnum.object) === + drawerColorVariantEnumImport.local.name; + + const isNoBackgroundEnum = + !!drawerColorVariantEnumImport && + isEnumValue( + context, + colorVariantValueAsEnum, + drawerColorVariantEnumImport.local.name, + "noBackground" + ); + const hasNoBackgroundValue = - colorVariantValue && colorVariantValue.property - ? hasPatternFlyEnum && - colorVariantValue.property.name === "noBackground" - : colorVariantValue === "no-background"; + colorVariantValue === "no-background" || isNoBackgroundEnum; if (!hasPatternFlyEnum && !hasNoBackgroundValue) { return; @@ -68,15 +86,19 @@ module.exports = { } if (!hasNoBackgroundValue && hasPatternFlyEnum) { - const enumPropertyName = colorVariantValue.property.name; - fixes.push( - fixer.replaceText( - colorVariantProp, - validDrawerContentValues.includes(enumPropertyName) - ? `colorVariant="${colorVariantValue.property.name}"` - : "" - ) + const enumPropertyName = getEnumPropertyName( + context, + colorVariantValueAsEnum ); + enumPropertyName && + fixes.push( + fixer.replaceText( + colorVariantProp, + validDrawerContentValues.includes(enumPropertyName) + ? `colorVariant="${enumPropertyName}"` + : "" + ) + ); } return fixes; }, diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/pageSectionRemoveNavType/pageSection-remove-nav-type.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/pageSectionRemoveNavType/pageSection-remove-nav-type.ts index d3b588ab..c9e315fa 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/pageSectionRemoveNavType/pageSection-remove-nav-type.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/pageSectionRemoveNavType/pageSection-remove-nav-type.ts @@ -1,6 +1,11 @@ import { Rule } from "eslint"; -import { JSXOpeningElement } from "estree-jsx"; -import { getFromPackage, getAttribute, getAttributeValue } from "../../helpers"; +import { JSXOpeningElement, MemberExpression } from "estree-jsx"; +import { + getFromPackage, + getAttribute, + getAttributeValue, + isEnumValue, +} from "../../helpers"; // https://github.com/patternfly/patternfly-react/pull/10650 module.exports = { @@ -29,10 +34,17 @@ module.exports = { } const typeValue = getAttributeValue(context, typeProp.value); + const typeValueAsEnum = typeValue as MemberExpression; + const isEnumValueNav = pageSectionTypeEnum && - typeValue.object?.name === pageSectionTypeEnum.local.name && - typeValue.property.name === "nav"; + isEnumValue( + context, + typeValueAsEnum, + pageSectionTypeEnum.local.name, + "nav" + ); + if (typeValue !== "nav" && !isEnumValueNav) { return; } diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/pageSectionUpdateVariantValues/pageSection-update-variant-values.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/pageSectionUpdateVariantValues/pageSection-update-variant-values.ts index 108d0b26..f86a5122 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/pageSectionUpdateVariantValues/pageSection-update-variant-values.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/pageSectionUpdateVariantValues/pageSection-update-variant-values.ts @@ -1,6 +1,12 @@ -import { getFromPackage, getAttribute, getAttributeValue } from "../../helpers"; +import { + getFromPackage, + getAttribute, + getAttributeValue, + isEnumValue, + attributeValueIsString, +} from "../../helpers"; import { Rule } from "eslint"; -import { JSXOpeningElement } from "estree-jsx"; +import { JSXOpeningElement, MemberExpression } from "estree-jsx"; // https://github.com/patternfly/patternfly-react/pull/9774 // https://github.com/patternfly/patternfly-react/pull/9848 @@ -34,21 +40,33 @@ module.exports = { context, variantProp.value ); - const pageSectionVariantLocalName = - pageSectionVariantImport && pageSectionVariantImport.local.name; + const variantValueAsEnum = variantValue as MemberExpression; + const hasPatternFlyEnum = - variantValue?.object && - variantValue.object.name === pageSectionVariantLocalName; - const variantValueIsLiteral = - variantProp.value.type === "Literal" || - (variantProp.value.type === "JSXExpressionContainer" && - variantProp.value.expression.type === "Literal"); - if (!variantValueIsLiteral && !hasPatternFlyEnum) { + pageSectionVariantImport && + variantValueAsEnum?.object && + context.getSourceCode().getText(variantValueAsEnum.object) === + pageSectionVariantImport.local.name; + + if ( + !attributeValueIsString(variantProp.value) && + !hasPatternFlyEnum + ) { return; } - const hasValidValue = variantValue?.property - ? validValues.includes(variantValue.property.name) - : validValues.includes(variantValue); + + const isValidEnumValue = + pageSectionVariantImport && + isEnumValue( + context, + variantValueAsEnum, + pageSectionVariantImport.local.name, + validValues + ); + + const hasValidValue = + isValidEnumValue || + validValues.includes(variantValue as string); if (!hasValidValue) { context.report({ diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarGroupUpdatedIconButtonGroupVariant/toolbarGroup-updated-variant.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarGroupUpdatedIconButtonGroupVariant/toolbarGroup-updated-variant.ts index 5129fac9..e8daa9bc 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarGroupUpdatedIconButtonGroupVariant/toolbarGroup-updated-variant.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarGroupUpdatedIconButtonGroupVariant/toolbarGroup-updated-variant.ts @@ -1,6 +1,12 @@ import { Rule } from "eslint"; -import { JSXOpeningElement } from "estree-jsx"; -import { getFromPackage, getAttribute, getAttributeValue } from "../../helpers"; +import { JSXOpeningElement, MemberExpression } from "estree-jsx"; +import { + getFromPackage, + getAttribute, + getAttributeValue, + getEnumPropertyName, + isEnumValue, +} from "../../helpers"; // https://github.com/patternfly/patternfly-react/pull/10674 module.exports = { @@ -20,6 +26,7 @@ module.exports = { "icon-button-group": "action-group-plain", }; const oldVariantNames = Object.keys(renames); + type OldVariantType = "button-group" | "icon-button-group"; return !componentImports.length ? {} @@ -38,24 +45,37 @@ module.exports = { } const variantValue = getAttributeValue(context, variant.value); + const variantValueAsEnum = variantValue as MemberExpression; + const isEnumToRename = variantEnumImport && - variantValue.object?.name === variantEnumImport.local.name && - oldVariantNames.includes(variantValue.property.value); + isEnumValue( + context, + variantValueAsEnum, + variantEnumImport.local.name, + oldVariantNames + ); - if (!oldVariantNames.includes(variantValue) && !isEnumToRename) { + if ( + !oldVariantNames.includes(variantValue as string) && + !isEnumToRename + ) { return; } - const variantToRename: "button-group" | "icon-button-group" = - variantValue.property?.value ?? variantValue; + const variantToRename = isEnumToRename + ? (getEnumPropertyName( + context, + variantValueAsEnum + ) as OldVariantType) + : (variantValue as OldVariantType); context.report({ node, message: `The \`${variantToRename}\` variant of ${applicableComponent.imported.name} has been renamed to \`${renames[variantToRename]}\`.`, fix(fixer) { return fixer.replaceText( - isEnumToRename ? variantValue.property : variant, + isEnumToRename ? variantValueAsEnum.property : variant, isEnumToRename ? `"${renames[variantToRename]}"` : `variant="${renames[variantToRename]}"` diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarItemVariantPropUpdates/toolbarItem-variant-prop-updates.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarItemVariantPropUpdates/toolbarItem-variant-prop-updates.ts index ccd82f0c..f141cb72 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarItemVariantPropUpdates/toolbarItem-variant-prop-updates.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarItemVariantPropUpdates/toolbarItem-variant-prop-updates.ts @@ -10,6 +10,8 @@ import { getAttribute, getAttributeValue, attributeValueIsString, + getEnumPropertyName, + isEnumValue, } from "../../helpers"; // https://github.com/patternfly/patternfly-react/pull/10649 @@ -76,14 +78,26 @@ module.exports = { variant.value ); + const isEnumToRemove = + enumImport && + isEnumValue( + context, + variantValue as MemberExpression, + enumImport.local.name, + variantsToRemove + ); + if ( (variantValueIsLiteral && - variantsToRemove.includes(variantValue)) || - (nodeIsEnum(variantValue) && - variantsToRemove.includes(variantValue.property.value)) + variantsToRemove.includes(variantValue as string)) || + isEnumToRemove ) { - const variantToRemove = - variantValue.property?.value ?? variantValue; + const variantToRemove = isEnumToRemove + ? getEnumPropertyName( + context, + variantValue as MemberExpression + ) + : variantValue; context.report({ node, 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 index f3183846..960f017b 100644 --- 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 @@ -1,5 +1,5 @@ import { Rule } from "eslint"; -import { JSXOpeningElement } from "estree-jsx"; +import { JSXOpeningElement, ObjectExpression } from "estree-jsx"; import { Property } from "estree-jsx"; import { getFromPackage, getAttribute, getAttributeValue } from "../../helpers"; @@ -35,7 +35,11 @@ module.exports = { spacerProp ? " Additionally, the" : "The" } spaceItems property has been removed from ${node.name.name}.`; const spacerVal = - spacerProp && getAttributeValue(context, spacerProp.value); + spacerProp && + (getAttributeValue( + context, + spacerProp.value + ) as ObjectExpression["properties"]); context.report({ node, @@ -47,7 +51,11 @@ module.exports = { if (spacerProp) { spacerVal && - spacerVal.forEach((val: Property) => { + spacerVal.forEach((val) => { + if (val.type !== "Property") { + return; + } + const newValue = val.value?.type === "Literal" && (val.value.value as string).replace("spacer", "gap"); diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarUpdateAlignValues/toolbar-update-align-values.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarUpdateAlignValues/toolbar-update-align-values.ts index 03b53182..8d39365c 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarUpdateAlignValues/toolbar-update-align-values.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarUpdateAlignValues/toolbar-update-align-values.ts @@ -1,5 +1,10 @@ import { Rule } from "eslint"; -import { JSXOpeningElement, Property } from "estree-jsx"; +import { + Identifier, + JSXOpeningElement, + ObjectExpression, + Property, +} from "estree-jsx"; import { getFromPackage, getAttribute, getAttributeValue } from "../../helpers"; const componentsPropMap: { [key: string]: string } = { @@ -47,15 +52,20 @@ module.exports = { return; } - const attributeValue = getAttributeValue( - context, - attribute.value - ); + const attributeValueProperties = ( + getAttributeValue( + context, + attribute.value + ) as ObjectExpression["properties"] + ).filter((prop) => prop.type === "Property") as Property[]; if ( - attributeValue.every( - (property: Property) => - property.value.type === "Literal" && - !oldPropValues.includes(property.value.value as string) + attributeValueProperties.every( + (property) => + (property.value.type === "Literal" && + !oldPropValues.includes( + property.value.value as string + )) || + property.value.type !== "Literal" ) ) { return; @@ -67,18 +77,22 @@ module.exports = { fix(fixer) { const fixes = []; - for (const property of attributeValue) { - if (oldPropValues.includes(property.value.value)) { + for (const property of attributeValueProperties) { + if (property.value.type !== "Literal") { + continue; + } + + const propertyValueString = property.value.value as string; + + if (oldPropValues.includes(propertyValueString)) { const propertyKeyValue = property.key.type === "Literal" ? `"${property.key.value}"` - : property.key.name; + : (property.key as Identifier).name; fixes.push( fixer.replaceText( property, - `${propertyKeyValue}: "${ - newPropValueMap[property.value.value] - }"` + `${propertyKeyValue}: "${newPropValueMap[propertyValueString]}"` ) ); } From 72f488f4712c3ad9963a012fd009bfb453a88db3 Mon Sep 17 00:00:00 2001 From: adamviktora Date: Tue, 12 Nov 2024 13:40:01 +0100 Subject: [PATCH 7/9] fix(misc): get rid of type casting / explain type casting --- .../src/rules/helpers/JSXAttributes.ts | 32 ++++++++++++------- .../src/rules/helpers/getEnumPropertyName.ts | 28 ++++++++-------- .../rules/helpers/getNodeForAttributeFixer.ts | 4 +-- .../src/rules/helpers/propertyNameMatches.ts | 30 +++++++++-------- .../card-updated-clickable-markup.ts | 9 ++++-- .../toolbar-replaced-spacer-spaceItems.ts | 3 +- .../toolbar-update-align-values.ts | 20 ++++-------- 7 files changed, 66 insertions(+), 60 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 22ca349d..03c9cba7 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/helpers/JSXAttributes.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/JSXAttributes.ts @@ -6,8 +6,6 @@ import { JSXEmptyExpression, JSXFragment, JSXOpeningElement, - MemberExpression, - Property, } from "estree-jsx"; export function getAttribute( @@ -95,19 +93,29 @@ export function getVariableDeclaration( return undefined; } +export function getVariableInit( + variableDeclaration: Scope.Variable | undefined +) { + if (!variableDeclaration || !variableDeclaration.defs.length) { + return; + } + + const variableDefinition = variableDeclaration.defs[0]; + + if (variableDefinition.type !== "Variable") { + return; + } + + return variableDefinition.node.init; +} + export function getVariableValue( name: string, scope: Scope.Scope | null, context: Rule.RuleContext ) { const variableDeclaration = getVariableDeclaration(name, scope); - if (!variableDeclaration) { - return; - } - - const variableInit = variableDeclaration.defs.length - ? variableDeclaration.defs[0].node.init - : undefined; + const variableInit = getVariableInit(variableDeclaration); if (!variableInit) { return; @@ -120,12 +128,12 @@ export function getVariableValue( ); } if (variableInit.type === "Literal") { - return variableInit.value as string; + return variableInit.value; } if (variableInit.type === "MemberExpression") { - return variableInit as MemberExpression; + return variableInit; } if (variableInit.type === "ObjectExpression") { - return variableInit.properties as Property[]; + return variableInit.properties; } } diff --git a/packages/eslint-plugin-pf-codemods/src/rules/helpers/getEnumPropertyName.ts b/packages/eslint-plugin-pf-codemods/src/rules/helpers/getEnumPropertyName.ts index c4b2e0e8..3970f5d0 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/helpers/getEnumPropertyName.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/getEnumPropertyName.ts @@ -1,28 +1,26 @@ import { Rule } from "eslint"; -import { Identifier, MemberExpression } from "estree-jsx"; -import { getVariableDeclaration } from "."; +import { MemberExpression } from "estree-jsx"; +import { getVariableValue } from "."; /** Used to get a property name on an enum (MemberExpression). */ export function getEnumPropertyName( context: Rule.RuleContext, enumNode: MemberExpression ) { - const isIdentifier = enumNode.property.type === "Identifier"; - const computed = enumNode.computed; + if (enumNode.property.type === "Identifier") { + // E.g. const key = "key"; someEnum[key] + if (enumNode.computed) { + const scope = context.getSourceCode().getScope(enumNode); + const propertyName = enumNode.property.name; - // E.g. const key = "key"; someEnum[key] - if (isIdentifier && computed) { - const scope = context.getSourceCode().getScope(enumNode); - const propertyName = (enumNode.property as Identifier).name; - const propertyVariable = getVariableDeclaration(propertyName, scope); - return propertyVariable?.defs[0].node.init.value as string; - } - // E.g. someEnum.key - if (isIdentifier && !computed) { - return (enumNode.property as Identifier).name; + return getVariableValue(propertyName, scope, context)?.toString(); + } + // E.g. someEnum.key + return enumNode.property.name; } + // E.g. someEnum["key"] if (enumNode.property.type === "Literal") { - return enumNode.property.value as string; + return enumNode.property.value?.toString(); } } diff --git a/packages/eslint-plugin-pf-codemods/src/rules/helpers/getNodeForAttributeFixer.ts b/packages/eslint-plugin-pf-codemods/src/rules/helpers/getNodeForAttributeFixer.ts index 2c72749d..0113d143 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/helpers/getNodeForAttributeFixer.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/getNodeForAttributeFixer.ts @@ -1,6 +1,6 @@ import { Rule } from "eslint"; import { JSXAttribute } from "estree-jsx"; -import { getVariableDeclaration } from "./JSXAttributes"; +import { getVariableDeclaration, getVariableInit } from "./JSXAttributes"; /** Used to find the node where a prop value is initially assigned, to then be passed * as a fixer function's nodeOrToken argument. Useful for when a prop may have an inline value, e.g. ``, or @@ -41,6 +41,6 @@ function getJSXExpressionContainerValue( scope ); - return variableDeclaration && variableDeclaration.defs[0].node.init; + return getVariableInit(variableDeclaration); } } diff --git a/packages/eslint-plugin-pf-codemods/src/rules/helpers/propertyNameMatches.ts b/packages/eslint-plugin-pf-codemods/src/rules/helpers/propertyNameMatches.ts index abc549df..22353a39 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/helpers/propertyNameMatches.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/propertyNameMatches.ts @@ -1,6 +1,6 @@ import { Rule } from "eslint"; -import { Expression, Identifier, PrivateIdentifier } from "estree-jsx"; -import { getVariableDeclaration } from "./JSXAttributes"; +import { Expression, PrivateIdentifier } from "estree-jsx"; +import { getVariableValue } from "./JSXAttributes"; /** Check whether a property name is of a given value. * Property can either be of an ObjectExpression - {propName: "value"} or MemberExpression - someObject.propName */ @@ -10,19 +10,23 @@ export function propertyNameMatches( computed: boolean, name: string ) { - const isIdentifier = key.type === "Identifier"; + if (key.type === "Identifier") { + // E.g. const key = "key"; {[key]: value}; someObject[key] + if (computed) { + const scope = context.getSourceCode().getScope(key); + const propertyName = key.name; + const propertyVariableValue = getVariableValue( + propertyName, + scope, + context + ); - // E.g. const key = "key"; {[key]: value}; someObject[key] - if (isIdentifier && computed) { - const scope = context.getSourceCode().getScope(key); - const propertyName = (key as Identifier).name; - const propertyVariable = getVariableDeclaration(propertyName, scope); - return propertyVariable?.defs[0].node.init.value === name; - } - // E.g. {key: value}; someObject.key - if (isIdentifier && !computed) { - return (key as Identifier).name === name; + return propertyVariableValue === name; + } + // E.g. {key: value}; someObject.key + return key.name === name; } + // E.g. {"key": value} or {["key"]: value}; someObject["key"] if (key.type === "Literal") { return key.value === name; diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/cardUpdatedClickableMarkup/card-updated-clickable-markup.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/cardUpdatedClickableMarkup/card-updated-clickable-markup.ts index 29972658..8c326b96 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/cardUpdatedClickableMarkup/card-updated-clickable-markup.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/cardUpdatedClickableMarkup/card-updated-clickable-markup.ts @@ -53,7 +53,7 @@ module.exports = { const selectableActionsValue = getAttributeValue( context, selectableActionsProp.value - ) as ObjectExpression["properties"]; + ) as ObjectExpression["properties"]; // selectableActions prop on CardHeader accepts an object if (!selectableActionsValue) { return; } @@ -99,7 +99,7 @@ module.exports = { validPropertiesToRemove ); const replacementProperties = propertiesToKeep - .map((property: Property) => + .map((property) => context.getSourceCode().getText(property) ) .join(", "); @@ -108,6 +108,11 @@ module.exports = { context, selectableActionsProp ); + + if (!nodeToUpdate) { + return []; + } + return fixer.replaceText( nodeToUpdate, propertiesToKeep.length 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 index 960f017b..9cb2896a 100644 --- 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 @@ -1,6 +1,5 @@ import { Rule } from "eslint"; import { JSXOpeningElement, ObjectExpression } from "estree-jsx"; -import { Property } from "estree-jsx"; import { getFromPackage, getAttribute, getAttributeValue } from "../../helpers"; // https://github.com/patternfly/patternfly-react/pull/10418 @@ -39,7 +38,7 @@ module.exports = { (getAttributeValue( context, spacerProp.value - ) as ObjectExpression["properties"]); + ) as ObjectExpression["properties"]); // spacer prop on Toolbar[Component] accepts an object context.report({ node, diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarUpdateAlignValues/toolbar-update-align-values.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarUpdateAlignValues/toolbar-update-align-values.ts index 8d39365c..3caa5dbe 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarUpdateAlignValues/toolbar-update-align-values.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarUpdateAlignValues/toolbar-update-align-values.ts @@ -1,10 +1,5 @@ import { Rule } from "eslint"; -import { - Identifier, - JSXOpeningElement, - ObjectExpression, - Property, -} from "estree-jsx"; +import { JSXOpeningElement, ObjectExpression, Property } from "estree-jsx"; import { getFromPackage, getAttribute, getAttributeValue } from "../../helpers"; const componentsPropMap: { [key: string]: string } = { @@ -57,7 +52,8 @@ module.exports = { context, attribute.value ) as ObjectExpression["properties"] - ).filter((prop) => prop.type === "Property") as Property[]; + ) // align prop on Toolbar[Component] accepts an object + .filter((prop) => prop.type === "Property") as Property[]; if ( attributeValueProperties.every( (property) => @@ -82,17 +78,13 @@ module.exports = { continue; } - const propertyValueString = property.value.value as string; + const propertyValueString = property.value.value as string; // value is expected to be "alignLeft" or "alignRight" if (oldPropValues.includes(propertyValueString)) { - const propertyKeyValue = - property.key.type === "Literal" - ? `"${property.key.value}"` - : (property.key as Identifier).name; fixes.push( fixer.replaceText( - property, - `${propertyKeyValue}: "${newPropValueMap[propertyValueString]}"` + property.value, + `"${newPropValueMap[propertyValueString]}"` ) ); } From 7379068b6a02014e554a721c7bd97839d401a3f1 Mon Sep 17 00:00:00 2001 From: adamviktora Date: Mon, 13 Jan 2025 16:43:04 +0100 Subject: [PATCH 8/9] refactor: change getAttributeValue return type --- .../src/rules/helpers/JSXAttributes.ts | 67 +++++++++++++++---- .../src/rules/helpers/getEnumPropertyName.ts | 2 +- .../src/rules/helpers/propertyNameMatches.ts | 2 +- .../banner-replace-variantProp.ts | 2 +- .../button-moveIcons-icon-prop.ts | 44 +++++++----- .../card-updated-clickable-markup.ts | 11 +-- .../colorProps-replaced-colors.ts | 6 +- ...navailableContent-bodyText-props-update.ts | 23 +++++-- ...ntent-replace-noBackground-colorVariant.ts | 25 +++---- .../kebabToggle-replace-with-menuToggle.ts | 3 +- .../pageSection-remove-nav-type.ts | 11 +-- .../pageSection-update-variant-values.ts | 24 ++++--- .../toolbarGroup-updated-variant.ts | 20 ++++-- .../toolbarItem-variant-prop-updates.ts | 22 +++--- .../toolbar-replaced-spacer-spaceItems.ts | 50 ++++++++------ .../toolbar-update-align-values.ts | 20 +++--- .../wizardNavItem-warn-update-markup.ts | 3 +- .../wizardStep-updated-body-typing.ts | 5 +- 18 files changed, 216 insertions(+), 124 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 03c9cba7..e891fe39 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/helpers/JSXAttributes.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/JSXAttributes.ts @@ -6,6 +6,9 @@ import { JSXEmptyExpression, JSXFragment, JSXOpeningElement, + MemberExpression, + Property, + SpreadElement, } from "estree-jsx"; export function getAttribute( @@ -34,22 +37,47 @@ export function getAnyAttribute( return foundAttribute; } +/** + * Attribute value and its type + */ +type Attribute = + | { type: "string"; value: string } + | { + type: "Literal"; + value: string | number | bigint | boolean | RegExp | null | undefined; + } + | { type: "MemberExpression"; value: MemberExpression } + | { type: "ObjectExpression"; value: (Property | SpreadElement)[] } + | { type: "undefined"; value: undefined }; + +const UNDEFINED: Attribute = { type: "undefined", value: undefined }; + +/** + * Helper to get the raw value from a JSXAttribute value. If the JSXAttribute value is an Identifier, it tries to get the value of that variable. If the JSXAttribute value is a JSXExpressionContainer: {"value"}, it returns the inner content. + * MemberExpressions and ObjectExpressions are not parsed further. + * @param context Rule context + * @param node JSXAttribute value + * @returns Attribute in this form: { type: [specific type of the returned value], value: [actual value]}. Literal types are further processed, if their value is of type "string", type: "string" is returned, otherwise type: "Literal" + */ export function getAttributeValue( context: Rule.RuleContext, node?: JSXAttribute["value"] -) { +): Attribute { if (!node) { - return; + return UNDEFINED; } const valueType = node.type; if (valueType === "Literal") { - return node.value; + if (typeof node.value === "string") { + return { type: "string", value: node.value }; + } + return { type: "Literal", value: node.value }; } if (valueType !== "JSXExpressionContainer") { - return; + return UNDEFINED; } if (node.expression.type === "Identifier") { @@ -57,14 +85,18 @@ export function getAttributeValue( return getVariableValue(node.expression.name, variableScope, context); } if (node.expression.type === "MemberExpression") { - return node.expression; + return { type: "MemberExpression", value: node.expression }; } if (node.expression.type === "Literal") { - return node.expression.value; + if (typeof node.expression.value === "string") { + return { type: "string", value: node.expression.value }; + } + return { type: "Literal", value: node.expression.value }; } if (node.expression.type === "ObjectExpression") { - return node.expression.properties; + return { type: "ObjectExpression", value: node.expression.properties }; } + return UNDEFINED; } export function getExpression(node?: JSXAttribute["value"]) { @@ -109,16 +141,23 @@ export function getVariableInit( return variableDefinition.node.init; } +/** + * Helper to get the raw value of a variable, given by its name. Returns an Attribute object, similarly to getAttributeValue helper. + * @param name Variable name + * @param scope Scope where to look for the variable declaration + * @param context Rule context + * @returns Attribute in this form: { type: [specific type of the returned value], value: [actual value]}. Literal types are further processed, if their value is of type "string", type: "string" is returned, otherwise type: "Literal" + */ export function getVariableValue( name: string, scope: Scope.Scope | null, context: Rule.RuleContext -) { +): Attribute { const variableDeclaration = getVariableDeclaration(name, scope); const variableInit = getVariableInit(variableDeclaration); if (!variableInit) { - return; + return UNDEFINED; } if (variableInit.type === "Identifier") { return getVariableValue( @@ -128,12 +167,16 @@ export function getVariableValue( ); } if (variableInit.type === "Literal") { - return variableInit.value; + if (typeof variableInit.value === "string") { + return { type: "string", value: variableInit.value }; + } + return { type: "Literal", value: variableInit.value }; } if (variableInit.type === "MemberExpression") { - return variableInit; + return { type: "MemberExpression", value: variableInit }; } if (variableInit.type === "ObjectExpression") { - return variableInit.properties; + return { type: "ObjectExpression", value: variableInit.properties }; } + return UNDEFINED; } diff --git a/packages/eslint-plugin-pf-codemods/src/rules/helpers/getEnumPropertyName.ts b/packages/eslint-plugin-pf-codemods/src/rules/helpers/getEnumPropertyName.ts index 3970f5d0..0e939295 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/helpers/getEnumPropertyName.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/getEnumPropertyName.ts @@ -13,7 +13,7 @@ export function getEnumPropertyName( const scope = context.getSourceCode().getScope(enumNode); const propertyName = enumNode.property.name; - return getVariableValue(propertyName, scope, context)?.toString(); + return getVariableValue(propertyName, scope, context).value?.toString(); } // E.g. someEnum.key return enumNode.property.name; diff --git a/packages/eslint-plugin-pf-codemods/src/rules/helpers/propertyNameMatches.ts b/packages/eslint-plugin-pf-codemods/src/rules/helpers/propertyNameMatches.ts index 22353a39..521a565f 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/helpers/propertyNameMatches.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/propertyNameMatches.ts @@ -19,7 +19,7 @@ export function propertyNameMatches( propertyName, scope, context - ); + ).value; return propertyVariableValue === name; } diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/bannerReplaceVariantProp/banner-replace-variantProp.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/bannerReplaceVariantProp/banner-replace-variantProp.ts index 9a67ec9e..4289f6e2 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/bannerReplaceVariantProp/banner-replace-variantProp.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/bannerReplaceVariantProp/banner-replace-variantProp.ts @@ -27,7 +27,7 @@ module.exports = { const attributeValue = getAttributeValue( context, attribute.value - ); + ).value; const isValueDefault = attributeValue === "default"; const fixMessage = isValueDefault ? "remove the variant property" diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/buttonMoveIconsIconProp/button-moveIcons-icon-prop.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/buttonMoveIconsIconProp/button-moveIcons-icon-prop.ts index 0cd94bc5..1e3cb877 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/buttonMoveIconsIconProp/button-moveIcons-icon-prop.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/buttonMoveIconsIconProp/button-moveIcons-icon-prop.ts @@ -1,5 +1,5 @@ import { Rule } from "eslint"; -import { JSXElement, JSXFragment, MemberExpression } from "estree-jsx"; +import { JSXElement, JSXFragment } from "estree-jsx"; import { childrenIsEmpty, getFromPackage, @@ -10,7 +10,6 @@ import { getChildJSXElementByName, isReactIcon, makeJSXElementSelfClosing, - propertyNameMatches, isEnumValue, } from "../../helpers"; @@ -39,28 +38,39 @@ module.exports = { node.openingElement.name.type === "JSXIdentifier" && buttonImport.local.name === node.openingElement.name.name ) { - const variantProp = getAttribute(node.openingElement, "variant"); const iconProp = getAttribute(node.openingElement, "icon"); if (iconProp) { return; } - const variantValue = getAttributeValue( - context, - variantProp?.value - ); - - const variantValueAsEnum = variantValue as MemberExpression; - const isEnumValuePlain = - !!buttonVariantEnumImport && - isEnumValue( - context, - variantValueAsEnum, - buttonVariantEnumImport.local.name, - "plain" + const isPlainVariant = () => { + const variantProp = getAttribute( + node.openingElement, + "variant" ); + const { value: variantValue, type: variantValueType } = + getAttributeValue(context, variantProp?.value); + + if (variantValue === "plain") { + return true; + } + + if (variantValueType === "MemberExpression") { + return ( + !!buttonVariantEnumImport && + isEnumValue( + context, + variantValue, + buttonVariantEnumImport.local.name, + "plain" + ) + ); + } + + return false; + }; - const isPlain = variantValue === "plain" || isEnumValuePlain; + const isPlain = isPlainVariant(); let plainButtonChildrenString: string | undefined; let nodeWithChildren: JSXElement | JSXFragment = node; diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/cardUpdatedClickableMarkup/card-updated-clickable-markup.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/cardUpdatedClickableMarkup/card-updated-clickable-markup.ts index 8c326b96..bdf49e91 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/cardUpdatedClickableMarkup/card-updated-clickable-markup.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/cardUpdatedClickableMarkup/card-updated-clickable-markup.ts @@ -50,11 +50,12 @@ module.exports = { if (!cardHeaderChild || !selectableActionsProp) { return; } - const selectableActionsValue = getAttributeValue( - context, - selectableActionsProp.value - ) as ObjectExpression["properties"]; // selectableActions prop on CardHeader accepts an object - if (!selectableActionsValue) { + const { + value: selectableActionsValue, + type: selectableActionsValueType, + } = getAttributeValue(context, selectableActionsProp.value); + // selectableActions prop on CardHeader accepts an object + if (selectableActionsValueType !== "ObjectExpression") { return; } diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/colorPropsReplacedColors/colorProps-replaced-colors.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/colorPropsReplacedColors/colorProps-replaced-colors.ts index b5753cbb..971cc9b2 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/colorPropsReplacedColors/colorProps-replaced-colors.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/colorPropsReplacedColors/colorProps-replaced-colors.ts @@ -2,7 +2,7 @@ import { Rule } from "eslint"; import { JSXOpeningElement } from "estree-jsx"; import { getFromPackage, getAttribute, getAttributeValue } from "../../helpers"; -const replacementMap: { [key: string]: string } = { +const replacementMap = { cyan: "teal", gold: "yellow", }; @@ -35,8 +35,8 @@ module.exports = { const colorValue = getAttributeValue( context, colorProp.value - ) as string; - if (Object.keys(replacementMap).includes(colorValue)) { + ).value; + if (colorValue === "cyan" || colorValue === "gold") { const newColorValue = replacementMap[colorValue]; const message = `The \`color\` prop on ${node.name.name} has been updated to replace "${colorValue}" with "${newColorValue}".`; context.report({ diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/componentGroupsUnavailableContentBodyTextPropsUpdate/component-groups-unavailableContent-bodyText-props-update.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/componentGroupsUnavailableContentBodyTextPropsUpdate/component-groups-unavailableContent-bodyText-props-update.ts index e0aa0abb..693aed80 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/componentGroupsUnavailableContentBodyTextPropsUpdate/component-groups-unavailableContent-bodyText-props-update.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/componentGroupsUnavailableContentBodyTextPropsUpdate/component-groups-unavailableContent-bodyText-props-update.ts @@ -28,13 +28,22 @@ module.exports = { node, "statusPageLinkText" ); + + const { + type: statusPageLinkTextPropType, + value: statusPageLinkTextPropValue, + } = getAttributeValue(context, statusPageLinkTextProp?.value); + const statusPageLinkTextString = - (getAttributeValue( - context, - statusPageLinkTextProp?.value - ) as string) ?? "status page"; + statusPageLinkTextPropType === "string" + ? statusPageLinkTextPropValue + : "status page"; - if (statusPageLinkTextProp && statusPageLinkTextString.length) { + if ( + statusPageLinkTextProp && + statusPageLinkTextPropType === "string" && + statusPageLinkTextString.length + ) { const firstChar = statusPageLinkTextString.charAt(0); if (firstChar !== firstChar.toUpperCase()) { @@ -68,10 +77,10 @@ module.exports = { } const preStatusLinkTextString = - getAttributeValue(context, preStatusLinkTextProp?.value) ?? + getAttributeValue(context, preStatusLinkTextProp?.value).value ?? "Try refreshing the page. If the problem persists, contact your organization administrator or visit our"; const postStatusLinkTextString = - getAttributeValue(context, postStatusLinkTextProp?.value) ?? + getAttributeValue(context, postStatusLinkTextProp?.value).value ?? "for known outages."; const bodyTextAttribute = `bodyText="${preStatusLinkTextString} ${statusPageLinkTextString} ${postStatusLinkTextString}"`; diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/drawerContentReplaceNoBackgroundColorVariant/drawerContent-replace-noBackground-colorVariant.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/drawerContentReplaceNoBackgroundColorVariant/drawerContent-replace-noBackground-colorVariant.ts index 4c0a4c59..9b830c27 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/drawerContentReplaceNoBackgroundColorVariant/drawerContent-replace-noBackground-colorVariant.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/drawerContentReplaceNoBackgroundColorVariant/drawerContent-replace-noBackground-colorVariant.ts @@ -1,5 +1,5 @@ import { Rule } from "eslint"; -import { JSXOpeningElement, MemberExpression } from "estree-jsx"; +import { JSXOpeningElement } from "estree-jsx"; import { getFromPackage, getAttribute, @@ -45,29 +45,30 @@ module.exports = { colorVariantProp.value ); - const colorVariantValueAsEnum = - colorVariantValue as MemberExpression; + const colorVariantValueEnum = + colorVariantValue?.type === "MemberExpression" + ? colorVariantValue.value + : null; const hasPatternFlyEnum = drawerColorVariantEnumImport && - colorVariantValueAsEnum && - colorVariantValueAsEnum.object && - context - .getSourceCode() - .getText(colorVariantValueAsEnum.object) === + colorVariantValueEnum && + colorVariantValueEnum.object && + context.getSourceCode().getText(colorVariantValueEnum.object) === drawerColorVariantEnumImport.local.name; const isNoBackgroundEnum = - !!drawerColorVariantEnumImport && + hasPatternFlyEnum && isEnumValue( context, - colorVariantValueAsEnum, + colorVariantValueEnum, drawerColorVariantEnumImport.local.name, "noBackground" ); const hasNoBackgroundValue = - colorVariantValue === "no-background" || isNoBackgroundEnum; + colorVariantValue?.value === "no-background" || + isNoBackgroundEnum; if (!hasPatternFlyEnum && !hasNoBackgroundValue) { return; @@ -88,7 +89,7 @@ module.exports = { if (!hasNoBackgroundValue && hasPatternFlyEnum) { const enumPropertyName = getEnumPropertyName( context, - colorVariantValueAsEnum + colorVariantValueEnum ); enumPropertyName && fixes.push( diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/kebabToggleReplaceWithMenuToggle/kebabToggle-replace-with-menuToggle.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/kebabToggleReplaceWithMenuToggle/kebabToggle-replace-with-menuToggle.ts index c73ef38a..1e4027d3 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/kebabToggleReplaceWithMenuToggle/kebabToggle-replace-with-menuToggle.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/kebabToggleReplaceWithMenuToggle/kebabToggle-replace-with-menuToggle.ts @@ -102,7 +102,8 @@ module.exports = { const iconProp = getAttribute(node, "icon"); const variantProp = getAttribute(node, "variant"); const variantValue = - variantProp && getAttributeValue(context, variantProp.value); + variantProp && + getAttributeValue(context, variantProp.value).value; context.report({ node, diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/pageSectionRemoveNavType/pageSection-remove-nav-type.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/pageSectionRemoveNavType/pageSection-remove-nav-type.ts index c9e315fa..1ecbbb2b 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/pageSectionRemoveNavType/pageSection-remove-nav-type.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/pageSectionRemoveNavType/pageSection-remove-nav-type.ts @@ -1,5 +1,5 @@ import { Rule } from "eslint"; -import { JSXOpeningElement, MemberExpression } from "estree-jsx"; +import { JSXOpeningElement } from "estree-jsx"; import { getFromPackage, getAttribute, @@ -33,19 +33,20 @@ module.exports = { return; } - const typeValue = getAttributeValue(context, typeProp.value); - const typeValueAsEnum = typeValue as MemberExpression; + const { type: typePropType, value: typePropValue } = + getAttributeValue(context, typeProp.value); const isEnumValueNav = pageSectionTypeEnum && + typePropType === "MemberExpression" && isEnumValue( context, - typeValueAsEnum, + typePropValue, pageSectionTypeEnum.local.name, "nav" ); - if (typeValue !== "nav" && !isEnumValueNav) { + if (typePropValue !== "nav" && !isEnumValueNav) { return; } diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/pageSectionUpdateVariantValues/pageSection-update-variant-values.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/pageSectionUpdateVariantValues/pageSection-update-variant-values.ts index f86a5122..a7d08b0c 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/pageSectionUpdateVariantValues/pageSection-update-variant-values.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/pageSectionUpdateVariantValues/pageSection-update-variant-values.ts @@ -6,7 +6,7 @@ import { attributeValueIsString, } from "../../helpers"; import { Rule } from "eslint"; -import { JSXOpeningElement, MemberExpression } from "estree-jsx"; +import { JSXOpeningElement } from "estree-jsx"; // https://github.com/patternfly/patternfly-react/pull/9774 // https://github.com/patternfly/patternfly-react/pull/9848 @@ -36,16 +36,17 @@ module.exports = { if (!variantProp || !variantProp.value) { return; } - const variantValue = getAttributeValue( - context, - variantProp.value - ); - const variantValueAsEnum = variantValue as MemberExpression; + const { type: variantPropType, value: variantPropValue } = + getAttributeValue(context, variantProp.value); + const variantValueEnum = + variantPropType === "MemberExpression" + ? variantPropValue + : null; const hasPatternFlyEnum = pageSectionVariantImport && - variantValueAsEnum?.object && - context.getSourceCode().getText(variantValueAsEnum.object) === + variantValueEnum?.object && + context.getSourceCode().getText(variantValueEnum.object) === pageSectionVariantImport.local.name; if ( @@ -56,17 +57,18 @@ module.exports = { } const isValidEnumValue = - pageSectionVariantImport && + hasPatternFlyEnum && isEnumValue( context, - variantValueAsEnum, + variantValueEnum, pageSectionVariantImport.local.name, validValues ); const hasValidValue = isValidEnumValue || - validValues.includes(variantValue as string); + (variantPropType === "string" && + validValues.includes(variantPropValue)); if (!hasValidValue) { context.report({ diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarGroupUpdatedIconButtonGroupVariant/toolbarGroup-updated-variant.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarGroupUpdatedIconButtonGroupVariant/toolbarGroup-updated-variant.ts index e8daa9bc..4eb0bbdb 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarGroupUpdatedIconButtonGroupVariant/toolbarGroup-updated-variant.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarGroupUpdatedIconButtonGroupVariant/toolbarGroup-updated-variant.ts @@ -1,5 +1,5 @@ import { Rule } from "eslint"; -import { JSXOpeningElement, MemberExpression } from "estree-jsx"; +import { JSXOpeningElement } from "estree-jsx"; import { getFromPackage, getAttribute, @@ -44,20 +44,26 @@ module.exports = { return; } - const variantValue = getAttributeValue(context, variant.value); - const variantValueAsEnum = variantValue as MemberExpression; + const { value: variantValue, type: variantType } = + getAttributeValue(context, variant.value); + const variantValueEnum = + variantType === "MemberExpression" ? variantValue : null; const isEnumToRename = variantEnumImport && + variantValueEnum && isEnumValue( context, - variantValueAsEnum, + variantValueEnum, variantEnumImport.local.name, oldVariantNames ); if ( - !oldVariantNames.includes(variantValue as string) && + !( + variantType === "string" && + oldVariantNames.includes(variantValue) + ) && !isEnumToRename ) { return; @@ -66,7 +72,7 @@ module.exports = { const variantToRename = isEnumToRename ? (getEnumPropertyName( context, - variantValueAsEnum + variantValueEnum ) as OldVariantType) : (variantValue as OldVariantType); @@ -75,7 +81,7 @@ module.exports = { message: `The \`${variantToRename}\` variant of ${applicableComponent.imported.name} has been renamed to \`${renames[variantToRename]}\`.`, fix(fixer) { return fixer.replaceText( - isEnumToRename ? variantValueAsEnum.property : variant, + isEnumToRename ? variantValueEnum.property : variant, isEnumToRename ? `"${renames[variantToRename]}"` : `variant="${renames[variantToRename]}"` diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarItemVariantPropUpdates/toolbarItem-variant-prop-updates.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarItemVariantPropUpdates/toolbarItem-variant-prop-updates.ts index f141cb72..05538e20 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarItemVariantPropUpdates/toolbarItem-variant-prop-updates.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarItemVariantPropUpdates/toolbarItem-variant-prop-updates.ts @@ -72,31 +72,29 @@ module.exports = { return; } - const variantValue = getAttributeValue(context, variant.value); + const { type: variantType, value: variantValue } = + getAttributeValue(context, variant.value); - const variantValueIsLiteral = attributeValueIsString( - variant.value - ); + const variantValueEnum = + variantType === "MemberExpression" ? variantValue : null; const isEnumToRemove = enumImport && + variantValueEnum && isEnumValue( context, - variantValue as MemberExpression, + variantValueEnum, enumImport.local.name, variantsToRemove ); if ( - (variantValueIsLiteral && - variantsToRemove.includes(variantValue as string)) || + (variantType === "string" && + variantsToRemove.includes(variantValue)) || isEnumToRemove ) { const variantToRemove = isEnumToRemove - ? getEnumPropertyName( - context, - variantValue as MemberExpression - ) + ? getEnumPropertyName(context, variantValueEnum) : variantValue; context.report({ @@ -108,7 +106,7 @@ module.exports = { }); } - if (variantValueIsLiteral && variantValue === "chip-group") { + if (variantType === "string" && variantValue === "chip-group") { context.report({ node, message: 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 index 9cb2896a..5a1a162a 100644 --- 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 @@ -1,5 +1,5 @@ import { Rule } from "eslint"; -import { JSXOpeningElement, ObjectExpression } from "estree-jsx"; +import { JSXOpeningElement } from "estree-jsx"; import { getFromPackage, getAttribute, getAttributeValue } from "../../helpers"; // https://github.com/patternfly/patternfly-react/pull/10418 @@ -33,12 +33,23 @@ module.exports = { const spaceItemsPropMessage = `${ spacerProp ? " Additionally, the" : "The" } spaceItems property has been removed from ${node.name.name}.`; - const spacerVal = - spacerProp && - (getAttributeValue( + + const getSpacerValue = () => { + if (!spacerProp) { + return; + } + + const { type, value } = getAttributeValue( context, spacerProp.value - ) as ObjectExpression["properties"]); // spacer prop on Toolbar[Component] accepts an object + ); + + if (type !== "ObjectExpression") { + return; + } + + return value; + }; context.report({ node, @@ -48,22 +59,23 @@ module.exports = { fix(fixer) { const fixes = []; - if (spacerProp) { - spacerVal && - spacerVal.forEach((val) => { - if (val.type !== "Property") { - return; - } + const spacerVal = getSpacerValue(); + + if (spacerProp && spacerVal) { + spacerVal.forEach((val) => { + if (val.type !== "Property") { + return; + } - const newValue = - val.value?.type === "Literal" && - (val.value.value as string).replace("spacer", "gap"); + const newValue = + val.value?.type === "Literal" && + (val.value.value as string).replace("spacer", "gap"); - newValue && - fixes.push( - fixer.replaceText(val.value, `"${newValue}"`) - ); - }); + newValue && + fixes.push( + fixer.replaceText(val.value, `"${newValue}"`) + ); + }); fixes.push(fixer.replaceText(spacerProp.name, "gap")); } diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarUpdateAlignValues/toolbar-update-align-values.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarUpdateAlignValues/toolbar-update-align-values.ts index 3caa5dbe..608da185 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarUpdateAlignValues/toolbar-update-align-values.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/toolbarUpdateAlignValues/toolbar-update-align-values.ts @@ -1,5 +1,5 @@ import { Rule } from "eslint"; -import { JSXOpeningElement, ObjectExpression, Property } from "estree-jsx"; +import { JSXOpeningElement, Property } from "estree-jsx"; import { getFromPackage, getAttribute, getAttributeValue } from "../../helpers"; const componentsPropMap: { [key: string]: string } = { @@ -47,13 +47,17 @@ module.exports = { return; } - const attributeValueProperties = ( - getAttributeValue( - context, - attribute.value - ) as ObjectExpression["properties"] - ) // align prop on Toolbar[Component] accepts an object - .filter((prop) => prop.type === "Property") as Property[]; + const { type: attrValueType, value: attrValue } = + getAttributeValue(context, attribute.value); + + // align prop on Toolbar[Component] accepts an object + if (attrValueType !== "ObjectExpression") { + return; + } + + const attributeValueProperties = attrValue.filter( + (prop) => prop.type === "Property" + ) as Property[]; if ( attributeValueProperties.every( (property) => diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/wizardNavItemWarnUpdateMarkup/wizardNavItem-warn-update-markup.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/wizardNavItemWarnUpdateMarkup/wizardNavItem-warn-update-markup.ts index cb18af48..8d8c6e37 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/wizardNavItemWarnUpdateMarkup/wizardNavItem-warn-update-markup.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/wizardNavItemWarnUpdateMarkup/wizardNavItem-warn-update-markup.ts @@ -26,7 +26,8 @@ module.exports = { 'Additionally, when the nav item has a status of "error" the icon will be rendered before the item content, and the WizardToggle will also now render an error icon.'; const statusProp = getAttribute(node, "status"); const statusValue = - statusProp && getAttributeValue(context, statusProp.value); + statusProp && + getAttributeValue(context, statusProp.value).value; context.report({ node, diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/wizardStepUpdatedBodyTyping/wizardStep-updated-body-typing.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/wizardStepUpdatedBodyTyping/wizardStep-updated-body-typing.ts index b66f3ed7..d89550ab 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/wizardStepUpdatedBodyTyping/wizardStep-updated-body-typing.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/wizardStepUpdatedBodyTyping/wizardStep-updated-body-typing.ts @@ -24,7 +24,10 @@ module.exports = { if (!bodyProp) { return; } - const bodyValue = getAttributeValue(context, bodyProp.value); + const bodyValue = getAttributeValue( + context, + bodyProp.value + ).value; if (bodyValue === null) { context.report({ From e3881b37aca779bf99518337b60b6944c23cce37 Mon Sep 17 00:00:00 2001 From: adamviktora Date: Tue, 21 Jan 2025 17:21:09 +0100 Subject: [PATCH 9/9] fix: remove casting --- .../toolbar-replaced-spacer-spaceItems.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) 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 index 5a1a162a..c2dcba05 100644 --- 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 @@ -67,14 +67,18 @@ module.exports = { return; } - const newValue = + if ( val.value?.type === "Literal" && - (val.value.value as string).replace("spacer", "gap"); - - newValue && + typeof val.value.value === "string" + ) { + const newValue = val.value.value.replace( + "spacer", + "gap" + ); fixes.push( fixer.replaceText(val.value, `"${newValue}"`) ); + } }); fixes.push(fixer.replaceText(spacerProp.name, "gap"));