From 4c7d9dabb1cd59cbaadac81bca290133c611f1c3 Mon Sep 17 00:00:00 2001 From: Eric Olkowski <70952936+thatblindgeye@users.noreply.github.com> Date: Tue, 6 Aug 2024 10:32:00 -0400 Subject: [PATCH] chore(generators): made enhancements to generator files (#719) * chore(generators): made enhancements to generator files * Updated generator for default imports --- generators/src/helpers.js | 5 - generators/src/helpers.ts | 5 + generators/src/plop-interfaces.ts | 1 + generators/src/write-readme.ts | 16 +- generators/src/write-rule.ts | 34 ++-- .../src/rules/helpers/index.ts | 1 + .../src/rules/helpers/nodeMatches.ts | 24 +++ .../accordionItem-warn-update-markup.ts | 7 +- plopFile.cjs | 147 ++++++++---------- 9 files changed, 126 insertions(+), 114 deletions(-) delete mode 100644 generators/src/helpers.js create mode 100644 generators/src/helpers.ts create mode 100644 packages/eslint-plugin-pf-codemods/src/rules/helpers/nodeMatches.ts diff --git a/generators/src/helpers.js b/generators/src/helpers.js deleted file mode 100644 index 967503fe9..000000000 --- a/generators/src/helpers.js +++ /dev/null @@ -1,5 +0,0 @@ -function betterStringSort(a, b) { - return a.toLowerCase().localeCompare(b.toLowerCase()) -} - -module.exports = { betterStringSort } \ No newline at end of file diff --git a/generators/src/helpers.ts b/generators/src/helpers.ts new file mode 100644 index 000000000..a8636ee9e --- /dev/null +++ b/generators/src/helpers.ts @@ -0,0 +1,5 @@ +function betterStringSort(a: string, b: string) { + return a.toLowerCase().localeCompare(b.toLowerCase()); +} + +module.exports = { betterStringSort }; diff --git a/generators/src/plop-interfaces.ts b/generators/src/plop-interfaces.ts index 4edcecbac..f260c94a8 100644 --- a/generators/src/plop-interfaces.ts +++ b/generators/src/plop-interfaces.ts @@ -2,6 +2,7 @@ export interface Answers { componentName: string; propName: string; ruleName: string; + referenceRepo: string; referencePR: string; message?: string; } diff --git a/generators/src/write-readme.ts b/generators/src/write-readme.ts index a7d4c12f7..4880fc293 100644 --- a/generators/src/write-readme.ts +++ b/generators/src/write-readme.ts @@ -3,7 +3,17 @@ import { outputFile } from "fs-extra"; import { camelCase } from "case-anything"; import { Answers } from "./plop-interfaces"; -async function baseReadme({ referencePR, ruleName, message }: Answers) { +export enum RepoNames { + react = "patternfly-react", + componentGroups = "react-component-groups", +} + +async function baseReadme({ + referenceRepo, + referencePR, + ruleName, + message, +}: Answers) { const camelCaseRuleName = camelCase(ruleName); const readMePath = join( require @@ -15,7 +25,9 @@ async function baseReadme({ referencePR, ruleName, message }: Answers) { `${ruleName}.md` ); - const readMeContent = `### ${ruleName} [(#${referencePR})](https://github.com/patternfly/patternfly-react/pull/${referencePR}) + const prLinkTextPrefix = + referenceRepo === RepoNames.react ? "" : `${referenceRepo}/`; + const readMeContent = `### ${ruleName} [(${prLinkTextPrefix}#${referencePR})](https://github.com/patternfly/${referenceRepo}/pull/${referencePR}) ${message} diff --git a/generators/src/write-rule.ts b/generators/src/write-rule.ts index d1b6de9c8..148d0021a 100644 --- a/generators/src/write-rule.ts +++ b/generators/src/write-rule.ts @@ -22,44 +22,34 @@ export async function genericRule({ componentName, propName, ruleName, + referenceRepo, referencePR, message, }: Answers) { // the formatting for content here looks weird, but that's to preserve indentation in the written file const content = `import { Rule } from "eslint"; import { JSXOpeningElement } from "estree-jsx"; -import { getFromPackage } from "../../helpers"; +import { getAllImportsFromPackage, checkMatchingJSXOpeningElement, getAttribute } from "../../helpers"; -// https://github.com/patternfly/patternfly-react/pull/${referencePR} +// https://github.com/patternfly/${referenceRepo}/pull/${referencePR} module.exports = { meta: { fixable: "code" }, create: function (context: Rule.RuleContext) { - const { imports } = getFromPackage(context, "@patternfly/react-core"); - - const componentImports = imports.filter( - (specifier) => specifier.imported.name === "${componentName}" - ); + const basePackage = "@patternfly/react-core"; + const componentImports = getAllImportsFromPackage(context, basePackage, ["${componentName}"]); return !componentImports.length ? {} : { JSXOpeningElement(node: JSXOpeningElement) { - if ( - node.name.type === "JSXIdentifier" && - componentImports - .map((imp) => imp.local.name) - .includes(node.name.name) - ) { - const attribute = node.attributes.find( - (attr) => - attr.type === "JSXAttribute" && attr.name.name === "${propName}" - ); - if (attribute) { + if (checkMatchingJSXOpeningElement(node, componentImports)) { + const ${propName}Prop = getAttribute(node, "${propName}"); + if (${propName}Prop) { context.report({ node, message: "${message}", fix(fixer) { - return fixer.replaceText(attribute, ""); + return fixer.replaceText(${propName}Prop, ""); }, }); } @@ -76,11 +66,12 @@ export async function addEventCBRule({ componentName, propName, ruleName, + referenceRepo, referencePR, }: Answers) { const content = `const { addCallbackParam } = require("../../helpers"); -// https://github.com/patternfly/patternfly-react/pull/${referencePR} +// https://github.com/patternfly/${referenceRepo}/pull/${referencePR} module.exports = { meta: { fixable: "code" }, create: addCallbackParam(["${componentName}"], { ${propName}: "_event" }), @@ -93,11 +84,12 @@ export async function swapCBRule({ componentName, propName, ruleName, + referenceRepo, referencePR, }: Answers) { const content = `const { addCallbackParam } = require("../../helpers"); -// https://github.com/patternfly/patternfly-react/pull/${referencePR} +// https://github.com/patternfly/${referenceRepo}/pull/${referencePR} module.exports = { meta: { fixable: "code" }, create: addCallbackParam(["${componentName}"], { ${propName}: { defaultParamName: "_event", previousParamIndex: 1, otherMatchers: /^_?(ev\\w*|e$)/ } }), diff --git a/packages/eslint-plugin-pf-codemods/src/rules/helpers/index.ts b/packages/eslint-plugin-pf-codemods/src/rules/helpers/index.ts index a0a6707f2..88173d615 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/helpers/index.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/index.ts @@ -10,6 +10,7 @@ export * from "./includesImport"; export * from "./interfaces"; export * from "./JSXAttributes"; export * from "./JSXElements"; +export * from "./nodeMatches"; export * from "./pfPackageMatches"; export * from "./removeElement"; export * from "./removeEmptyLineAfter"; diff --git a/packages/eslint-plugin-pf-codemods/src/rules/helpers/nodeMatches.ts b/packages/eslint-plugin-pf-codemods/src/rules/helpers/nodeMatches.ts new file mode 100644 index 000000000..1d3657947 --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/src/rules/helpers/nodeMatches.ts @@ -0,0 +1,24 @@ +import { + JSXOpeningElement, + ImportSpecifier, + ImportDefaultSpecifier, +} from "estree-jsx"; + +export function checkMatchingJSXOpeningElement( + node: JSXOpeningElement, + imports: + | ImportSpecifier + | ImportDefaultSpecifier + | (ImportSpecifier | ImportDefaultSpecifier)[] +) { + if (Array.isArray(imports)) { + return ( + node.name.type === "JSXIdentifier" && + imports.map((imp) => imp.local.name).includes(node.name.name) + ); + } + + return ( + node.name.type === "JSXIdentifier" && imports.local.name === node.name.name + ); +} diff --git a/packages/eslint-plugin-pf-codemods/src/rules/v6/accordionItemWarnUpdateMarkup/accordionItem-warn-update-markup.ts b/packages/eslint-plugin-pf-codemods/src/rules/v6/accordionItemWarnUpdateMarkup/accordionItem-warn-update-markup.ts index 4a0714515..ce32d9a25 100644 --- a/packages/eslint-plugin-pf-codemods/src/rules/v6/accordionItemWarnUpdateMarkup/accordionItem-warn-update-markup.ts +++ b/packages/eslint-plugin-pf-codemods/src/rules/v6/accordionItemWarnUpdateMarkup/accordionItem-warn-update-markup.ts @@ -1,4 +1,4 @@ -import { getFromPackage } from "../../helpers"; +import { getFromPackage, checkMatchingJSXOpeningElement } from "../../helpers"; import { Rule } from "eslint"; import { JSXOpeningElement } from "estree-jsx"; @@ -17,10 +17,7 @@ module.exports = { ? {} : { JSXOpeningElement(node: JSXOpeningElement) { - if ( - node.name.type === "JSXIdentifier" && - accordionItemImport.local.name === node.name.name - ) { + if (checkMatchingJSXOpeningElement(node, accordionItemImport)) { context.report({ node, message: diff --git a/plopFile.cjs b/plopFile.cjs index 3f5ad59ab..7d569313c 100644 --- a/plopFile.cjs +++ b/plopFile.cjs @@ -9,9 +9,10 @@ const { swapCBTest, } = require("./generators/dist/js/write-test"); const { + RepoNames, genericReadme, addEventCBReadme, - swapCBReadme + swapCBReadme, } = require("./generators/dist/js/write-readme"); const { genericTestSingle, @@ -19,6 +20,38 @@ const { swapCBTestSingle, } = require("./generators/dist/js/write-test-single"); +const componentNamePrompt = { + type: "input", + name: "componentName", + message: "What is the name of the component being changed? (PascalCase)", +}; +const propNamePrompt = { + type: "input", + name: "propName", + message: "What is the name of the prop being changed? (camelCase)", +}; +const ruleNamePrompt = { + type: "input", + name: "ruleName", + message: "What should the name of this rule be? (kebab-case)", +}; +const referenceRepoPrompt = { + type: "list", + name: "referenceRepo", + message: "What is the repo the PR was made in", + choices: Object.values(RepoNames), +}; +const referencePrPrompt = { + type: "input", + name: "referencePR", + message: "What is the PR reference number", +}; +const messagePrompt = { + type: "input", + name: "message", + message: "What message should the codemod send? (Sentence case)", +}; + module.exports = function (plop) { plop.setActionType("generateRule", async function (answers, config, plop) { console.log("Generating rule file", answers.ruleName); @@ -62,49 +95,32 @@ module.exports = function (plop) { } }); - plop.setActionType("generateTestSingle", async function (answers, config, plop) { - console.log("Generating tsx files for", answers.ruleName); - switch (config.generatorSelection) { - case "addEventCB": - await addEventCBTestSingle(answers); - break; - case "swapCB": - await swapCBTestSingle(answers); - break; - default: - await genericTestSingle(answers); + plop.setActionType( + "generateTestSingle", + async function (answers, config, plop) { + console.log("Generating tsx files for", answers.ruleName); + switch (config.generatorSelection) { + case "addEventCB": + await addEventCBTestSingle(answers); + break; + case "swapCB": + await swapCBTestSingle(answers); + break; + default: + await genericTestSingle(answers); + } } - }); + ); plop.setGenerator("generic", { description: "create a generic new rule", prompts: [ - { - type: "input", - name: "componentName", - message: - "What is the name of the component being changed? (PascalCase)", - }, - { - type: "input", - name: "propName", - message: "What is the name of the prop being changed? (camelCase)", - }, - { - type: "input", - name: "ruleName", - message: "What should the name of this rule be? (kebab-case)", - }, - { - type: "input", - name: "referencePR", - message: "What is the PR reference number", - }, - { - type: "input", - name: "message", - message: "What message should the codemod send? (Sentence case)", - }, + componentNamePrompt, + propNamePrompt, + ruleNamePrompt, + referenceRepoPrompt, + referencePrPrompt, + messagePrompt, ], actions: [ { @@ -125,27 +141,12 @@ module.exports = function (plop) { plop.setGenerator("add event parameter", { description: "add an event parameter to the front of a callback", prompts: [ - { - type: "input", - name: "componentName", - message: - "What is the name of the component being changed? (PascalCase)", - }, - { - type: "input", - name: "propName", - message: "What is the name of the prop being changed? (camelCase)", - }, - { - type: "input", - name: "ruleName", - message: "What should the name of this rule be? (kebab-case)", - }, - { - type: "input", - name: "referencePR", - message: "What is the PR reference number", - }, + componentNamePrompt, + propNamePrompt, + ruleNamePrompt, + referenceRepoPrompt, + referencePrPrompt, + , ], actions: [ { @@ -170,27 +171,11 @@ module.exports = function (plop) { plop.setGenerator("swap parameter", { description: "move the position of a parameter in a callback to the front", prompts: [ - { - type: "input", - name: "componentName", - message: - "What is the name of the component being changed? (PascalCase)", - }, - { - type: "input", - name: "propName", - message: "What is the name of the prop being changed? (camelCase)", - }, - { - type: "input", - name: "ruleName", - message: "What should the name of this rule be? (kebab-case)", - }, - { - type: "input", - name: "referencePR", - message: "What is the PR reference number", - }, + componentNamePrompt, + propNamePrompt, + ruleNamePrompt, + referenceRepoPrompt, + referencePrPrompt, ], actions: [ {