From 1194c4dc6678e169269342a2691d0fb8f9c35ad7 Mon Sep 17 00:00:00 2001 From: Joachim Schuler Date: Tue, 26 May 2020 10:03:17 -0400 Subject: [PATCH 1/6] add tabtitletext --- packages/eslint-plugin-pf-codemods/index.js | 3 +- .../lib/rules/tab-title-text.js | 51 +++++++++++++++++++ .../test/rules/tab-title-text.js | 24 +++++++++ test/test.tsx | 21 +++++++- 4 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 packages/eslint-plugin-pf-codemods/lib/rules/tab-title-text.js create mode 100644 packages/eslint-plugin-pf-codemods/test/rules/tab-title-text.js diff --git a/packages/eslint-plugin-pf-codemods/index.js b/packages/eslint-plugin-pf-codemods/index.js index 85fd5ccf9..7a3b0c261 100644 --- a/packages/eslint-plugin-pf-codemods/index.js +++ b/packages/eslint-plugin-pf-codemods/index.js @@ -11,9 +11,10 @@ const rules = { "select-rename-isExpanded": require('./lib/rules/select-rename-isExpanded'), "title-require-heading-level": require('./lib/rules/title-require-heading-level'), "title-size": require('./lib/rules/title-size'), - "wizard-text": require('./lib/rules/wizard-text'), + "wizard-text": require('./lib/rules/wizard-rename-text'), "wizard-rename-hasBodyPadding": require('./lib/rules/wizard-rename-hasBodyPadding'), "wizard-remove-props": require('./lib/rules/wizard-remove-props'), + "tab-title-text": require('./lib/rules/tab-title-text'), }; module.exports = { diff --git a/packages/eslint-plugin-pf-codemods/lib/rules/tab-title-text.js b/packages/eslint-plugin-pf-codemods/lib/rules/tab-title-text.js new file mode 100644 index 000000000..5d7ce7d2e --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/lib/rules/tab-title-text.js @@ -0,0 +1,51 @@ +const { getPackageImports } = require('../helpers'); + +// https://github.com/patternfly/patternfly-react/pull/4146 +module.exports = { + create: function(context) { + const imports = getPackageImports(context, '@patternfly/react-core') + .filter(specifier => specifier.imported.name === 'Tab'); + const pfImport = context.getSourceCode().ast.body + .filter(node => node.type === 'ImportDeclaration' && node.source.value === '@patternfly/react-core'); + pfImport.forEach(imp => console.log(imp.type)); + + return !imports ? {} : { + JSXOpeningElement(node) { + if (imports.map(imp => imp.local.name).includes(node.name.name)) { + const attribute = node.attributes.find(node => node.name.name === 'title'); + if (attribute) { + const { value } = attribute; + let replacement; + if (value.type === 'Literal') { + // i.e. title="Title" + replacement = fixer => fixer.replaceText(attribute.value, `{${attribute.value.value}}`); + } else if (value.type === 'JSXExpressionContainer') { + if (value.expression.type === 'Literal') { + // i.e. title={'Title'} or title={100} + replacement = fixer => fixer.replaceText(attribute.value, `{${attribute.value.expression.value}}`); + } else if (value.expression.type === 'Identifier') { + // i.e. title={myVariable} + replacement = fixer => fixer.replaceText(attribute.value, `{{${attribute.value.expression.name}}}`); + } else if (value.expression.type === 'JSXElement' && value.expression.openingElement.name.name !== 'TabTitleText') { + // i.e. title={} + replacement = fixer => [ + fixer.insertTextBefore(attribute.value.expression, ``), + fixer.insertTextAfter(attribute.value.expression, ``) + ]; + } + } + if (replacement) { + context.report({ + node, + message: `title needs to be wrapped with the TabTitleText and/or TabTitleIcon component`, + fix(fixer) { + return replacement(fixer); + } + }); + } + } + } + } + }; + } +}; diff --git a/packages/eslint-plugin-pf-codemods/test/rules/tab-title-text.js b/packages/eslint-plugin-pf-codemods/test/rules/tab-title-text.js new file mode 100644 index 000000000..e570a51c8 --- /dev/null +++ b/packages/eslint-plugin-pf-codemods/test/rules/tab-title-text.js @@ -0,0 +1,24 @@ +const ruleTester = require('./ruletester'); +const rule = require('../../lib/rules/tab-title-text'); + +ruleTester.run("tab-title-text", rule, { + valid: [ + { + code: `import { Tab } from '@patternfly/react-core'; Title}>Content`, + }, + { + // No @patternfly/react-core import + code: `Content`, + } + ], + invalid: [ + { + code: `import { Tab } from '@patternfly/react-core'; Content`, + output: `import { Tab } from '@patternfly/react-core'; Title}>Content`, + errors: [{ + message: `title needs to be wrapped with the TabTitleText and/or TabTitleIcon component`, + type: "JSXOpeningElement", + }] + }, + ] +}); diff --git a/test/test.tsx b/test/test.tsx index f2ccec006..730d934a0 100644 --- a/test/test.tsx +++ b/test/test.tsx @@ -1,7 +1,7 @@ import { Title, Title as MyTitle } from '@patternfly/react-core'; -export const Thing1 = () => Title; -export const Thing2 = () => Title; +export const Thing1 = () => Title; +export const Thing2 = () => Title; import { List, ListVariant } from '@patternfly/react-core'; @@ -24,3 +24,20 @@ export const MyButtonWithCustomEnum = (