diff --git a/packages/eslint-plugin-pf-codemods/src/ruleCustomization.ts b/packages/eslint-plugin-pf-codemods/src/ruleCustomization.ts index 3fd012fe5..0174768ef 100644 --- a/packages/eslint-plugin-pf-codemods/src/ruleCustomization.ts +++ b/packages/eslint-plugin-pf-codemods/src/ruleCustomization.ts @@ -16,6 +16,7 @@ export const warningRules = [ "emptyState-warn-change-structure", "formControls-updated-markup", "horizontalSubnav-warn-ariaLabel", + "jumpLinksItem-warn-markup-change", "label-warn-truncated-default", "nav-warn-flyouts-now-inline", "overflowMenu-warn-updated-dropdownItem", diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemHrefRequired/jumpLinksItem-href-required.md b/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemHrefRequired/jumpLinksItem-href-required.md new file mode 100644 index 000000000..4f41bd6b6 --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemHrefRequired/jumpLinksItem-href-required.md @@ -0,0 +1,3 @@ +### jumpLinksItem-href-required [(#10027)](https://github.com/patternfly/patternfly-react/pull/10027) + +The `href` prop on JumpLinksItem is now required. diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemHrefRequired/jumpLinksItem-href-required.test.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemHrefRequired/jumpLinksItem-href-required.test.ts new file mode 100644 index 000000000..3fa1456d4 --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemHrefRequired/jumpLinksItem-href-required.test.ts @@ -0,0 +1,35 @@ +const ruleTester = require("../../ruletester"); +import * as rule from "./jumpLinksItem-href-required"; + +ruleTester.run("jumpLinksItem-href-required", rule, { + valid: [ + { + code: `import { JumpLinksItem } from 'someOtherPackage'; `, + }, + { + code: `import { JumpLinksItem } from '@patternfly/react-core'; `, + }, + ], + invalid: [ + { + code: `import { JumpLinksItem } from '@patternfly/react-core'; `, + output: `import { JumpLinksItem } from '@patternfly/react-core'; `, + errors: [ + { + message: `The \`href\` prop on JumpLinksItem is now required.`, + type: "JSXOpeningElement", + }, + ], + }, + { + code: `import { JumpLinksItem } from '@patternfly/react-core'; `, + output: `import { JumpLinksItem } from '@patternfly/react-core'; `, + errors: [ + { + message: `The \`href\` prop on JumpLinksItem is now required.`, + type: "JSXOpeningElement", + }, + ], + }, + ], +}); diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemHrefRequired/jumpLinksItem-href-required.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemHrefRequired/jumpLinksItem-href-required.ts new file mode 100644 index 000000000..d76b3bf4c --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemHrefRequired/jumpLinksItem-href-required.ts @@ -0,0 +1,39 @@ +import { getFromPackage } from "../../helpers"; +import { Rule } from "eslint"; +import { JSXOpeningElement, JSXAttribute } from "estree-jsx"; + +// https://github.com/patternfly/patternfly-react/pull/10027 +module.exports = { + meta: {}, + create: function (context: Rule.RuleContext) { + const { imports } = getFromPackage(context, "@patternfly/react-core"); + + const jumpLinksItemImport = imports.find( + (specifier) => specifier.imported.name === "JumpLinksItem" + ); + + return !jumpLinksItemImport + ? {} + : { + JSXOpeningElement(node: JSXOpeningElement) { + if ( + node.name.type === "JSXIdentifier" && + jumpLinksItemImport.local.name === node.name.name + ) { + const hrefAttribute = node.attributes.find( + (attribute) => + attribute.type === "JSXAttribute" && + attribute.name.name === "href" + ); + + if (!hrefAttribute || !(hrefAttribute as JSXAttribute).value) { + context.report({ + node, + message: "The `href` prop on JumpLinksItem is now required.", + }); + } + } + }, + }; + }, +}; diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemHrefRequired/jumpLinksItemHrefRequiredInput.tsx b/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemHrefRequired/jumpLinksItemHrefRequiredInput.tsx new file mode 100644 index 000000000..1635e8073 --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemHrefRequired/jumpLinksItemHrefRequiredInput.tsx @@ -0,0 +1,8 @@ +import { JumpLinksItem } from "@patternfly/react-core"; + +export const JumpLinksItemWarnMarkupChangeInput = () => ( + <> + + + +); diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemHrefRequired/jumpLinksItemHrefRequiredOutput.tsx b/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemHrefRequired/jumpLinksItemHrefRequiredOutput.tsx new file mode 100644 index 000000000..1635e8073 --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemHrefRequired/jumpLinksItemHrefRequiredOutput.tsx @@ -0,0 +1,8 @@ +import { JumpLinksItem } from "@patternfly/react-core"; + +export const JumpLinksItemWarnMarkupChangeInput = () => ( + <> + + + +); diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemWarnMarkupChange/jumpLinksItem-warn-markup-change.md b/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemWarnMarkupChange/jumpLinksItem-warn-markup-change.md new file mode 100644 index 000000000..0b26b83e9 --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemWarnMarkupChange/jumpLinksItem-warn-markup-change.md @@ -0,0 +1,3 @@ +### jumpLinksItem-warn-markup-change [(#10027)](https://github.com/patternfly/patternfly-react/pull/10027) + +The markup for JumpLinksItem has changed, as it now uses our Button component internally. Additionally, the `onClick` prop type has been updated to just `React.MouseEvent` (previously `React.MouseEvent`). diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemWarnMarkupChange/jumpLinksItem-warn-markup-change.test.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemWarnMarkupChange/jumpLinksItem-warn-markup-change.test.ts new file mode 100644 index 000000000..d47341246 --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemWarnMarkupChange/jumpLinksItem-warn-markup-change.test.ts @@ -0,0 +1,22 @@ +const ruleTester = require("../../ruletester"); +import * as rule from "./jumpLinksItem-warn-markup-change"; + +ruleTester.run("jumpLinksItem-warn-markup-change", rule, { + valid: [ + { + code: `import { JumpLinksItem } from '@someOtherPackage';`, + }, + ], + invalid: [ + { + code: `import { JumpLinksItem } from '@patternfly/react-core';`, + output: `import { JumpLinksItem } from '@patternfly/react-core';`, + errors: [ + { + message: `The markup for JumpLinksItem has changed, as it now uses our Button component internally. Additionally, the \`onClick\` prop type has been updated to just \`React.MouseEvent\` (previously \`React.MouseEvent\`).`, + type: "ImportDeclaration", + }, + ], + }, + ], +}); diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemWarnMarkupChange/jumpLinksItem-warn-markup-change.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemWarnMarkupChange/jumpLinksItem-warn-markup-change.ts new file mode 100644 index 000000000..b1552c455 --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemWarnMarkupChange/jumpLinksItem-warn-markup-change.ts @@ -0,0 +1,35 @@ +import { getFromPackage } from "../../helpers"; +import { Rule } from "eslint"; +import { ImportDeclaration, ImportSpecifier } from "estree-jsx"; + +// https://github.com/patternfly/patternfly-react/pull/10027 +module.exports = { + meta: {}, + create: function (context: Rule.RuleContext) { + const { imports } = getFromPackage(context, "@patternfly/react-core"); + + const jumpLinksItemImport = imports.find( + (specifier) => specifier.imported.name === "JumpLinksItem" + ); + + return !jumpLinksItemImport + ? {} + : { + ImportDeclaration(node: ImportDeclaration) { + if ( + node.specifiers.find( + (specifier) => + specifier.type === "ImportSpecifier" && + specifier.imported.name === jumpLinksItemImport.imported.name + ) + ) { + context.report({ + node, + message: + "The markup for JumpLinksItem has changed, as it now uses our Button component internally. Additionally, the `onClick` prop type has been updated to just `React.MouseEvent` (previously `React.MouseEvent`).", + }); + } + }, + }; + }, +}; diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemWarnMarkupChange/jumpLinksItemWarnMarkupChangeInput.tsx b/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemWarnMarkupChange/jumpLinksItemWarnMarkupChangeInput.tsx new file mode 100644 index 000000000..1982b083d --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemWarnMarkupChange/jumpLinksItemWarnMarkupChangeInput.tsx @@ -0,0 +1 @@ +import { JumpLinksItem } from "@patternfly/react-core"; diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemWarnMarkupChange/jumpLinksItemWarnMarkupChangeOutput.tsx b/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemWarnMarkupChange/jumpLinksItemWarnMarkupChangeOutput.tsx new file mode 100644 index 000000000..1982b083d --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/jumpLinksItemWarnMarkupChange/jumpLinksItemWarnMarkupChangeOutput.tsx @@ -0,0 +1 @@ +import { JumpLinksItem } from "@patternfly/react-core"; diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/pageSectionUpdateVariantValues/pageSection-update-variant-values.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/pageSectionUpdateVariantValues/pageSection-update-variant-values.ts index 661fc23d2..6a395a44d 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/pageSectionUpdateVariantValues/pageSection-update-variant-values.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/pageSectionUpdateVariantValues/pageSection-update-variant-values.ts @@ -1,39 +1,39 @@ import { getFromPackage } from "../../helpers"; +import { Rule } from "eslint"; +import { JSXOpeningElement, JSXAttribute, Literal } from "estree-jsx"; +import { isJsxAttribute } from "typescript"; // https://github.com/patternfly/patternfly-react/pull/9774 // https://github.com/patternfly/patternfly-react/pull/9848 module.exports = { meta: { fixable: "code" }, - create: function (context: { - report: (arg0: { - node: any; - message: string; - fix(fixer: any): any; - }) => void; - }) { + create: function (context: Rule.RuleContext) { const { imports } = getFromPackage(context, "@patternfly/react-core"); - const componentImports = imports.filter( - (specifier: { imported: { name: string } }) => - specifier.imported.name === "PageSection" + const pageSectionImport = imports.find( + (specifier) => specifier.imported.name === "PageSection" ); - return !componentImports.length + return !pageSectionImport ? {} : { - JSXOpeningElement(node: { name: { name: any }; attributes: any[] }) { + JSXOpeningElement(node: JSXOpeningElement) { if ( - componentImports - .map((imp: { local: { name: any } }) => imp.local.name) - .includes(node.name.name) + node.name.type === "JSXIdentifier" && + pageSectionImport.local.name === node.name.name ) { const attribute = node.attributes.find( - (attr: { name: { name: string } }) => - attr.name?.name === "variant" - ); + (attr) => + attr.type === "JSXAttribute" && attr.name.name === "variant" + ) as JSXAttribute | undefined; + + if (!attribute || !attribute.value) { + return; + } if ( - attribute && + attribute.value.type === "Literal" && + typeof attribute.value.value === "string" && !["default", "secondary"].includes(attribute.value.value) ) { context.report({ diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/pageSectionWarnVariantClassesApplied/pageSection-warn-variantClasses-applied.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/pageSectionWarnVariantClassesApplied/pageSection-warn-variantClasses-applied.ts index b8591086e..57f038f34 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/pageSectionWarnVariantClassesApplied/pageSection-warn-variantClasses-applied.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/pageSectionWarnVariantClassesApplied/pageSection-warn-variantClasses-applied.ts @@ -1,34 +1,28 @@ import { getFromPackage } from "../../helpers"; +import { Rule } from "eslint"; +import { JSXOpeningElement } from "estree-jsx"; // https://github.com/patternfly/patternfly-react/pull/9848 module.exports = { meta: {}, - create: function (context: { - report: (arg0: { - node: any; - message: string; - fix?(fixer: any): any; - }) => void; - }) { + create: function (context: Rule.RuleContext) { const { imports } = getFromPackage(context, "@patternfly/react-core"); - const componentImports = imports.filter( - (specifier: { imported: { name: string } }) => - specifier.imported.name === "PageSection" + const pageSectionImport = imports.find( + (specifier) => specifier.imported.name === "PageSection" ); - return !componentImports.length + return !pageSectionImport ? {} : { - JSXOpeningElement(node: { name: { name: any }; attributes: any[] }) { + JSXOpeningElement(node: JSXOpeningElement) { if ( - componentImports - .map((imp: { local: { name: any } }) => imp.local.name) - .includes(node.name.name) + node.name.type === "JSXIdentifier" && + pageSectionImport.local.name === node.name.name ) { const attribute = node.attributes.find( - (attr: { name: { name: string } }) => - attr.name?.name === "variant" + (attr) => + attr.type === "JSXAttribute" && attr.name.name === "variant" ); if (attribute) { context.report({