Skip to content

Commit 2f25480

Browse files
authored
Make use-styled-react-import rule configurable (#407)
* Add configuration options to the use-styled-react-import rule * Create large-cherries-cheat.md
1 parent ab614ec commit 2f25480

File tree

4 files changed

+150
-9
lines changed

4 files changed

+150
-9
lines changed

.changeset/large-cherries-cheat.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"eslint-plugin-primer-react": minor
3+
---
4+
5+
Make `use-styled-react-import` rule configurable

docs/rules/use-styled-react-import.md

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,55 @@ const Component2 = () => <StyledButton sx={{color: 'red'}}>Styled me</StyledButt
121121

122122
## Options
123123

124-
This rule has no options.
124+
This rule accepts an optional configuration object with the following properties:
125+
126+
- `styledComponents` (array of strings): Components that should be imported from `@primer/styled-react` when used with `sx` prop. Defaults to the list shown above.
127+
- `styledTypes` (array of strings): Types that should always be imported from `@primer/styled-react`. Defaults to `['BoxProps', 'SxProp', 'BetterSystemStyleObject']`.
128+
- `styledUtilities` (array of strings): Utilities that should always be imported from `@primer/styled-react`. Defaults to `['sx']`.
129+
130+
### Example Configuration
131+
132+
```json
133+
{
134+
"rules": {
135+
"@primer/primer-react/use-styled-react-import": [
136+
"error",
137+
{
138+
"styledComponents": ["Button", "Box", "CustomComponent"],
139+
"styledTypes": ["BoxProps", "CustomProps"],
140+
"styledUtilities": ["sx", "customSx"]
141+
}
142+
]
143+
}
144+
}
145+
```
146+
147+
### Configuration Examples
148+
149+
#### ❌ Incorrect with custom configuration
150+
151+
```jsx
152+
// With styledComponents: ["CustomButton"]
153+
import {CustomButton} from '@primer/react'
154+
155+
const Component = () => <CustomButton sx={{color: 'red'}}>Click me</CustomButton>
156+
```
157+
158+
#### ✅ Correct with custom configuration
159+
160+
```jsx
161+
// With styledComponents: ["CustomButton"]
162+
import {CustomButton} from '@primer/styled-react'
163+
164+
const Component = () => <CustomButton sx={{color: 'red'}}>Click me</CustomButton>
165+
```
166+
167+
```jsx
168+
// Box is not in custom styledComponents list, so it can be used with sx from @primer/react
169+
import {Box} from '@primer/react'
170+
171+
const Component = () => <Box sx={{color: 'red'}}>Content</Box>
172+
```
125173

126174
## When Not To Use It
127175

src/rules/__tests__/use-styled-react-import.test.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,3 +249,64 @@ import { Button as StyledButton, Link } from '@primer/styled-react'
249249
},
250250
],
251251
})
252+
253+
// Test configuration options
254+
ruleTester.run('use-styled-react-import with custom configuration', rule, {
255+
valid: [
256+
// Valid: Custom component not in default list
257+
{
258+
code: `import { CustomButton } from '@primer/react'
259+
const Component = () => <CustomButton sx={{ color: 'red' }}>Click me</CustomButton>`,
260+
options: [{}], // Using default configuration
261+
},
262+
263+
// Valid: Custom component in custom list used without sx prop
264+
{
265+
code: `import { CustomButton } from '@primer/react'
266+
const Component = () => <CustomButton>Click me</CustomButton>`,
267+
options: [{styledComponents: ['CustomButton']}],
268+
},
269+
270+
// Valid: Custom component with sx prop imported from styled-react
271+
{
272+
code: `import { CustomButton } from '@primer/styled-react'
273+
const Component = () => <CustomButton sx={{ color: 'red' }}>Click me</CustomButton>`,
274+
options: [{styledComponents: ['CustomButton']}],
275+
},
276+
277+
// Valid: Box not in custom list, so sx usage is allowed from @primer/react
278+
{
279+
code: `import { Box } from '@primer/react'
280+
const Component = () => <Box sx={{ color: 'red' }}>Content</Box>`,
281+
options: [{styledComponents: ['CustomButton']}], // Box not included
282+
},
283+
],
284+
invalid: [
285+
// Invalid: Custom component with sx prop should be from styled-react
286+
{
287+
code: `import { CustomButton } from '@primer/react'
288+
const Component = () => <CustomButton sx={{ color: 'red' }}>Click me</CustomButton>`,
289+
output: `import { CustomButton } from '@primer/styled-react'
290+
const Component = () => <CustomButton sx={{ color: 'red' }}>Click me</CustomButton>`,
291+
options: [{styledComponents: ['CustomButton']}],
292+
errors: [
293+
{
294+
messageId: 'useStyledReactImport',
295+
data: {componentName: 'CustomButton'},
296+
},
297+
],
298+
},
299+
// Invalid: Custom utility should be from styled-react
300+
{
301+
code: `import { customSx } from '@primer/react'`,
302+
output: `import { customSx } from '@primer/styled-react'`,
303+
options: [{styledUtilities: ['customSx']}],
304+
errors: [
305+
{
306+
messageId: 'moveToStyledReact',
307+
data: {importName: 'customSx'},
308+
},
309+
],
310+
},
311+
],
312+
})

src/rules/use-styled-react-import.js

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
const url = require('../url')
44
const {getJSXOpeningElementName} = require('../utils/get-jsx-opening-element-name')
55

6-
// Components that should be imported from @primer/styled-react when used with sx prop
7-
const styledComponents = new Set([
6+
// Default components that should be imported from @primer/styled-react when used with sx prop
7+
const defaultStyledComponents = [
88
'ActionList',
99
'ActionMenu',
1010
'Box',
@@ -23,13 +23,13 @@ const styledComponents = new Set([
2323
'Truncate',
2424
'Octicon',
2525
'Dialog',
26-
])
26+
]
2727

28-
// Types that should be imported from @primer/styled-react
29-
const styledTypes = new Set(['BoxProps', 'SxProp', 'BetterSystemStyleObject'])
28+
// Default types that should be imported from @primer/styled-react
29+
const defaultStyledTypes = ['BoxProps', 'SxProp', 'BetterSystemStyleObject']
3030

31-
// Utilities that should be imported from @primer/styled-react
32-
const styledUtilities = new Set(['sx'])
31+
// Default utilities that should be imported from @primer/styled-react
32+
const defaultStyledUtilities = ['sx']
3333

3434
/**
3535
* @type {import('eslint').Rule.RuleModule}
@@ -43,7 +43,29 @@ module.exports = {
4343
url: url(module),
4444
},
4545
fixable: 'code',
46-
schema: [],
46+
schema: [
47+
{
48+
type: 'object',
49+
properties: {
50+
styledComponents: {
51+
type: 'array',
52+
items: {type: 'string'},
53+
description: 'Components that should be imported from @primer/styled-react when used with sx prop',
54+
},
55+
styledTypes: {
56+
type: 'array',
57+
items: {type: 'string'},
58+
description: 'Types that should be imported from @primer/styled-react',
59+
},
60+
styledUtilities: {
61+
type: 'array',
62+
items: {type: 'string'},
63+
description: 'Utilities that should be imported from @primer/styled-react',
64+
},
65+
},
66+
additionalProperties: false,
67+
},
68+
],
4769
messages: {
4870
useStyledReactImport: 'Import {{ componentName }} from "@primer/styled-react" when using with sx prop',
4971
useStyledReactImportWithAlias:
@@ -54,6 +76,11 @@ module.exports = {
5476
},
5577
},
5678
create(context) {
79+
// Get configuration options or use defaults
80+
const options = context.options[0] || {}
81+
const styledComponents = new Set(options.styledComponents || defaultStyledComponents)
82+
const styledTypes = new Set(options.styledTypes || defaultStyledTypes)
83+
const styledUtilities = new Set(options.styledUtilities || defaultStyledUtilities)
5784
const componentsWithSx = new Set()
5885
const componentsWithoutSx = new Set() // Track components used without sx
5986
const allUsedComponents = new Set() // Track all used components

0 commit comments

Comments
 (0)