Skip to content

Commit

Permalink
feat(DrawerContent): removed no-background colorVariant (#629)
Browse files Browse the repository at this point in the history
* feat(DrawerContent): removed no-background colorVariant

* Updated logicals

* Suggested changes
  • Loading branch information
thatblindgeye authored Apr 23, 2024
1 parent 3d41fef commit fb7076c
Show file tree
Hide file tree
Showing 7 changed files with 322 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import { JSXElement, JSXAttribute } from "estree-jsx";
import { Rule, Scope } from "eslint";
import {
JSXElement,
JSXAttribute,
JSXOpeningElement,
MemberExpression,
} from "estree-jsx";

export function getAttribute(node: JSXElement, attributeName: string) {
return node.openingElement.attributes.find(
export function getAttribute(
node: JSXElement | JSXOpeningElement,
attributeName: string
) {
const nodeProperty = node.type === "JSXElement" ? node.openingElement : node;
return nodeProperty.attributes.find(
(attr) => attr.type === "JSXAttribute" && attr.name.name === attributeName
) as JSXAttribute | undefined;
}
Expand All @@ -15,3 +25,77 @@ export function getExpression(node?: JSXAttribute["value"]) {
return node.expression;
}
}

function getMemberExpression(node: MemberExpression) {
if (!node) {
return;
}
const { object, property } = node;

return { object, property };
}

export function getVariableDeclaration(
name: string,
scope: Scope.Scope | null
) {
while (scope !== null) {
const variable = scope.variables.find((v) => v.name === name);

if (variable) {
return variable;
}

scope = scope.upper;
}
return undefined;
}

export function getVariableValue(name: string, scope: Scope.Scope | null) {
const variableDeclaration = getVariableDeclaration(name, scope);

if (!variableDeclaration) {
return;
}

const variableInit = variableDeclaration.defs.length
? variableDeclaration.defs[0].node.init
: undefined;

if (!variableInit) {
return;
}
if (variableInit.type === "Literal") {
return variableInit.value;
}
if (variableInit.type === "MemberExpression") {
return getMemberExpression(variableInit);
}
}

export function getAttributeValue(
context: Rule.RuleContext,
node?: JSXAttribute["value"]
) {
if (!node) {
return;
}

const valueType = node.type;

if (valueType === "Literal") {
return node.value;
}

const isExpressionContainer = valueType === "JSXExpressionContainer";
if (isExpressionContainer && node.expression.type === "Identifier") {
const variableScope = context.getSourceCode().getScope(node);
return getVariableValue(node.expression.name, variableScope);
}
if (isExpressionContainer && node.expression.type === "MemberExpression") {
return getMemberExpression(node.expression);
}
if (isExpressionContainer && node.expression.type === "Literal") {
return node.expression.value;
}
}
16 changes: 2 additions & 14 deletions packages/eslint-plugin-pf-codemods/src/rules/helpers/helpers.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { getFromPackage } from './getFromPackage';
import { pfPackageMatches } from './pfPackageMatches';
import { findAncestor } from './findAncestor';
import { getVariableDeclaration } from './JSXAttributes';

const evk = require('eslint-visitor-keys');

Expand Down Expand Up @@ -492,7 +493,7 @@ export function addCallbackParam(
if (propProperties.type === 'ArrowFunctionExpression') {
propProperties.params = attribute.value?.expression?.params;
} else if (propProperties.type === 'Identifier') {
const matchingVariable = findVariableDeclaration(
const matchingVariable = getVariableDeclaration(
propProperties.name,
context.getSourceCode().getScope(node)
);
Expand Down Expand Up @@ -763,16 +764,3 @@ export function getAllJSXElements(context) {

return jsxElements;
}

export function findVariableDeclaration(name, scope) {
while (scope !== null) {
const variable = scope.variables.find((v) => v.name === name);

if (variable) {
return variable;
}

scope = scope.upper;
}
return undefined;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
### drawerContent-replace-noBackground-colorVariant [(#10211)](https://github.com/patternfly/patternfly-react/pull/10211)

The "no-background" value of the `colorVariant` prop on DrawerContent has been removed, and a new "primary" value has been added.

Additionally, a new DrawerContentColorVariant enum has been added and should be used instead of the DrawerColorVariant enum. The fix when the DrawerColorVariant enum is being used will replace the `colorVariant` prop value with a string.

#### Examples

In:

```jsx
%inputExample%
```

Out:

```jsx
%outputExample%
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
const ruleTester = require("../../ruletester");
import * as rule from "./drawerContent-replace-noBackground-colorVariant";

ruleTester.run("drawerContent-replace-noBackground-colorVariant", rule, {
valid: [
{
code: `<DrawerContent colorVariant="no-background" />`,
},
{
code: `<DrawerContent colorVariant={DrawerColorVariant.primary} />`,
},
{
code: `import { DrawerContent } from '@patternfly/react-core'; <DrawerContent colorVariant="primary" />`,
},
{
code: `import { DrawerContent, DrawerContentColorVariant } from '@patternfly/react-core'; <DrawerContent colorVariant={DrawerContentColorVariant.primary} />`,
},
{
code: `import { DrawerContent } from '@patternfly/react-core'; <DrawerContent colorVariant={DrawerColorVariant.primary} />`,
},
{
code: `import { DrawerContent } from '@patternfly/react-core'; <DrawerContent someOtherProp />`,
},
],
invalid: [
{
code: `import { DrawerContent } from '@patternfly/react-core'; <DrawerContent colorVariant="no-background" />`,
output: `import { DrawerContent } from '@patternfly/react-core'; <DrawerContent />`,
errors: [
{
message: `The "no-background" value of the \`colorVariant\` prop on DrawerContent has been removed.`,
type: "JSXOpeningElement",
},
],
},
{
code: `import { DrawerContent } from '@patternfly/react-core'; <DrawerContent colorVariant={"no-background"} />`,
output: `import { DrawerContent } from '@patternfly/react-core'; <DrawerContent />`,
errors: [
{
message: `The "no-background" value of the \`colorVariant\` prop on DrawerContent has been removed.`,
type: "JSXOpeningElement",
},
],
},
{
code: `import { DrawerContent } from '@patternfly/react-core'; const color = "no-background"; <DrawerContent colorVariant={color} />`,
output: `import { DrawerContent } from '@patternfly/react-core'; const color = "no-background"; <DrawerContent />`,
errors: [
{
message: `The "no-background" value of the \`colorVariant\` prop on DrawerContent has been removed.`,
type: "JSXOpeningElement",
},
],
},
{
code: `import { DrawerContent, DrawerColorVariant } from '@patternfly/react-core'; <DrawerContent colorVariant={DrawerColorVariant.default} />`,
output: `import { DrawerContent, DrawerColorVariant } from '@patternfly/react-core'; <DrawerContent colorVariant="default" />`,
errors: [
{
message: `The DrawerContentColorVariant enum should be used instead of the DrawerColorVariant enum when passed to the DrawerContent component. This fix will replace the colorVariant prop value with a string.`,
type: "JSXOpeningElement",
},
],
},
{
code: `import { DrawerContent, DrawerColorVariant } from '@patternfly/react-core'; <DrawerContent colorVariant={DrawerColorVariant.noBackground} />`,
output: `import { DrawerContent, DrawerColorVariant } from '@patternfly/react-core'; <DrawerContent />`,
errors: [
{
message: `The "no-background" value of the \`colorVariant\` prop on DrawerContent has been removed.`,
type: "JSXOpeningElement",
},
],
},
{
code: `import { DrawerContent, DrawerColorVariant } from '@patternfly/react-core'; const color = DrawerColorVariant.default; <DrawerContent colorVariant={DrawerColorVariant.default} />`,
output: `import { DrawerContent, DrawerColorVariant } from '@patternfly/react-core'; const color = DrawerColorVariant.default; <DrawerContent colorVariant="default" />`,
errors: [
{
message: `The DrawerContentColorVariant enum should be used instead of the DrawerColorVariant enum when passed to the DrawerContent component. This fix will replace the colorVariant prop value with a string.`,
type: "JSXOpeningElement",
},
],
},
{
code: `import { DrawerContent, DrawerColorVariant } from '@patternfly/react-core'; const color = DrawerColorVariant.noBackground; <DrawerContent colorVariant={color} />`,
output: `import { DrawerContent, DrawerColorVariant } from '@patternfly/react-core'; const color = DrawerColorVariant.noBackground; <DrawerContent />`,
errors: [
{
message: `The "no-background" value of the \`colorVariant\` prop on DrawerContent has been removed.`,
type: "JSXOpeningElement",
},
],
},
],
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { Rule } from "eslint";
import { JSXOpeningElement } from "estree-jsx";
import { getFromPackage, getAttribute, getAttributeValue } from "../../helpers";

// https://github.com/patternfly/patternfly-react/pull/10211
module.exports = {
meta: { fixable: "code" },
create: function (context: Rule.RuleContext) {
const { imports } = getFromPackage(context, "@patternfly/react-core");

const drawerContentImport = imports.find(
(specifier) => specifier.imported.name === "DrawerContent"
);
const drawerColorVariantEnumImport = imports.find(
(specifier) => specifier.imported.name === "DrawerColorVariant"
);
const validDrawerContentValues = ["default", "primary", "secondary"];

return !drawerContentImport
? {}
: {
JSXOpeningElement(node: JSXOpeningElement) {
if (
!(
node.name.type === "JSXIdentifier" &&
drawerContentImport.local.name === node.name.name
)
) {
return;
}
const colorVariantProp = getAttribute(node, "colorVariant");

if (!colorVariantProp) {
return;
}

const colorVariantValue = getAttributeValue(
context,
colorVariantProp.value
);
const drawerColorVariantLocalName =
drawerColorVariantEnumImport &&
drawerColorVariantEnumImport.local.name;
const hasPatternFlyEnum =
colorVariantValue &&
colorVariantValue.object &&
colorVariantValue.object.name === drawerColorVariantLocalName;
const hasNoBackgroundValue =
colorVariantValue && colorVariantValue.property
? hasPatternFlyEnum &&
colorVariantValue.property.name === "noBackground"
: colorVariantValue === "no-background";

if (!hasPatternFlyEnum && !hasNoBackgroundValue) {
return;
}

const message = hasNoBackgroundValue
? 'The "no-background" value of the `colorVariant` prop on DrawerContent has been removed.'
: "The DrawerContentColorVariant enum should be used instead of the DrawerColorVariant enum when passed to the DrawerContent component. This fix will replace the colorVariant prop value with a string.";
context.report({
node,
message,
fix(fixer) {
const fixes = [];
if (hasNoBackgroundValue) {
fixes.push(fixer.replaceText(colorVariantProp, ""));
}

if (!hasNoBackgroundValue && hasPatternFlyEnum) {
const enumPropertyName = colorVariantValue.property.name;
fixes.push(
fixer.replaceText(
colorVariantProp,
validDrawerContentValues.includes(enumPropertyName)
? `colorVariant="${colorVariantValue.property.name}"`
: ""
)
);
}
return fixes;
},
});
},
};
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { DrawerContent, DrawerColorVariant } from "@patternfly/react-core";

export const DrawerContentReplaceNoBackgroundColorVariantInput = () => {
const stringColor = "no-background";
const enumColor = DrawerColorVariant.default;

return (
<>
<DrawerContent colorVariant='no-background' />
<DrawerContent colorVariant={DrawerColorVariant.default} />
<DrawerContent colorVariant={stringColor} />
<DrawerContent colorVariant={enumColor} />
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { DrawerContent, DrawerColorVariant } from "@patternfly/react-core";

export const DrawerContentReplaceNoBackgroundColorVariantInput = () => {
const stringColor = "no-background";
const enumColor = DrawerColorVariant.default;

return (
<>
<DrawerContent />
<DrawerContent colorVariant="default" />
<DrawerContent />
<DrawerContent colorVariant="default" />
</>
);
};

0 comments on commit fb7076c

Please sign in to comment.