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
2 changes: 2 additions & 0 deletions packages/eslint-plugin-pf-codemods/src/ruleCustomization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ export const warningRules = [
"notificationBadge-warn-markup-change",
"notificationDrawerHeader-warn-update-markup",
"overflowMenu-warn-updated-dropdownItem",
"page-warn-updated-markup",
"pageBreadcrumbAndSection-warn-updated-wrapperLogic",
"pageSection-warn-variantClasses-applied",
"popover-warn-appendTo-default",
"popper-update-appendTo-default",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,22 @@ export function getAttribute(
) as JSXAttribute | undefined;
}

export function getAnyAttribute(
node: JSXElement | JSXOpeningElement,
attributeNames: string[]
) {
let foundAttribute = undefined;
for (const attribute of attributeNames) {
foundAttribute = getAttribute(node, attribute);

if (foundAttribute) {
break;
}
}

return foundAttribute;
}

export function getAttributeValue(
context: Rule.RuleContext,
node?: JSXAttribute["value"]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
### pageBreadcrumbAndSection-warn-updated-wrapperLogic [(#10650)](https://github.com/patternfly/patternfly-react/pull/10650)

The `isWidthLimited` prop on PageBreadcrumb and PageSection will no longer determine whether the children of either component are wrapped in a PageBody. Instead the new `hasBodyWrapper` prop must be used. By default this new prop is set to true. Running the fix for this rule will apply `hasBodyWrapper` with the same value as the `isWidthLimited` prop or false if `isWidthLimited` is not passed.

#### Examples

In:

```jsx
%inputExample%
```

Out:

```jsx
%outputExample%
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
const ruleTester = require("../../ruletester");
import * as rule from "./pageBreadcrumbAndSection-warn-updated-wrapperLogic";
import {
ValidTests,
InvalidTests,
createInvalidTest,
createValidTest,
} from "../../helpers/testHelpers";

const validTests: ValidTests = [];
const invalidTests: InvalidTests = [];
const applicableComponents = ["PageBreadcrumb", "PageSection"];
for (const component of applicableComponents) {
validTests.push(createValidTest(`<${component} isWidthLimited />`));

const message = `The isWidthLimited prop on ${component} will no longer determine whether the children are wrapped in a PageBody. Instead the new hasBodyWrapper prop must be used. By default this new prop is set to true. Running the fix for this rule will apply hasBodyWrapper with the same value as the isWidthLimited prop or false if isWidthLimited is not passed.`;
const errorObject = {
message,
type: "JSXOpeningElement",
};
invalidTests.push(
createInvalidTest(
`import { ${component} } from '@patternfly/react-core'; <${component} isWidthLimited />`,
`import { ${component} } from '@patternfly/react-core'; <${component} hasBodyWrapper isWidthLimited />`,
[errorObject]
)
);
invalidTests.push(
createInvalidTest(
`import { ${component} } from '@patternfly/react-core'; <${component} />`,
`import { ${component} } from '@patternfly/react-core'; <${component} hasBodyWrapper={false} />`,
[errorObject]
)
);
invalidTests.push(
createInvalidTest(
`import { ${component} } from '@patternfly/react-core'; <${component} isWidthLimited={someVar} />`,
`import { ${component} } from '@patternfly/react-core'; <${component} hasBodyWrapper={someVar} isWidthLimited={someVar} />`,
[errorObject]
)
);
invalidTests.push(
createInvalidTest(
`import { ${component} } from '@patternfly/react-core'; <${component} isWidthLimited={() => someCallback()} />`,
`import { ${component} } from '@patternfly/react-core'; <${component} hasBodyWrapper={() => someCallback()} isWidthLimited={() => someCallback()} />`,
[errorObject]
)
);
invalidTests.push(
createInvalidTest(
`import { ${component} as CustomThing } from '@patternfly/react-core'; <CustomThing isWidthLimited />`,
`import { ${component} as CustomThing } from '@patternfly/react-core'; <CustomThing hasBodyWrapper isWidthLimited />`,
[errorObject]
)
);
invalidTests.push(
createInvalidTest(
`import { ${component} } from '@patternfly/react-core/dist/esm/components/Page/index.js'; <${component} isWidthLimited />`,
`import { ${component} } from '@patternfly/react-core/dist/esm/components/Page/index.js'; <${component} hasBodyWrapper isWidthLimited />`,
[errorObject]
)
);
invalidTests.push(
createInvalidTest(
`import { ${component} } from '@patternfly/react-core/dist/js/components/Page/index.js'; <${component} isWidthLimited />`,
`import { ${component} } from '@patternfly/react-core/dist/js/components/Page/index.js'; <${component} hasBodyWrapper isWidthLimited />`,
[errorObject]
)
);
invalidTests.push(
createInvalidTest(
`import { ${component} } from '@patternfly/react-core/dist/dynamic/components/Page/index.js'; <${component} isWidthLimited />`,
`import { ${component} } from '@patternfly/react-core/dist/dynamic/components/Page/index.js'; <${component} hasBodyWrapper isWidthLimited />`,
[errorObject]
)
);
}

ruleTester.run("pageBreadcrumbAndSection-warn-updated-wrapperLogic", rule, {
valid: validTests,
invalid: invalidTests,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Rule } from "eslint";
import { JSXOpeningElement } from "estree-jsx";
import {
getFromPackage,
getAttribute,
getAttributeValueText,
} from "../../helpers";

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

const componentImports = imports.filter((specifier) =>
["PageBreadcrumb", "PageSection"].includes(specifier.imported.name)
);

return !componentImports.length
? {}
: {
JSXOpeningElement(node: JSXOpeningElement) {
const applicableComponent = componentImports.find(
(imp) =>
node.name.type === "JSXIdentifier" &&
imp.local.name === node.name.name
);
if (applicableComponent) {
const isWidthLimitedProp = getAttribute(node, "isWidthLimited");
const isWidthLimitedValueText = getAttributeValueText(
context,
isWidthLimitedProp
);
const hadBodyWrapperProp = getAttribute(node, "hasBodyWrapper");

if (!hadBodyWrapperProp) {
context.report({
node,
message: `The isWidthLimited prop on ${applicableComponent.imported.name} will no longer determine whether the children are wrapped in a PageBody. Instead the new hasBodyWrapper prop must be used. By default this new prop is set to true. Running the fix for this rule will apply hasBodyWrapper with the same value as the isWidthLimited prop or false if isWidthLimited is not passed.`,
fix(fixer) {
const hasBodyWrapperValue = isWidthLimitedProp
? isWidthLimitedValueText
: `{false}`;
return fixer.insertTextAfter(
node.name,
` hasBodyWrapper${
hasBodyWrapperValue ? `=${hasBodyWrapperValue}` : ""
}`
);
},
});
}
}
},
};
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { PageBreadcrumb, PageSection } from "@patternfly/react-core";

export const PageBreadcrumbAndSectionWarnUpdatedWrapperLogicInput = () => (
<>
<PageBreadcrumb isWidthLimited />
<PageBreadcrumb isWidthLimited={someVar} />
<PageBreadcrumb isWidthLimited={() => someCallback()} />
<PageSection isWidthLimited />
<PageSection isWidthLimited={someVar} />
<PageSection isWidthLimited={() => someCallback()} />
</>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { PageBreadcrumb, PageSection } from "@patternfly/react-core";

export const PageBreadcrumbAndSectionWarnUpdatedWrapperLogicInput = () => (
<>
<PageBreadcrumb hasBodyWrapper isWidthLimited />
<PageBreadcrumb hasBodyWrapper={someVar} isWidthLimited={someVar} />
<PageBreadcrumb hasBodyWrapper={() => someCallback()} isWidthLimited={() => someCallback()} />
<PageSection hasBodyWrapper isWidthLimited />
<PageSection hasBodyWrapper={someVar} isWidthLimited={someVar} />
<PageSection hasBodyWrapper={() => someCallback()} isWidthLimited={() => someCallback()} />
</>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
### pageNavigation-remove-component [(#10650)](https://github.com/patternfly/patternfly-react/pull/10650)

The PageNavigation component has been removed from PatternFly.

#### Examples

In:

```jsx
%inputExample%
```

Out:

```jsx
%outputExample%
```

Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
const ruleTester = require("../../ruletester");
import * as rule from "./pageNavigation-remove-component";

ruleTester.run("pageNavigation-remove-component", rule, {
valid: [
{
code: `<PageNavigation />`,
},
{
code: `<PageNavigation></PageNavigation>`,
},
{
code: `import { PageNavigation } from '@patternfly/someOtherPackage'; <PageNavigation />`,
},
{
code: `import { PageNavigation } from '@patternfly/someOtherPackage'; <PageNavigation></PageNavigation>`,
},
],
invalid: [
{
code: `import { PageNavigation } from '@patternfly/react-core'; <PageNavigation />`,
output: `import { PageNavigation } from '@patternfly/react-core'; `,
errors: [
{
message: `The PageNavigation component has been removed from PatternFly.`,
type: "JSXElement",
},
],
},
{
code: `import { PageNavigation } from '@patternfly/react-core'; <PageNavigation></PageNavigation>`,
output: `import { PageNavigation } from '@patternfly/react-core'; `,
errors: [
{
message: `The PageNavigation component has been removed from PatternFly.`,
type: "JSXElement",
},
],
},
{
code: `import { PageNavigation } from '@patternfly/react-core'; <PageNavigation><div>Some internal content</div></PageNavigation>`,
output: `import { PageNavigation } from '@patternfly/react-core'; <div>Some internal content</div>`,
errors: [
{
message: `The PageNavigation component has been removed from PatternFly.`,
type: "JSXElement",
},
],
},
{
code: `import { PageNavigation } from '@patternfly/react-core'; <div>Wrapper content<div>Adjacent Content</div><PageNavigation><div>Some internal content</div></PageNavigation></div>`,
output: `import { PageNavigation } from '@patternfly/react-core'; <div>Wrapper content<div>Adjacent Content</div><div>Some internal content</div></div>`,
errors: [
{
message: `The PageNavigation component has been removed from PatternFly.`,
type: "JSXElement",
},
],
},
{
code: `export { PageNavigation } from '@patternfly/react-core';`,
output: ``,
errors: [
{
message: `The PageNavigation component has been removed from PatternFly.`,
type: "ExportNamedDeclaration",
},
],
},
{
code: `export { PageNavigation, Button } from '@patternfly/react-core';`,
output: `export { Button } from '@patternfly/react-core';`,
errors: [
{
message: `The PageNavigation component has been removed from PatternFly.`,
type: "ExportNamedDeclaration",
},
],
},
{
code: `export { Alert, PageNavigation, Button } from '@patternfly/react-core';`,
output: `export { Alert, Button } from '@patternfly/react-core';`,
errors: [
{
message: `The PageNavigation component has been removed from PatternFly.`,
type: "ExportNamedDeclaration",
},
],
},
{
code: `import { PageNavigation } from '@patternfly/react-core'; export { PageNavigation }`,
output: `import { PageNavigation } from '@patternfly/react-core'; `,
errors: [
{
message: `The PageNavigation component has been removed from PatternFly.`,
type: "ExportNamedDeclaration",
},
],
},
{
code: `import { PageNavigation } from '@patternfly/react-core'; export default PageNavigation`,
output: `import { PageNavigation } from '@patternfly/react-core'; `,
errors: [
{
message: `The PageNavigation component has been removed from PatternFly.`,
type: "ExportDefaultDeclaration",
},
],
},
{
code: `import { PageNavigation } from '@patternfly/react-core/dist/esm/components/Page/index.js'; <PageNavigation />`,
output: `import { PageNavigation } from '@patternfly/react-core/dist/esm/components/Page/index.js'; `,
errors: [
{
message: `The PageNavigation component has been removed from PatternFly.`,
type: "JSXElement",
},
],
},
{
code: `import { PageNavigation } from '@patternfly/react-core/dist/js/components/Page/index.js'; <PageNavigation />`,
output: `import { PageNavigation } from '@patternfly/react-core/dist/js/components/Page/index.js'; `,
errors: [
{
message: `The PageNavigation component has been removed from PatternFly.`,
type: "JSXElement",
},
],
},
{
code: `import { PageNavigation } from '@patternfly/react-core/dist/dynamic/components/Page/index.js'; <PageNavigation />`,
output: `import { PageNavigation } from '@patternfly/react-core/dist/dynamic/components/Page/index.js'; `,
errors: [
{
message: `The PageNavigation component has been removed from PatternFly.`,
type: "JSXElement",
},
],
},
],
});
Loading