-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(Masthead): Update subcomponent names (#729)
* feat(Masthead): Update subcomponent names * chore(helpers): Get rid of recursion in getNodeName * chore(masthead): Refactor to only rename MastheadBrand * chore(helpers): Add import source updating to renameComponent helper * chore(helpers): Rename getDeclarationString helper * feat(helpers): Add getCodeModDataTag helper * chore(readme): Update rule description * chore(masthead): update example input/output
- Loading branch information
1 parent
8c2ce49
commit 23a8d8d
Showing
15 changed files
with
330 additions
and
1 deletion.
There are no files selected for viewing
11 changes: 11 additions & 0 deletions
11
packages/eslint-plugin-pf-codemods/src/rules/helpers/getAttributeName.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { JSXAttribute } from "estree-jsx"; | ||
|
||
/** Gets the name value of a JSX attribute */ | ||
export function getAttributeName(attr: JSXAttribute) { | ||
switch (attr.name.type) { | ||
case "JSXIdentifier": | ||
return attr.name.name; | ||
case "JSXNamespacedName": | ||
return attr.name.name.name; | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
packages/eslint-plugin-pf-codemods/src/rules/helpers/getCodeModDataTag.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { JSXAttribute, JSXOpeningElement } from "estree-jsx"; | ||
import { getAttributeName } from "./getAttributeName"; | ||
|
||
/** Returns the data-codemods attribute of an element, if it exists */ | ||
export function getCodeModDataTag(openingElement: JSXOpeningElement) { | ||
const nonSpreadAttributes = openingElement.attributes.filter( | ||
(attr) => attr.type === "JSXAttribute" | ||
); | ||
|
||
return nonSpreadAttributes.find( | ||
(attr) => getAttributeName(attr as JSXAttribute) === "data-codemods" | ||
); | ||
} |
17 changes: 17 additions & 0 deletions
17
packages/eslint-plugin-pf-codemods/src/rules/helpers/getComponentImportName.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { ImportSpecifier } from "estree-jsx"; | ||
import { ImportDefaultSpecifierWithParent } from "./interfaces"; | ||
import { getDefaultDeclarationString } from "./getDefaultDeclarationString"; | ||
|
||
/** Gets the name of an import based on the specifier and an array of names that should be looked for in default import paths */ | ||
export function getComponentImportName( | ||
importSpecifier: ImportSpecifier | ImportDefaultSpecifierWithParent, | ||
potentialNames: string[] | ||
) { | ||
if (importSpecifier.type === "ImportSpecifier") { | ||
return importSpecifier.imported.name; | ||
} | ||
|
||
return potentialNames.find((name) => | ||
getDefaultDeclarationString(importSpecifier)?.includes(name) | ||
); | ||
} |
8 changes: 8 additions & 0 deletions
8
packages/eslint-plugin-pf-codemods/src/rules/helpers/getDefaultDeclarationString.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { ImportDefaultSpecifierWithParent } from "./interfaces"; | ||
|
||
/** Gets the import path string for a default import */ | ||
export function getDefaultDeclarationString( | ||
defaultImportSpecifier: ImportDefaultSpecifierWithParent | ||
) { | ||
return defaultImportSpecifier?.parent?.source.value?.toString(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
23 changes: 23 additions & 0 deletions
23
packages/eslint-plugin-pf-codemods/src/rules/helpers/getNodeName.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { JSXOpeningElement, JSXMemberExpression } from "estree-jsx"; | ||
|
||
function getJSXMemberExpressionName(node: JSXMemberExpression) { | ||
switch (node.object.type) { | ||
case "JSXMemberExpression": | ||
return getJSXMemberExpressionName(node.object); | ||
case "JSXIdentifier": | ||
return node.object.name; | ||
} | ||
} | ||
|
||
/** Gets the name of an opening element */ | ||
export function getNodeName(node: JSXOpeningElement) { | ||
switch (node.name.type) { | ||
case "JSXMemberExpression": | ||
return getJSXMemberExpressionName(node.name); | ||
case "JSXIdentifier": | ||
case "JSXNamespacedName": | ||
return typeof node.name.name === "string" | ||
? node.name.name | ||
: node.name.name.name; | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
packages/eslint-plugin-pf-codemods/src/rules/helpers/hasCodemodDataTag.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { JSXOpeningElement } from "estree-jsx"; | ||
import { getCodeModDataTag } from "./getCodeModDataTag"; | ||
|
||
/** Returns true if the passed opening element has a data-codemods attribute */ | ||
export function hasCodeModDataTag(openingElement: JSXOpeningElement) { | ||
return !!getCodeModDataTag(openingElement) | ||
} |
6 changes: 6 additions & 0 deletions
6
packages/eslint-plugin-pf-codemods/src/rules/helpers/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 10 additions & 0 deletions
10
packages/eslint-plugin-pf-codemods/src/rules/helpers/interfaces.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,25 @@ | ||
import { | ||
Node, | ||
Identifier, | ||
ImportSpecifier, | ||
ImportDefaultSpecifier, | ||
ImportDeclaration, | ||
JSXOpeningElement, | ||
JSXElement, | ||
} from "estree-jsx"; | ||
|
||
export interface IdentifierWithParent extends Identifier { | ||
parent?: Node; | ||
} | ||
|
||
export interface ImportSpecifierWithParent extends ImportSpecifier { | ||
parent?: ImportDeclaration; | ||
} | ||
export interface ImportDefaultSpecifierWithParent | ||
extends ImportDefaultSpecifier { | ||
parent?: ImportDeclaration; | ||
} | ||
|
||
export interface JSXOpeningElementWithParent extends JSXOpeningElement { | ||
parent?: JSXElement; | ||
} |
117 changes: 117 additions & 0 deletions
117
packages/eslint-plugin-pf-codemods/src/rules/helpers/renameComponent.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
import { Rule } from "eslint"; | ||
import { getAllImportsFromPackage } from "./getFromPackage"; | ||
import { | ||
ImportSpecifierWithParent, | ||
ImportDefaultSpecifierWithParent, | ||
JSXOpeningElementWithParent, | ||
} from "./interfaces"; | ||
import { | ||
getDefaultDeclarationString, | ||
getComponentImportName, | ||
getNodeName, | ||
hasCodeModDataTag, | ||
} from "./index"; | ||
|
||
interface ComponentRenames { | ||
[currentName: string]: string; | ||
} | ||
|
||
function formatDefaultMessage(oldName: string, newName: string) { | ||
return `${oldName} has been renamed to ${newName}.`; | ||
} | ||
|
||
function getFixes( | ||
fixer: Rule.RuleFixer, | ||
nodeImport: ImportSpecifierWithParent | ImportDefaultSpecifierWithParent, | ||
node: JSXOpeningElementWithParent, | ||
oldName: string, | ||
newName: string | ||
) { | ||
const fixes = []; | ||
|
||
const isNamedImport = nodeImport.type === "ImportSpecifier"; | ||
const importDeclaration = nodeImport.parent; | ||
const importSource = importDeclaration?.source.raw; | ||
const importSourceHasComponentName = importSource?.includes(oldName); | ||
const newImportDeclaration = importSource?.replace(oldName, newName); | ||
|
||
if (isNamedImport) { | ||
fixes.push(fixer.replaceText(nodeImport.imported, newName)); | ||
} | ||
|
||
if ( | ||
importDeclaration && | ||
newImportDeclaration && | ||
importSourceHasComponentName | ||
) { | ||
fixes.push( | ||
fixer.replaceText(importDeclaration.source, newImportDeclaration) | ||
); | ||
} | ||
|
||
const shouldRenameNode = | ||
isNamedImport && nodeImport.imported.name === nodeImport.local.name; | ||
|
||
if (shouldRenameNode) { | ||
fixes.push(fixer.replaceText(node.name, newName)); | ||
fixes.push(fixer.insertTextAfter(node.name, " data-codemods")); | ||
} | ||
|
||
const closingElement = node?.parent?.closingElement; | ||
if (shouldRenameNode && closingElement) { | ||
fixes.push(fixer.replaceText(closingElement.name, newName)); | ||
} | ||
|
||
return fixes; | ||
} | ||
|
||
export function renameComponent( | ||
renames: ComponentRenames, | ||
packageName = "@patternfly/react-core" | ||
) { | ||
return function (context: Rule.RuleContext) { | ||
const oldNames = Object.keys(renames); | ||
const imports = getAllImportsFromPackage(context, packageName, oldNames); | ||
|
||
if (imports.length === 0) { | ||
return {}; | ||
} | ||
|
||
return { | ||
JSXOpeningElement(node: JSXOpeningElementWithParent) { | ||
if (hasCodeModDataTag(node)) { | ||
return; | ||
} | ||
|
||
const nodeName = getNodeName(node); | ||
const nodeImport = imports.find((imp) => { | ||
if (imp.type === "ImportSpecifier") { | ||
return [imp.imported.name, imp.local.name].includes(nodeName); | ||
} | ||
|
||
return oldNames.some((name) => | ||
getDefaultDeclarationString(imp)?.includes(name) | ||
); | ||
}); | ||
|
||
if (!nodeImport) { | ||
return; | ||
} | ||
|
||
const oldName = getComponentImportName(nodeImport, oldNames); | ||
|
||
if (!oldName) { | ||
return; | ||
} | ||
|
||
const newName = renames[oldName]; | ||
|
||
context.report({ | ||
node, | ||
message: formatDefaultMessage(oldName, newName), | ||
fix: (fixer) => getFixes(fixer, nodeImport, node, oldName, newName), | ||
}); | ||
}, | ||
}; | ||
}; | ||
} |
20 changes: 20 additions & 0 deletions
20
...nt-plugin-pf-codemods/src/rules/v6/mastheadNameChanges/masthead-name-changes.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
### masthead-name-changes [(#10809)](https://github.com/patternfly/patternfly-react/pull/10809) | ||
|
||
Our old implementation of `MastheadBrand` has been renamed to `MastheadLogo`, which must be wrapped by our new implementation of `MastheadBrand`." | ||
|
||
This rule will handle the renaming, required restructuring will be handled under a separate rule. | ||
|
||
#### Examples | ||
|
||
In: | ||
|
||
```jsx | ||
%inputExample% | ||
``` | ||
|
||
Out: | ||
|
||
```jsx | ||
%outputExample% | ||
``` | ||
|
78 changes: 78 additions & 0 deletions
78
.../eslint-plugin-pf-codemods/src/rules/v6/mastheadNameChanges/masthead-name-changes.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
const ruleTester = require("../../ruletester"); | ||
import * as rule from "./masthead-name-changes"; | ||
|
||
ruleTester.run("masthead-name-changes", rule, { | ||
valid: [ | ||
{ | ||
code: `<MastheadBrand />`, | ||
}, | ||
{ | ||
code: `import { MastheadBrand } from '@patternfly/react-core'; <MastheadBrand data-codemods />`, | ||
}, | ||
], | ||
invalid: [ | ||
{ | ||
code: `import { MastheadBrand } from '@patternfly/react-core'; <MastheadBrand />`, | ||
output: `import { MastheadLogo } from '@patternfly/react-core'; <MastheadLogo data-codemods />`, | ||
errors: [ | ||
{ | ||
message: `MastheadBrand has been renamed to MastheadLogo.`, | ||
type: "JSXOpeningElement", | ||
}, | ||
], | ||
}, | ||
// with other props | ||
{ | ||
code: `import { MastheadBrand } from '@patternfly/react-core'; <MastheadBrand className="foo" />`, | ||
output: `import { MastheadLogo } from '@patternfly/react-core'; <MastheadLogo data-codemods className="foo" />`, | ||
errors: [ | ||
{ | ||
message: `MastheadBrand has been renamed to MastheadLogo.`, | ||
type: "JSXOpeningElement", | ||
}, | ||
], | ||
}, | ||
// with alias | ||
{ | ||
code: `import { MastheadBrand as MB } from '@patternfly/react-core'; <MB />`, | ||
output: `import { MastheadLogo as MB } from '@patternfly/react-core'; <MB />`, | ||
errors: [ | ||
{ | ||
message: `MastheadBrand has been renamed to MastheadLogo.`, | ||
type: "JSXOpeningElement", | ||
}, | ||
], | ||
}, | ||
// dist imports | ||
{ | ||
code: `import { MastheadBrand } from '@patternfly/react-core/dist/esm/components/Masthead/MastheadBrand'; <MastheadBrand />`, | ||
output: `import { MastheadLogo } from '@patternfly/react-core/dist/esm/components/Masthead/MastheadLogo'; <MastheadLogo data-codemods />`, | ||
errors: [ | ||
{ | ||
message: `MastheadBrand has been renamed to MastheadLogo.`, | ||
type: "JSXOpeningElement", | ||
}, | ||
], | ||
}, | ||
{ | ||
code: `import { MastheadBrand } from '@patternfly/react-core/dist/js/components/Masthead/MastheadBrand'; <MastheadBrand />`, | ||
output: `import { MastheadLogo } from '@patternfly/react-core/dist/js/components/Masthead/MastheadLogo'; <MastheadLogo data-codemods />`, | ||
errors: [ | ||
{ | ||
message: `MastheadBrand has been renamed to MastheadLogo.`, | ||
type: "JSXOpeningElement", | ||
}, | ||
], | ||
}, | ||
{ | ||
code: `import { MastheadBrand } from '@patternfly/react-core/dist/dynamic/components/Masthead/MastheadBrand'; <MastheadBrand />`, | ||
output: `import { MastheadLogo } from '@patternfly/react-core/dist/dynamic/components/Masthead/MastheadLogo'; <MastheadLogo data-codemods />`, | ||
errors: [ | ||
{ | ||
message: `MastheadBrand has been renamed to MastheadLogo.`, | ||
type: "JSXOpeningElement", | ||
}, | ||
], | ||
}, | ||
], | ||
}); |
12 changes: 12 additions & 0 deletions
12
packages/eslint-plugin-pf-codemods/src/rules/v6/mastheadNameChanges/masthead-name-changes.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { renameComponent } from "../../helpers/renameComponent"; | ||
|
||
// https://github.com/patternfly/patternfly-react/pull/10809 | ||
|
||
const renames = { | ||
MastheadBrand: "MastheadLogo", | ||
}; | ||
|
||
module.exports = { | ||
meta: { fixable: "code" }, | ||
create: renameComponent(renames), | ||
}; |
3 changes: 3 additions & 0 deletions
3
...s/eslint-plugin-pf-codemods/src/rules/v6/mastheadNameChanges/mastheadNameChangesInput.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import { MastheadBrand } from "@patternfly/react-core"; | ||
|
||
export const MastheadNameChanges = () => <MastheadBrand>Logo</MastheadBrand>; |
3 changes: 3 additions & 0 deletions
3
.../eslint-plugin-pf-codemods/src/rules/v6/mastheadNameChanges/mastheadNameChangesOutput.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import { MastheadLogo } from "@patternfly/react-core"; | ||
|
||
export const MastheadNameChanges = () => <MastheadLogo data-codemods>Logo</MastheadLogo>; |