From 5794a420e667c76ef50af34574fca45685e4caf7 Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Thu, 11 Sep 2025 20:37:34 +0000 Subject: [PATCH 1/3] Update rule to check sub components and imports --- .../__tests__/use-styled-react-import.test.js | 14 ++++++++++++++ src/rules/use-styled-react-import.js | 15 ++++++++++----- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/rules/__tests__/use-styled-react-import.test.js b/src/rules/__tests__/use-styled-react-import.test.js index bd11ae7d..bc2697c0 100644 --- a/src/rules/__tests__/use-styled-react-import.test.js +++ b/src/rules/__tests__/use-styled-react-import.test.js @@ -56,6 +56,20 @@ ruleTester.run('use-styled-react-import', rule, { ], }, + // Invalid: ActionList.Item with sx prop and ActionList imported from @primer/react + { + code: `import { ActionList } from '@primer/react' + const Component = () => Content`, + output: `import { ActionList } from '@primer/styled-react' + const Component = () => Content`, + errors: [ + { + messageId: 'useStyledReactImport', + data: {componentName: 'ActionList'}, + }, + ], + }, + // Invalid: Button with sx prop imported from @primer/react { code: `import { Button } from '@primer/react' diff --git a/src/rules/use-styled-react-import.js b/src/rules/use-styled-react-import.js index b4ba55bd..5c54429c 100644 --- a/src/rules/use-styled-react-import.js +++ b/src/rules/use-styled-react-import.js @@ -105,9 +105,14 @@ module.exports = { // Check if this is an aliased component from styled-react const originalComponentName = aliasMapping.get(componentName) || componentName + // For compound components like "ActionList.Item", we need to check the parent component + const parentComponentName = originalComponentName.includes('.') + ? originalComponentName.split('.')[0] + : originalComponentName + // Track all used components that are in our styled components list - if (styledComponents.has(originalComponentName)) { - allUsedComponents.add(originalComponentName) + if (styledComponents.has(parentComponentName)) { + allUsedComponents.add(parentComponentName) // Check if this component has an sx prop const hasSxProp = openingElement.attributes.some( @@ -115,17 +120,17 @@ module.exports = { ) if (hasSxProp) { - componentsWithSx.add(originalComponentName) + componentsWithSx.add(parentComponentName) jsxElementsWithSx.push({node, componentName: originalComponentName, openingElement}) } else { - componentsWithoutSx.add(originalComponentName) + componentsWithoutSx.add(parentComponentName) // If this is an aliased component without sx, we need to track it for renaming if (aliasMapping.has(componentName)) { jsxElementsWithoutSx.push({ node, localName: componentName, - originalName: originalComponentName, + originalName: parentComponentName, openingElement, }) } From 0c4524b4a714f1d8e52df13d065ebee2ba51a9dd Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Thu, 11 Sep 2025 20:50:23 +0000 Subject: [PATCH 2/3] When a component is aliased all sub components also get aliased. --- .../__tests__/use-styled-react-import.test.js | 33 +++++++++++++++++++ src/rules/use-styled-react-import.js | 15 ++++----- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/rules/__tests__/use-styled-react-import.test.js b/src/rules/__tests__/use-styled-react-import.test.js index bc2697c0..2e5d8064 100644 --- a/src/rules/__tests__/use-styled-react-import.test.js +++ b/src/rules/__tests__/use-styled-react-import.test.js @@ -70,6 +70,39 @@ ruleTester.run('use-styled-react-import', rule, { ], }, + // Invalid: FormControl used both with and without sx prop - should use alias + { + code: `import { FormControl } from '@primer/react' + const Component = () => ( +
+ + + Label + +
+ )`, + output: `import { FormControl } from '@primer/react' +import { FormControl as StyledFormControl } from '@primer/styled-react' + const Component = () => ( +
+ + + Label + +
+ )`, + errors: [ + { + messageId: 'useStyledReactImportWithAlias', + data: {componentName: 'FormControl', aliasName: 'StyledFormControl'}, + }, + { + messageId: 'useAliasedComponent', + data: {componentName: 'FormControl', aliasName: 'StyledFormControl'}, + }, + ], + }, + // Invalid: Button with sx prop imported from @primer/react { code: `import { Button } from '@primer/react' diff --git a/src/rules/use-styled-react-import.js b/src/rules/use-styled-react-import.js index 5c54429c..2a2f08ff 100644 --- a/src/rules/use-styled-react-import.js +++ b/src/rules/use-styled-react-import.js @@ -271,17 +271,14 @@ module.exports = { messageId: 'useAliasedComponent', data: {componentName, aliasName}, fix(fixer) { - const fixes = [] + const sourceCode = context.getSourceCode() + const jsxText = sourceCode.getText(jsxNode) - // Replace the component name in the JSX opening tag - fixes.push(fixer.replaceText(openingElement.name, aliasName)) + // Replace all instances of the component name (both main component and compound components) + const componentPattern = new RegExp(`\\b${componentName}(?=\\.|\\s|>)`, 'g') + const aliasedText = jsxText.replace(componentPattern, aliasName) - // Replace the component name in the JSX closing tag if it exists - if (jsxNode.closingElement) { - fixes.push(fixer.replaceText(jsxNode.closingElement.name, aliasName)) - } - - return fixes + return fixer.replaceText(jsxNode, aliasedText) }, }) } From 36db6cb3a0e702dd8a614785e78732ad1d37cdb3 Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Thu, 11 Sep 2025 13:55:30 -0700 Subject: [PATCH 3/3] Fix typo in changeset for eslint-plugin-primer-react --- .changeset/good-cobras-pay.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/good-cobras-pay.md diff --git a/.changeset/good-cobras-pay.md b/.changeset/good-cobras-pay.md new file mode 100644 index 00000000..56f6a6bb --- /dev/null +++ b/.changeset/good-cobras-pay.md @@ -0,0 +1,5 @@ +--- +"eslint-plugin-primer-react": patch +--- + +Fixes for `use-styled-react-import` rule for compound components.