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
7 changes: 5 additions & 2 deletions packages/eslint-plugin-pf-codemods/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
const createListOfRules = (version) => {
const rules = {};
require("glob")
.sync(require.resolve('@patternfly/eslint-plugin-pf-codemods').replace('index.js', `lib/rules/v${version}/*.js`))
.sync(
require
.resolve("@patternfly/eslint-plugin-pf-codemods")
.replace("index.js", `lib/rules/v${version}/*.js`)
)
.forEach(function (file) {
const ruleName = /.*\/([^.]+)/.exec(file)[1];
rules[ruleName] = require(`./lib/rules/v${version}/${ruleName}`);
Expand All @@ -19,7 +23,6 @@ const warningRules = [
"charts-tooltip-warning",
"datePicker-warn-appendTo-default-value-changed",
"horizontalSubnav-ariaLabel",
"onToggle-warn-event",
"nav-warn-flyouts-now-inline",
"popover-appendTo-default",
"react-dropzone-warn-upgrade",
Expand Down
85 changes: 85 additions & 0 deletions packages/eslint-plugin-pf-codemods/lib/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,96 @@ function ensureImports(context, node, package, imports) {
}
}

function addCallbackParam(componentsArray, propMap) {
return function (context) {
const imports = getPackageImports(context, "@patternfly/react-core").filter(
(specifier) => componentsArray.includes(specifier.imported.name)
);

return !imports.length
? {}
: {
JSXOpeningElement(node) {
if (imports.map((imp) => imp.local.name).includes(node.name.name)) {
const namedAttributes = node.attributes.filter((attr) =>
Object.keys(propMap).includes(attr.name?.name)
);

namedAttributes.forEach((attribute) => {
const newParam = propMap[attribute.name.name];

const propProperties = {
type: attribute.value?.expression?.type,
name: attribute.value?.expression?.name,
};

if (propProperties.type === "ArrowFunctionExpression") {
propProperties.params = attribute.value?.expression?.params;
} else if (propProperties.type === "Identifier") {
const currentScope = context.getScope();
const matchingVariable = currentScope.variables.find(
(variable) => variable.name === propProperties.name
);
const matchingDefinition = matchingVariable.defs.find(
(def) => def.name.name === propProperties.name
);

propProperties.params =
matchingDefinition.type === "FunctionName"
? matchingDefinition.node.params
: matchingDefinition.node.init.params;
}
const { type, params } = propProperties;

if (
(params?.length === 1 &&
["ArrowFunctionExpression", "Identifier"].includes(type)) ||
type === "MemberExpression"
) {
context.report({
node,
message: `The "${attribute.name.name}" prop for ${node.name.name} has been updated to include the "${newParam}" parameter as its first parameter. "${attribute.name.name}" handlers may require an update.`,
fix(fixer) {
const fixes = [];
const createReplacerFix = (functionParam) => {
const hasParenthesis =
context.getTokenAfter(functionParam).value === ")";
const replacementParams = `${newParam}, ${functionParam.name}`;

return fixer.replaceText(
functionParam,
hasParenthesis
? replacementParams
: `(${replacementParams})`
);
};

if (
["ArrowFunctionExpression", "Identifier"].includes(
type
) &&
params.length === 1
) {
fixes.push(createReplacerFix(params[0]));
}

return fixes;
},
});
}
});
}
},
};
};
}

module.exports = {
ensureImports,
getPackageImports,
renameProp,
renameProps0,
renameProps,
renameComponents,
addCallbackParam
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const { addCallbackParam } = require("../../helpers");

// https://github.com/patternfly/patternfly-react/pull/8723
module.exports = {
meta: { fixable: "code" },
create: addCallbackParam(["DataList"], { onSelectDataListItem: "_event" }),
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const { addCallbackParam } = require("../../helpers");
const onToggleAPIUpdateList = [
"ApplicationLauncher",
"BadgeToggle",
"DropdownToggle",
"KebabToggle",
"Toggle",
"Select",
"SelectToggle",
];
// https://github.com/patternfly/patternfly-react/pull/8667
module.exports = {
meta: { fixable: "code" },
create: addCallbackParam(onToggleAPIUpdateList, { onToggle: "_event" }),
};

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
const ruleTester = require("../../ruletester");
const rule = require("../../../lib/rules/v5/dataList-updated-callback");

ruleTester.run("dataList-updated-callback", rule, {
valid: [
{
code: `import { DataList } from '@patternfly/react-core'; <DataList />;`,
},
{
code: `import { DataList } from '@patternfly/react-core'; <DataList onSelectDataListItem={() => onSelect()} />;`,
},
{
code: `import { DataList } from '@patternfly/react-core'; const onSelect = () => {}; <DataList onSelectDataListItem={onSelect} />;`,
},
{
code: `import { DataList } from '@patternfly/react-core'; function onSelect() {}; <DataList onSelectDataListItem={onSelect} />;`,
},
{
// No @patternfly/react-core import
code: `<DataList onSelectDataListItem />;`,
},
],
invalid: [
{
code: `import { DataList } from '@patternfly/react-core'; <DataList onSelectDataListItem={(id) => onSelect(id)} />;`,
output: `import { DataList } from '@patternfly/react-core'; <DataList onSelectDataListItem={(_event, id) => onSelect(id)} />;`,
errors: [
{
message: `The "onSelectDataListItem" prop for DataList has been updated to include the "_event" parameter as its first parameter. "onSelectDataListItem" handlers may require an update.`,
type: "JSXOpeningElement",
},
],
},
{
code: `import { DataList } from '@patternfly/react-core'; <DataList onSelectDataListItem={id => onSelect(id)} />;`,
output: `import { DataList } from '@patternfly/react-core'; <DataList onSelectDataListItem={(_event, id) => onSelect(id)} />;`,
errors: [
{
message: `The "onSelectDataListItem" prop for DataList has been updated to include the "_event" parameter as its first parameter. "onSelectDataListItem" handlers may require an update.`,
type: "JSXOpeningElement",
},
],
},
{
code: `import { DataList } from '@patternfly/react-core'; const onSelect = (id) => {}; <DataList onSelectDataListItem={onSelect} />;`,
output: `import { DataList } from '@patternfly/react-core'; const onSelect = (_event, id) => {}; <DataList onSelectDataListItem={onSelect} />;`,
errors: [
{
message: `The "onSelectDataListItem" prop for DataList has been updated to include the "_event" parameter as its first parameter. "onSelectDataListItem" handlers may require an update.`,
type: "JSXOpeningElement",
},
],
},
{
code: `import { DataList } from '@patternfly/react-core'; function onSelect(id) {}; <DataList onSelectDataListItem={onSelect} />;`,
output: `import { DataList } from '@patternfly/react-core'; function onSelect(_event, id) {}; <DataList onSelectDataListItem={onSelect} />;`,
errors: [
{
message: `The "onSelectDataListItem" prop for DataList has been updated to include the "_event" parameter as its first parameter. "onSelectDataListItem" handlers may require an update.`,
type: "JSXOpeningElement",
},
],
},
{
code: `import { DataList } from '@patternfly/react-core'; <DataList onSelectDataListItem={this.onSelect} />;`,
output: `import { DataList } from '@patternfly/react-core'; <DataList onSelectDataListItem={this.onSelect} />;`,
errors: [
{
message: `The "onSelectDataListItem" prop for DataList has been updated to include the "_event" parameter as its first parameter. "onSelectDataListItem" handlers may require an update.`,
type: "JSXOpeningElement",
},
],
},
{
code: `import { DataList as PFDataList } from '@patternfly/react-core'; <PFDataList onSelectDataListItem={(id) => onSelect(id)} />;`,
output: `import { DataList as PFDataList } from '@patternfly/react-core'; <PFDataList onSelectDataListItem={(_event, id) => onSelect(id)} />;`,
errors: [
{
message: `The "onSelectDataListItem" prop for PFDataList has been updated to include the "_event" parameter as its first parameter. "onSelectDataListItem" handlers may require an update.`,
type: "JSXOpeningElement",
},
],
},
],
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
const ruleTester = require("../../ruletester");
const rule = require("../../../lib/rules/v5/onToggle-updated-paramaters");
const onToggleAPIUpdateList = [
"ApplicationLauncher",
"BadgeToggle",
"DropdownToggle",
"KebabToggle",
"Toggle",
"Select",
"SelectToggle",
];

ruleTester.run("onToggle-updated-paramaters", rule, {
valid: [
...onToggleAPIUpdateList.map((component) => ({
code: `import { ${component} } from '@patternfly/react-core'; <${component} />;`,
})),
...onToggleAPIUpdateList.map((component) => ({
code: `import { ${component} } from '@patternfly/react-core'; <${component} onToggle={() => onToggle} />;`,
})),
...onToggleAPIUpdateList.map((component) => ({
code: `import { ${component} } from '@patternfly/react-core'; const onToggle = () => {}; <${component} onToggle={onToggle} />;`,
})),
...onToggleAPIUpdateList.map((component) => ({
code: `import { ${component} } from '@patternfly/react-core'; function onToggle() {}; <${component} onToggle={onToggle} />;`,
})),
// No @patternfly/react-core import
...onToggleAPIUpdateList.map((component) => ({
code: `<${component} onToggle />;`,
})),
],
invalid: [
...onToggleAPIUpdateList.map((component) => ({
code: `import { ${component} } from '@patternfly/react-core'; <${component} onToggle={(isOpen) => onToggle(isOpen)} />;`,
output: `import { ${component} } from '@patternfly/react-core'; <${component} onToggle={(_event, isOpen) => onToggle(isOpen)} />;`,
errors: [
{
message: `The "onToggle" prop for ${component} has been updated to include the "_event" parameter as its first parameter. "onToggle" handlers may require an update.`,
type: "JSXOpeningElement",
},
],
})),
...onToggleAPIUpdateList.map((component) => ({
code: `import { ${component} } from '@patternfly/react-core'; <${component} onToggle={isOpen => onToggle(isOpen)} />;`,
output: `import { ${component} } from '@patternfly/react-core'; <${component} onToggle={(_event, isOpen) => onToggle(isOpen)} />;`,
errors: [
{
message: `The "onToggle" prop for ${component} has been updated to include the "_event" parameter as its first parameter. "onToggle" handlers may require an update.`,
type: "JSXOpeningElement",
},
],
})),
...onToggleAPIUpdateList.map((component) => ({
code: `import { ${component} } from '@patternfly/react-core'; const onToggle = (isOpen) => {}; <${component} onToggle={onToggle} />;`,
output: `import { ${component} } from '@patternfly/react-core'; const onToggle = (_event, isOpen) => {}; <${component} onToggle={onToggle} />;`,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bitmoji

errors: [
{
message: `The "onToggle" prop for ${component} has been updated to include the "_event" parameter as its first parameter. "onToggle" handlers may require an update.`,
type: "JSXOpeningElement",
},
],
})),
...onToggleAPIUpdateList.map((component) => ({
code: `import { ${component} } from '@patternfly/react-core'; function onToggle(isOpen) {}; <${component} onToggle={onToggle} />;`,
output: `import { ${component} } from '@patternfly/react-core'; function onToggle(_event, isOpen) {}; <${component} onToggle={onToggle} />;`,
errors: [
{
message: `The "onToggle" prop for ${component} has been updated to include the "_event" parameter as its first parameter. "onToggle" handlers may require an update.`,
type: "JSXOpeningElement",
},
],
})),
...onToggleAPIUpdateList.map((component) => ({
code: `import { ${component} } from '@patternfly/react-core'; <${component} onToggle={this.onToggle} />;`,
output: `import { ${component} } from '@patternfly/react-core'; <${component} onToggle={this.onToggle} />;`,
errors: [
{
message: `The "onToggle" prop for ${component} has been updated to include the "_event" parameter as its first parameter. "onToggle" handlers may require an update.`,
type: "JSXOpeningElement",
},
],
})),
],
});
Loading