Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
const { getPackageImports } = require("../../helpers");

// https://github.com/patternfly/patternfly-react/pull/8861
// https://github.com/patternfly/patternfly-react/pull/8904
module.exports = {
meta: { fixable: "code" },
create: function (context) {
const tableTdImport = getPackageImports(
context,
"@patternfly/react-table"
).find((specifier) => "Td" === specifier.imported.name);

return !tableTdImport
? {}
: {
JSXOpeningElement(node) {
if (tableTdImport.local.name !== node.name.name) {
return;
}

const attributesToUpdate = node.attributes.filter(
(attr) =>
attr.type === "JSXAttribute" &&
attr.value.type === "JSXExpressionContainer" &&
["select", "actions"].includes(attr.name?.name)
);

const getObjectProp = (expr, propName) =>
expr.properties.find(
(prop) =>
(prop.key.type === "Identifier" &&
prop.key.name === propName) ||
(prop.key.type === "Literal" && prop.key.value === propName)
);

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

if (variable) {
return variable;
}

scope = scope.upper;
}
return undefined;
};

const handleObjectExpression = (expr, toReplace) => {
const disableProp = getObjectProp(expr, "disable");
disableProp && toReplace.push(disableProp.key);

if (disableProp?.shorthand) {
const variable = findVariableDeclaration(
"disable",
context.getSourceCode().getScope(expr)
);

variable && toReplace.push(variable.defs[0].node.id);
}
};

for (const attr of attributesToUpdate) {
const expr = attr.value.expression;

let toReplace = [];

if (expr.type === "ObjectExpression") {
handleObjectExpression(expr, toReplace);
}

if (expr.type === "Identifier") {
const variable = findVariableDeclaration(
expr.name,
context.getSourceCode().getScope(node)
);

const variableValue = variable.defs[0].node.init;

if (variableValue?.type === "ObjectExpression") {
handleObjectExpression(variableValue, toReplace);
}

const nodesUsingVariable = variable.references.map(
(ref) => ref.identifier.parent
);

nodesUsingVariable.forEach((n) => {
if (
n.type === "MemberExpression" &&
(n.property.name === "disable" ||
n.property.value === "disable")
) {
toReplace.push(n.property);
}

if (
n.type === "AssignmentExpression" &&
n.right.type === "ObjectExpression"
) {
handleObjectExpression(n.right, toReplace);
}
});
}

toReplace.length &&
context.report({
message: `'disable' prop of interface ${
{
select: "TdSelectType",
actions: "TdActionsType",
}[attr.name.name]
} has been renamed to 'isDisabled'`,
node,
fix: function (fixer) {
return toReplace.map((val) =>
fixer.replaceText(
val,
val.type === "Literal" ? '"isDisabled"' : "isDisabled"
)
);
},
});
}
},
};
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
const ruleTester = require("../../ruletester");
const rule = require("../../../lib/rules/v5/td-TdSelectType-TdActionsType-rename-disable");

ruleTester.run("td-TdSelectType-TdActionsType-rename-disable", rule, {
valid: [
{
code: `import { Td } from "@patternfly/react-table";

let myObj = { isDisabled: true };
myObj["isDisabled"] = false;
myObj.isDisabled = true;
myObj = { isDisabled: false };

<Td select={myObj} actions={{ isDisabled: false }}></Td>;

const isDisabled = true;
const obj = { isDisabled };
<>
<Td select={obj} actions={{ "isDisabled": true }}></Td>
<Td select={{isDisabled}}></Td>
</>;`,
},
{
// No @patternfly/react-core import
code: `
let myObj = { disable: true };
myObj["disable"] = false;
myObj.disable = true;
myObj = { disable: false };

<Td select={myObj} actions={{ disable: false }}></Td>;

const disable = true;
const obj = { disable };
<>
<Td select={obj} actions={{ "disable": true }}></Td>
<Td select={{disable}}></Td>
</>;`,
},
],
invalid: [
{
code: `
import { Td } from "@patternfly/react-table";

let myObj = { disable: true };
myObj["disable"] = false;
myObj.disable = true;
myObj = { disable: false };

<Td select={myObj} actions={{ disable: false }}></Td>;

const disable = true;
const obj = { disable };
<>
<Td select={obj} actions={{ "disable": true }}></Td>
<Td actions={myObj}></Td>
</>;`,
output: `
import { Td } from "@patternfly/react-table";

let myObj = { isDisabled: true };
myObj["isDisabled"] = false;
myObj.isDisabled = true;
myObj = { isDisabled: false };

<Td select={myObj} actions={{ isDisabled: false }}></Td>;

const isDisabled = true;
const obj = { isDisabled };
<>
<Td select={obj} actions={{ "isDisabled": true }}></Td>
<Td actions={myObj}></Td>
</>;`,
errors: [
{
message: `'disable' prop of interface TdSelectType has been renamed to 'isDisabled'`,
type: "JSXOpeningElement",
},
{
message: `'disable' prop of interface TdActionsType has been renamed to 'isDisabled'`,
type: "JSXOpeningElement",
},
{
message: `'disable' prop of interface TdSelectType has been renamed to 'isDisabled'`,
type: "JSXOpeningElement",
},
{
message: `'disable' prop of interface TdActionsType has been renamed to 'isDisabled'`,
type: "JSXOpeningElement",
},
{
message: `'disable' prop of interface TdActionsType has been renamed to 'isDisabled'`,
type: "JSXOpeningElement",
}
],
},
],
});
42 changes: 42 additions & 0 deletions packages/pf-codemods/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1768,6 +1768,48 @@ We've restricted the type of elements that can be passed to the `Tabs` component

This rule will raise a warning when `Tabs` is imported in a file, even if the children passed to it are already of the appropriate type. It will not make any code changes.

### td-TdSelectType-TdActionsType-rename-disable [(#8861,](https://github.com/patternfly/patternfly-react/pull/8861) [#8904)](https://github.com/patternfly/patternfly-react/pull/8904)

We've renamed `disable` prop to `isDisabled` inside `TdSelectType` and `TdActionsType` interfaces. These interfaces are used as types of `Td` component's props `select` (`TdSelectType`) and `actions` (`TdActionsType`).

#### Examples

In:

```jsx
let myObj = { disable: true };
myObj["disable"] = false;
myObj.disable = true;
myObj = { disable: false };

<Td select={myObj} actions={{ disable: false }}></Td>;

const disable = true;
const obj = { disable };
<>
<Td select={obj} actions={{ "disable": true }}></Td>
<Td select={{disable}}></Td>
</>;
```

Out:

```jsx
let myObj = { isDisabled: true };
myObj["isDisabled"] = false;
myObj.isDisabled = true;
myObj = { isDisabled: false };

<Td select={myObj} actions={{ isDisabled: false }}></Td>;

const isDisabled = true;
const obj = { isDisabled };
<>
<Td select={obj} actions={{ "isDisabled": true }}></Td>
<Td select={{isDisabled}}></Td>
</>;
```

### toggle-remove-isprimary [(#8179)](https://github.com/patternfly/patternfly-react/pull/8179)

We've removed the deprecated `isPrimary` prop. This rule wil replace it with the "primary" value on the `toggleVariant` prop.
Expand Down
5 changes: 5 additions & 0 deletions test/test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ import {
} from "@patternfly/react-core";
import { SelectOption, WizardBody as WizardBodyNext, WizardFooter } from "@patternfly/react-core/next";

import { Td } from "@patternfly/react-table";

const tdSelectTypeObj = {"disable": true};

//following type of import was causing errors for rules that checked specifiers before import package
import foo from Bar;

Expand Down Expand Up @@ -172,6 +176,7 @@ const backgroundImgSrcObj: BackgroundImageSrcMap = {};
<Spinner isSVG />
<Toggle isPrimary onToggle={} />
<Tooltip reference />
<Td select={tdSelectTypeObj} actions={{disable: false}} />
<TreeView hasCheck />
<Wizard />
<Wizard mainAriaLabel />
Expand Down