-
Notifications
You must be signed in to change notification settings - Fork 19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(componentGroups): rename InvalidObjectProps to MissingPageProps #799
base: main
Are you sure you want to change the base?
Changes from all commits
f725054
91aaa1b
a4ead58
b16ab25
2d4b3d2
61f5a6a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { ImportSpecifier } from "estree-jsx"; | ||
|
||
/** Used to check whether the current ImportSpecifier node matches at least 1 of the import specifiers. */ | ||
export function checkMatchingImportSpecifier( | ||
node: ImportSpecifier, | ||
imports: ImportSpecifier | ImportSpecifier[] | ||
) { | ||
if (Array.isArray(imports)) { | ||
return imports.some( | ||
(specifier) => specifier.imported.name === node.imported.name | ||
); | ||
} | ||
|
||
return imports.imported.name === node.imported.name; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import { Rule } from "eslint"; | ||
import { TSESTree } from "@typescript-eslint/utils"; | ||
import { Identifier, ImportSpecifier } from "estree-jsx"; | ||
import { getFromPackage } from "./getFromPackage"; | ||
import { checkMatchingImportSpecifier } from "./nodeMatches/checkMatchingImportSpecifier"; | ||
|
||
interface InterfaceRenames { | ||
[currentName: string]: string; | ||
} | ||
|
||
function formatDefaultMessage(oldName: string, newName: string) { | ||
return `${oldName} has been renamed to ${newName}.`; | ||
} | ||
|
||
export function renameInterface( | ||
renames: InterfaceRenames, | ||
packageName = "@patternfly/react-core" | ||
) { | ||
return function (context: Rule.RuleContext) { | ||
const oldNames = Object.keys(renames); | ||
const { imports } = getFromPackage(context, packageName, oldNames); | ||
|
||
if (imports.length === 0) { | ||
return {}; | ||
} | ||
|
||
const shouldRenameIdentifier = (identifier: Identifier) => { | ||
const matchingImport = imports.find( | ||
(specifier) => specifier.local.name === identifier.name | ||
); | ||
|
||
if (!matchingImport) { | ||
return false; | ||
} | ||
|
||
return matchingImport.local.name === matchingImport.imported.name; | ||
}; | ||
|
||
const replaceIdentifier = (identifier: Identifier) => { | ||
const oldName = identifier.name; | ||
const newName = renames[oldName]; | ||
|
||
context.report({ | ||
node: identifier, | ||
message: formatDefaultMessage(oldName, newName), | ||
fix(fixer) { | ||
return fixer.replaceText(identifier, newName); | ||
}, | ||
}); | ||
}; | ||
|
||
return { | ||
ImportSpecifier(node: ImportSpecifier) { | ||
if (!checkMatchingImportSpecifier(node, imports)) { | ||
return; | ||
} | ||
|
||
const oldName = node.imported.name; | ||
const newName = renames[oldName]; | ||
|
||
context.report({ | ||
node, | ||
message: formatDefaultMessage(oldName, newName), | ||
fix(fixer) { | ||
return fixer.replaceText(node.imported, newName); | ||
}, | ||
}); | ||
}, | ||
TSTypeReference(node: TSESTree.TSTypeReference) { | ||
if (node.typeName.type === "Identifier") { | ||
shouldRenameIdentifier(node.typeName) && | ||
replaceIdentifier(node.typeName); | ||
} | ||
}, | ||
TSInterfaceHeritage(node: TSESTree.TSInterfaceHeritage) { | ||
if (node.expression.type === "Identifier") { | ||
shouldRenameIdentifier(node.expression) && | ||
replaceIdentifier(node.expression); | ||
} | ||
}, | ||
}; | ||
}; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
### component-groups-invalidObjectProps-rename-to-missingPageProps [(react-component-groups/#313)](https://github.com/patternfly/react-component-groups/pull/313) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This isn't a blocker for this PR, but sorta wondering if this should really be its own separate rule or included as part of the pre-existing one (with a rename maybe). Really the question is, "should there be a single rule dealing with anything InvalidObject rename related?" Doing so would require a little refactoring both to the existing rule and the new helper here possibly, but also depends whether doing so would just bloat the existing rule too much. Having them separate may be more clear and understandable than trying to combine them, but curious what you think. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think ideally there should be just a single rule, but...
I am afraid it could end up being "a lot of" refactoring, given that the current
But maybe it will not be that easy |
||
|
||
In react-component-groups, we've renamed InvalidObjectProps interface to MissingPageProps | ||
|
||
#### Examples | ||
|
||
In: | ||
|
||
```jsx | ||
%inputExample% | ||
``` | ||
|
||
Out: | ||
|
||
```jsx | ||
%outputExample% | ||
``` | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
const ruleTester = require("../../ruletester"); | ||
import * as rule from "./component-groups-invalidObjectProps-rename-to-missingPageProps"; | ||
|
||
const message = `InvalidObjectProps has been renamed to MissingPageProps.`; | ||
|
||
ruleTester.run( | ||
"component-groups-invalidObjectProps-rename-to-missingPageProps", | ||
rule, | ||
{ | ||
valid: [ | ||
// missing import | ||
{ | ||
code: `const props: InvalidObjectProps;`, | ||
}, | ||
// import from wrong package | ||
{ | ||
code: `import { InvalidObjectProps } from '@patternfly/react-core';`, | ||
}, | ||
// import of other props | ||
{ | ||
code: `import { SomeOtherProps } from '@patternfly/react-component-groups';`, | ||
}, | ||
], | ||
invalid: [ | ||
{ | ||
code: `import { InvalidObjectProps, SomethingElse } from '@patternfly/react-component-groups'; | ||
const props: InvalidObjectProps; | ||
const otherProps = props as InvalidObjectProps; | ||
interface CustomProps extends InvalidObjectProps {};`, | ||
output: `import { MissingPageProps, SomethingElse } from '@patternfly/react-component-groups'; | ||
const props: MissingPageProps; | ||
const otherProps = props as MissingPageProps; | ||
interface CustomProps extends MissingPageProps {};`, | ||
errors: [ | ||
{ | ||
message, | ||
type: "ImportSpecifier", | ||
}, | ||
{ | ||
message, | ||
type: "Identifier", | ||
}, | ||
{ | ||
message, | ||
type: "Identifier", | ||
}, | ||
{ | ||
message, | ||
type: "Identifier", | ||
}, | ||
], | ||
}, | ||
// named import with alias | ||
{ | ||
code: `import { InvalidObjectProps as InvObjProps } from '@patternfly/react-component-groups'; | ||
const props: InvObjProps;`, | ||
output: `import { MissingPageProps as InvObjProps } from '@patternfly/react-component-groups'; | ||
const props: InvObjProps;`, | ||
errors: [ | ||
{ | ||
message, | ||
type: "ImportSpecifier", | ||
}, | ||
], | ||
}, | ||
// imports from dist | ||
{ | ||
code: `import { InvalidObjectProps } from '@patternfly/react-component-groups/dist/cjs/InvalidObject';`, | ||
output: `import { MissingPageProps } from '@patternfly/react-component-groups/dist/cjs/InvalidObject';`, | ||
errors: [ | ||
{ | ||
message, | ||
type: "ImportSpecifier", | ||
}, | ||
], | ||
}, | ||
{ | ||
code: `import { InvalidObjectProps } from '@patternfly/react-component-groups/dist/esm/InvalidObject';`, | ||
output: `import { MissingPageProps } from '@patternfly/react-component-groups/dist/esm/InvalidObject';`, | ||
errors: [ | ||
{ | ||
message, | ||
type: "ImportSpecifier", | ||
}, | ||
], | ||
}, | ||
{ | ||
code: `import { InvalidObjectProps } from '@patternfly/react-component-groups/dist/dynamic/InvalidObject';`, | ||
output: `import { MissingPageProps } from '@patternfly/react-component-groups/dist/dynamic/InvalidObject';`, | ||
errors: [ | ||
{ | ||
message, | ||
type: "ImportSpecifier", | ||
}, | ||
], | ||
}, | ||
], | ||
} | ||
); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { renameInterface } from "../../helpers"; | ||
|
||
// https://github.com/patternfly/react-component-groups/pull/313 | ||
module.exports = { | ||
meta: { fixable: "code" }, | ||
create: renameInterface( | ||
{ | ||
InvalidObjectProps: "MissingPageProps", | ||
}, | ||
"@patternfly/react-component-groups" | ||
), | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import { InvalidObjectProps } from "@patternfly/react-component-groups"; | ||
|
||
const props: InvalidObjectProps; | ||
interface CustomProps extends InvalidObjectProps {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import { MissingPageProps } from "@patternfly/react-component-groups"; | ||
|
||
const props: MissingPageProps; | ||
interface CustomProps extends MissingPageProps {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a blocker, but wondering if we should add a directory to
helpers
for these sort of default message functions.defaultMessages
as the directory ->renameIdentifier.tsx
as this helper for example. Or just yanking this out as its own individual helper to be reused elsewhere.