Skip to content

Commit

Permalink
page header tools rules (#71)
Browse files Browse the repository at this point in the history
* WIP use-page-header-tools

* adding space

* targeting JSXIdentifiers

* updates to match card-rename-components, WIP

* matching error messages

* make rule error

* adding data-codemods

* leaving room for headerTools prop

* fix import

* WIP, fixed AST type

* rename-toolbar-components

* adjust tests

* once more

* rename rule

* update readme

Co-authored-by: jenny-s51 <[email protected]>
Co-authored-by: redallen <[email protected]>
  • Loading branch information
3 people authored Jun 3, 2020
1 parent 3dc5ce2 commit a8bed7b
Show file tree
Hide file tree
Showing 12 changed files with 335 additions and 7 deletions.
3 changes: 3 additions & 0 deletions packages/eslint-plugin-pf-codemods/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ const rules = {
"tab-rename-variant": require('./lib/rules/tab-rename-variant'),
"form-fix-isValid": require('./lib/rules/form-fix-isValid'),
"expandable-rename-expandablesection": require('./lib/rules/expandable-rename-expandablesection'),
"rename-toolbar-components": require('./lib/rules/rename-toolbar-components'),
"page-header-prop-rename": require('./lib/rules/page-header-prop-rename'),
"page-header-move-avatar": require('./lib/rules/page-header-move-avatar'),
};

module.exports = {
Expand Down
8 changes: 3 additions & 5 deletions packages/eslint-plugin-pf-codemods/lib/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,8 @@ function renameComponent(
}
},
// update component's JSX usage
JSXElement(node) {
const { openingElement, closingElement } = node;
const nodeName = openingElement.name.name;
JSXIdentifier(node) {
const nodeName = node.name;
const importedNode = imports.find(imp => imp.local.name === nodeName);
if (
importedNamesArr.includes(nodeName) &&
Expand All @@ -126,8 +125,7 @@ function renameComponent(
message: message(nodeName, newName),
fix(fixer) {
const fixes = [
fixer.replaceText(openingElement, updateTagName(openingElement)),
fixer.replaceText(closingElement, updateTagName(closingElement))
fixer.replaceText(node, updateTagName(node))
];
return fixes;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
const { getPackageImports } = require('../helpers');

const components = [
'PageHeader',
'PageHeaderTools'
]

// https://github.com/patternfly/patternfly-react/pull/4246
module.exports = {
create: function(context) {
const imports = getPackageImports(context, '@patternfly/react-core')
.filter(specifier => components.includes(specifier.imported.name));

return imports.length === 0 ? {} : {
JSXElement(node) {
// find avatar attribute
let avatarValue;
if (node.openingElement.name.name === 'PageHeader' && node.openingElement.attributes.length) {
const avatarAttr = node.openingElement.attributes.find(attr => attr.name.name === 'avatar');
const toolbarAttr = node.openingElement.attributes.find(attr => attr.name.name === 'toolbar');
if (toolbarAttr) {
// not ready yet this round, wait for other rules to kick in first
return context.report({
node,
message: `avatar prop was removed from PageHeader, move the avatar component into PageHeaderTools`
});
}
const headerToolsAttr = node.openingElement.attributes.find(attr => attr.name.name === 'headerTools');
if (avatarAttr) {
context.report({
node,
message: `avatar prop was removed from PageHeader, move the avatar component into PageHeaderTools`,
fix(fixer) {
if (!headerToolsAttr) {
// comment out
return fixer.replaceText(avatarAttr, `/*TODO: move to PageHeaderTools - ${context.getSourceCode().getText(avatarAttr)}*/`)
} else {
// move into headerTools if possible
if (
headerToolsAttr.value.type === 'JSXExpressionContainer' &&
headerToolsAttr.value.expression.type === 'JSXElement' &&
headerToolsAttr.value.expression.openingElement.name.name === 'PageHeaderTools' &&
headerToolsAttr.value.expression.closingElement
) {
const intermediateValue = context.getSourceCode().getText(avatarAttr.value);
if (avatarAttr.value.expression && avatarAttr.value.expression.type === 'JSXElement') {
avatarValue = `${intermediateValue.substring(1, intermediateValue.length - 1)}`;
} else {
avatarValue = intermediateValue;
}
return [
fixer.insertTextBefore(
headerToolsAttr.value.expression.closingElement,
avatarValue
),
fixer.remove(avatarAttr)
]
} else {
// well we tried... just comment it out then
return fixer.replaceText(avatarAttr, `/*TODO: move to PageHeaderTools - ${context.getSourceCode().getText(avatarAttr)}*/`)
}

}
}
});
}
}
}
};
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const { renameProp } = require('../helpers');

// https://github.com/patternfly/patternfly-react/pull/4246
module.exports = {
create: renameProp(
'PageHeader',
{
'toolbar': 'headerTools'
},
node => `toolbar prop has been removed from ${node.name.name}. Use headerTools instead`
),
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const { renameComponent } = require('../helpers');

// https://github.com/patternfly/patternfly-react/pull/4246
module.exports = {
create: renameComponent(
{
'Toolbar': 'PageHeaderTools',
'ToolbarGroup': 'PageHeaderToolsGroup',
'ToolbarItem': 'PageHeaderToolsItem'
}
)
};
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ ruleTester.run("chipgroup-remove-chipbutton", rule, {
},
{
message: `ChipButton has been replaced with Button`,
type: "JSXElement",
type: "JSXIdentifier",
},
{
message: `ChipButton has been replaced with Button`,
type: "JSXIdentifier",
},
]
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ ruleTester.run("expandable-rename-expandablesection", rule, {
},
{
message: 'Expandable has been replaced with ExpandableSection',
type: "JSXElement"
type: "JSXIdentifier"
},
{
message: 'Expandable has been replaced with ExpandableSection',
type: "JSXIdentifier"
}
]
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
const ruleTester = require("./ruletester");
const rule = require("../../lib/rules/page-header-move-avatar");

ruleTester.run("page-header-move-avatar", rule, {
valid: [
{
code: `import { Avatar, PageHeader } from '@patternfly/react-core'; <PageHeader headerTools="tools" />`
},
{
// no @patternfly import
code: `<PageHeader avatar={<Avatar />} />`
}
],
invalid: [
{
code: `import { Avatar, PageHeader } from '@patternfly/react-core'; <PageHeader avatar={<Avatar />} />`,
output: `import { Avatar, PageHeader } from '@patternfly/react-core'; <PageHeader /*TODO: move to PageHeaderTools - avatar={<Avatar />}*/ />`,
errors: [
{
message: 'avatar prop was removed from PageHeader, move the avatar component into PageHeaderTools',
type: 'JSXElement'
}
]
},
{
code: `import { Avatar, PageHeader, PageHeaderTools } from '@patternfly/react-core'; <PageHeader avatar={<Avatar />} headerTools={<PageHeaderTools></PageHeaderTools>} />`,
output: `import { Avatar, PageHeader, PageHeaderTools } from '@patternfly/react-core'; <PageHeader headerTools={<PageHeaderTools><Avatar /></PageHeaderTools>} />`,
errors: [
{
message: 'avatar prop was removed from PageHeader, move the avatar component into PageHeaderTools',
type: 'JSXElement'
}
]
},
]
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const ruleTester = require('./ruletester');
const rule = require('../../lib/rules/page-header-prop-rename');

ruleTester.run("page-header-prop-rename", rule, {
valid: [
{
code: `import { PageHeader } from '@patternfly/react-core'; <PageHeader headerTools="tools" />`,
},
{
// no @patternfly import
code: `<PageHeader toolbar="tools" />`}
],
invalid: [
{
code: `import { PageHeader } from '@patternfly/react-core'; <PageHeader toolbar="tools" />`,
output: `import { PageHeader } from '@patternfly/react-core'; <PageHeader headerTools="tools" />`,
errors: [{
message: `toolbar prop has been removed from PageHeader. Use headerTools instead`,
type: "JSXOpeningElement",
}]
},
]
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
const ruleTester = require('./ruletester');
const rule = require('../../lib/rules/rename-toolbar-components');

ruleTester.run("rename-toolbar-components", rule, {
valid: [
{
code: `import { PageHeaderTools, PageHeaderToolsGroup, PageHeaderToolsItem } from '@patternfly/react-core';
<PageHeaderTools>
<PageHeaderToolsGroup>
<PageHeaderToolsItem />
</PageHeaderToolsGroup>
</PageHeaderTools>
`,
},
{
// No @patternfly/react-core import
code: `
<Toolbar>
<ToolbarGroup>
<ToolbarItem />
</ToolbarGroup>
</Toolbar>
`
}
],
invalid: [
{
code: `
import { Page, PageHeader, Toolbar, ToolbarGroup, ToolbarItem } from '@patternfly/react-core';
<Page>
<PageHeader toolbar={
<Toolbar>
<ToolbarGroup>
<ToolbarItem />
</ToolbarGroup>
</Toolbar>
}
/>
</Page>
`,
output: `
import { Page, PageHeader, PageHeaderTools, PageHeaderToolsGroup, PageHeaderToolsItem } from '@patternfly/react-core';
<Page>
<PageHeader toolbar={
<PageHeaderTools>
<PageHeaderToolsGroup>
<PageHeaderToolsItem />
</PageHeaderToolsGroup>
</PageHeaderTools>
}
/>
</Page>
`,
errors: [
{
message: `Toolbar has been replaced with PageHeaderTools`,
type: "ImportSpecifier",
},
{
message: `ToolbarGroup has been replaced with PageHeaderToolsGroup`,
type: "ImportSpecifier",
},
{
message: `ToolbarItem has been replaced with PageHeaderToolsItem`,
type: "ImportSpecifier",
},
{
message: `Toolbar has been replaced with PageHeaderTools`,
type: "JSXIdentifier",
},
{
message: `ToolbarGroup has been replaced with PageHeaderToolsGroup`,
type: "JSXIdentifier",
},
{
message: `ToolbarItem has been replaced with PageHeaderToolsItem`,
type: "JSXIdentifier",
},
{
message: `ToolbarGroup has been replaced with PageHeaderToolsGroup`,
type: "JSXIdentifier",
},
{
message: `Toolbar has been replaced with PageHeaderTools`,
type: "JSXIdentifier",
},
]
},
]
});
63 changes: 63 additions & 0 deletions packages/pf-codemods/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,35 @@ Out:
import { Divider } from '@patternfly/react-core';
```
### page-header-move-avatar [(#4246)](https://github.com/patternfly/patternfly-react/pull/4246)
This rule tries to move the PageHeader avatar prop value into the headerTools prop. If it can't it will comment the avatar prop and value out.
It depends on the `rename-toolbar-components` and `page-header-prop-rename` props to be run first.
#### Examples
In:
```jsx
<PageHeader avatar={<Avatar />} />
<PageHeader avatar={<Avatar />} headerTools={<PageHeaderTools></PageHeaderTools>} />
```
Out:
```jsx
<PageHeader /*TODO: move to PageHeaderTools - avatar={<Avatar />}*/ />
<PageHeader headerTools={<PageHeaderTools><Avatar /></PageHeaderTools>} />
```
### page-header-prop-rename [(#4246)](https://github.com/patternfly/patternfly-react/pull/4246)
Renames the PageHeader `toolbar` prop to `headerTools`
#### Examples
In:
```jsx
<PageHeader toolbar="tools" />
```
Out:
```jsx
<PageHeader headerTools="tools" />
```
### pagination-removed-variant [(#4202)](https://github.com/patternfly/patternfly-react/pull/4202)
Removed obsolete 'left' and 'right' variants. These can be replaced with 'top' (default) or 'bottom' if needed.
Expand Down Expand Up @@ -502,6 +531,40 @@ Out:
<PageSection hasNoPadding />
```
### rename-toolbar-components [(#4246)](https://github.com/patternfly/patternfly-react/pull/4246)
Renames the `Toolbar` related imports and components to `PageHeader` related imports and components.
Note: The PageHeader `toolbar` prop is renamed in the `page-header-prop-rename` rule.
#### Examples
In:
```jsx
import { Page, PageHeader, Toolbar, ToolbarGroup, ToolbarItem } from '@patternfly/react-core';
<Page>
<PageHeader toolbar={
<Toolbar>
<ToolbarGroup>
<ToolbarItem />
</ToolbarGroup>
</Toolbar>
}
/>
</Page>
```
Out:
```jsx
import { Page, PageHeader, PageHeaderTools, PageHeaderToolsGroup, PageHeaderToolsItem } from '@patternfly/react-core';
<Page>
<PageHeader toolbar={
<PageHeaderTools>
<PageHeaderToolsGroup>
<PageHeaderToolsItem />
</PageHeaderToolsGroup>
</PageHeaderTools>
}
/>
</Page>
```
### react-icons-remove-icon [(#3978)](https://github.com/patternfly/patternfly-react/pull/3978)
- Removed `OutlinedFontAwesomeLogoFullIcon`. Import it from @fortawesome instead.
Expand Down
Loading

0 comments on commit a8bed7b

Please sign in to comment.