eslint-plugin-primer-react 8.2.0-rc.b646af2 → 8.2.1-rc.aedddaa

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,11 +1,21 @@
1
1
  # eslint-plugin-primer-react
2
2
 
3
+ ## 8.2.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#410](https://github.com/primer/eslint-plugin-primer-react/pull/410) [`f3e47b1`](https://github.com/primer/eslint-plugin-primer-react/commit/f3e47b1a75ad27aceaed89d50175cc59754c8b9d) Thanks [@jonrohan](https://github.com/jonrohan)! - Fix for deprecated and experimental import paths
8
+
3
9
  ## 8.2.0
4
10
 
5
11
  ### Minor Changes
6
12
 
7
13
  - [#407](https://github.com/primer/eslint-plugin-primer-react/pull/407) [`2f25480`](https://github.com/primer/eslint-plugin-primer-react/commit/2f25480c3341c1d1afb6fc040c5c5deee416d71c) Thanks [@jonrohan](https://github.com/jonrohan)! - Make `use-styled-react-import` rule configurable
8
14
 
15
+ ### Patch Changes
16
+
17
+ - [#406](https://github.com/primer/eslint-plugin-primer-react/pull/406) [`d72e8c4`](https://github.com/primer/eslint-plugin-primer-react/commit/d72e8c4c172d1c37da201a20cde0b7b2bd9ab283) Thanks [@jonrohan](https://github.com/jonrohan)! - Fixes for `use-styled-react-import` rule for compound components.
18
+
9
19
  ## 8.1.0
10
20
 
11
21
  ### Minor Changes
@@ -12,7 +12,7 @@ Enforce importing components that use `sx` prop from `@primer/styled-react` inst
12
12
 
13
13
  This rule detects when certain Primer React components are used with the `sx` prop and ensures they are imported from the temporary `@primer/styled-react` package instead of `@primer/react`. When the same components are used without the `sx` prop, it ensures they are imported from `@primer/react` instead of `@primer/styled-react`.
14
14
 
15
- When a component is used both with and without the `sx` prop in the same file, the rule will import the styled version with an alias (e.g., `StyledButton`) and update the JSX usage accordingly to avoid naming conflicts.
15
+ When a component is used with the `sx` prop anywhere in the file, the entire component import is moved to `@primer/styled-react`, simplifying the import structure.
16
16
 
17
17
  It also moves certain types and utilities to the styled-react package.
18
18
 
@@ -111,12 +111,11 @@ const Component = () => <Button>Click me</Button>
111
111
  ```
112
112
 
113
113
  ```jsx
114
- // When a component is used both ways, use an alias for the styled version
115
- import {Button} from '@primer/react'
116
- import {Button as StyledButton} from '@primer/styled-react'
114
+ // When a component is used with sx prop anywhere, import from styled-react
115
+ import {Button} from '@primer/styled-react'
117
116
 
118
117
  const Component1 = () => <Button>Click me</Button>
119
- const Component2 = () => <StyledButton sx={{color: 'red'}}>Styled me</StyledButton>
118
+ const Component2 = () => <Button sx={{color: 'red'}}>Styled me</Button>
120
119
  ```
121
120
 
122
121
  ## Options
package/package-lock.json CHANGED
@@ -10,7 +10,7 @@
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@styled-system/props": "^5.1.5",
13
- "@typescript-eslint/utils": "8.43.0",
13
+ "@typescript-eslint/utils": "^8.39.0",
14
14
  "eslint-plugin-github": "^6.0.0",
15
15
  "eslint-plugin-jsx-a11y": "^6.7.1",
16
16
  "eslint-traverse": "^1.0.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-primer-react",
3
- "version": "8.2.0-rc.b646af2",
3
+ "version": "8.2.1-rc.aedddaa",
4
4
  "description": "ESLint rules for Primer React",
5
5
  "main": "src/index.js",
6
6
  "engines": {
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@styled-system/props": "^5.1.5",
35
- "@typescript-eslint/utils": "8.43.0",
35
+ "@typescript-eslint/utils": "^8.39.0",
36
36
  "eslint-plugin-github": "^6.0.0",
37
37
  "eslint-plugin-jsx-a11y": "^6.7.1",
38
38
  "eslint-traverse": "^1.0.0",
@@ -56,6 +56,68 @@ ruleTester.run('use-styled-react-import', rule, {
56
56
  ],
57
57
  },
58
58
 
59
+ // Invalid: Imports from /experimental and /deprecated paths
60
+ {
61
+ code: `import { Button } from '@primer/react/experimental'
62
+ import { Box } from '@primer/react/deprecated'
63
+ const Component = () => <Box sx={{ color: 'red' }}><Button sx={{ margin: 2 }}>Click me</Button></Box>`,
64
+ output: `import { Button } from '@primer/styled-react/experimental'
65
+ import { Box } from '@primer/styled-react/deprecated'
66
+ const Component = () => <Box sx={{ color: 'red' }}><Button sx={{ margin: 2 }}>Click me</Button></Box>`,
67
+ errors: [
68
+ {
69
+ messageId: 'useStyledReactImport',
70
+ data: {componentName: 'Button'},
71
+ },
72
+ {
73
+ messageId: 'useStyledReactImport',
74
+ data: {componentName: 'Box'},
75
+ },
76
+ ],
77
+ },
78
+
79
+ // Invalid: ActionList.Item with sx prop and ActionList imported from @primer/react
80
+ {
81
+ code: `import { ActionList } from '@primer/react'
82
+ const Component = () => <ActionList.Item sx={{ color: 'red' }}>Content</ActionList.Item>`,
83
+ output: `import { ActionList } from '@primer/styled-react'
84
+ const Component = () => <ActionList.Item sx={{ color: 'red' }}>Content</ActionList.Item>`,
85
+ errors: [
86
+ {
87
+ messageId: 'useStyledReactImport',
88
+ data: {componentName: 'ActionList'},
89
+ },
90
+ ],
91
+ },
92
+
93
+ // Invalid: FormControl used both with and without sx prop - should move to styled-react
94
+ {
95
+ code: `import { FormControl } from '@primer/react'
96
+ const Component = () => (
97
+ <div>
98
+ <FormControl></FormControl>
99
+ <FormControl sx={{ color: 'red' }}>
100
+ <FormControl.Label visuallyHidden>Label</FormControl.Label>
101
+ </FormControl>
102
+ </div>
103
+ )`,
104
+ output: `import { FormControl } from '@primer/styled-react'
105
+ const Component = () => (
106
+ <div>
107
+ <FormControl></FormControl>
108
+ <FormControl sx={{ color: 'red' }}>
109
+ <FormControl.Label visuallyHidden>Label</FormControl.Label>
110
+ </FormControl>
111
+ </div>
112
+ )`,
113
+ errors: [
114
+ {
115
+ messageId: 'useStyledReactImport',
116
+ data: {componentName: 'FormControl'},
117
+ },
118
+ ],
119
+ },
120
+
59
121
  // Invalid: Button with sx prop imported from @primer/react
60
122
  {
61
123
  code: `import { Button } from '@primer/react'
@@ -70,6 +132,41 @@ ruleTester.run('use-styled-react-import', rule, {
70
132
  ],
71
133
  },
72
134
 
135
+ // Invalid: ActionList used without sx, ActionList.Item used with sx - should move ActionList to styled-react
136
+ {
137
+ code: `import { ActionList, ActionMenu } from '@primer/react'
138
+ const Component = () => (
139
+ <ActionMenu>
140
+ <ActionMenu.Overlay>
141
+ <ActionList>
142
+ <ActionList.Item sx={{ paddingLeft: 'calc(1 * var(--base-size-12))' }}>
143
+ Item
144
+ </ActionList.Item>
145
+ </ActionList>
146
+ </ActionMenu.Overlay>
147
+ </ActionMenu>
148
+ )`,
149
+ output: `import { ActionMenu } from '@primer/react'
150
+ import { ActionList } from '@primer/styled-react'
151
+ const Component = () => (
152
+ <ActionMenu>
153
+ <ActionMenu.Overlay>
154
+ <ActionList>
155
+ <ActionList.Item sx={{ paddingLeft: 'calc(1 * var(--base-size-12))' }}>
156
+ Item
157
+ </ActionList.Item>
158
+ </ActionList>
159
+ </ActionMenu.Overlay>
160
+ </ActionMenu>
161
+ )`,
162
+ errors: [
163
+ {
164
+ messageId: 'useStyledReactImport',
165
+ data: {componentName: 'ActionList'},
166
+ },
167
+ ],
168
+ },
169
+
73
170
  // Invalid: Multiple components, one with sx prop
74
171
  {
75
172
  code: `import { Button, Box, Avatar } from '@primer/react'
@@ -138,7 +235,7 @@ import { Button } from '@primer/styled-react'
138
235
  ],
139
236
  },
140
237
 
141
- // Invalid: <Link /> and <StyledButton /> imported from styled-react but used without sx prop
238
+ // Invalid: <Link /> and <Button /> imported from styled-react but used without sx prop
142
239
  {
143
240
  code: `import { Button } from '@primer/react'
144
241
  import { Button as StyledButton, Link } from '@primer/styled-react'
@@ -155,7 +252,7 @@ import { Button as StyledButton, Link } from '@primer/styled-react'
155
252
  <div>
156
253
  <Link />
157
254
  <Button>Regular button</Button>
158
- <Button>Styled button</Button>
255
+ <StyledButton>Styled button</StyledButton>
159
256
  </div>
160
257
  )`,
161
258
  errors: [
@@ -167,10 +264,6 @@ import { Button as StyledButton, Link } from '@primer/styled-react'
167
264
  messageId: 'usePrimerReactImport',
168
265
  data: {componentName: 'Link'},
169
266
  },
170
- {
171
- messageId: 'usePrimerReactImport',
172
- data: {componentName: 'Button'},
173
- },
174
267
  ],
175
268
  },
176
269
 
@@ -213,7 +306,7 @@ import { Button } from '@primer/react'
213
306
  ],
214
307
  },
215
308
 
216
- // Invalid: Button used both with and without sx prop - should use alias
309
+ // Invalid: Button and Link used with sx prop - should move both to styled-react
217
310
  {
218
311
  code: `import { Button, Link } from '@primer/react'
219
312
  const Component = () => (
@@ -223,28 +316,23 @@ import { Button } from '@primer/react'
223
316
  <Button sx={{ color: 'red' }}>Styled button</Button>
224
317
  </div>
225
318
  )`,
226
- output: `import { Button } from '@primer/react'
227
- import { Button as StyledButton, Link } from '@primer/styled-react'
319
+ output: `import { Link, Button } from '@primer/styled-react'
228
320
  const Component = () => (
229
321
  <div>
230
322
  <Link sx={{ color: 'red' }} />
231
323
  <Button>Regular button</Button>
232
- <StyledButton sx={{ color: 'red' }}>Styled button</StyledButton>
324
+ <Button sx={{ color: 'red' }}>Styled button</Button>
233
325
  </div>
234
326
  )`,
235
327
  errors: [
236
328
  {
237
- messageId: 'useStyledReactImportWithAlias',
238
- data: {componentName: 'Button', aliasName: 'StyledButton'},
329
+ messageId: 'useStyledReactImport',
330
+ data: {componentName: 'Button'},
239
331
  },
240
332
  {
241
333
  messageId: 'useStyledReactImport',
242
334
  data: {componentName: 'Link'},
243
335
  },
244
- {
245
- messageId: 'useAliasedComponent',
246
- data: {componentName: 'Button', aliasName: 'StyledButton'},
247
- },
248
336
  ],
249
337
  },
250
338
  ],
@@ -68,9 +68,6 @@ module.exports = {
68
68
  ],
69
69
  messages: {
70
70
  useStyledReactImport: 'Import {{ componentName }} from "@primer/styled-react" when using with sx prop',
71
- useStyledReactImportWithAlias:
72
- 'Import {{ componentName }} as {{ aliasName }} from "@primer/styled-react" when using with sx prop (conflicts with non-sx usage)',
73
- useAliasedComponent: 'Use {{ aliasName }} instead of {{ componentName }} when using sx prop',
74
71
  moveToStyledReact: 'Move {{ importName }} import to "@primer/styled-react"',
75
72
  usePrimerReactImport: 'Import {{ componentName }} from "@primer/react" when not using sx prop',
76
73
  },
@@ -86,16 +83,13 @@ module.exports = {
86
83
  const allUsedComponents = new Set() // Track all used components
87
84
  const primerReactImports = new Map() // Map of component name to import node
88
85
  const styledReactImports = new Map() // Map of components imported from styled-react to import node
89
- const aliasMapping = new Map() // Map local name to original component name for aliased imports
90
- const jsxElementsWithSx = [] // Track JSX elements that use sx prop
91
- const jsxElementsWithoutSx = [] // Track JSX elements that don't use sx prop
92
86
 
93
87
  return {
94
88
  ImportDeclaration(node) {
95
89
  const importSource = node.source.value
96
90
 
97
- if (importSource === '@primer/react') {
98
- // Track imports from @primer/react
91
+ if (importSource === '@primer/react' || importSource.startsWith('@primer/react/')) {
92
+ // Track imports from @primer/react and its subpaths
99
93
  for (const specifier of node.specifiers) {
100
94
  if (specifier.type === 'ImportSpecifier') {
101
95
  const importedName = specifier.imported.name
@@ -104,22 +98,16 @@ module.exports = {
104
98
  styledTypes.has(importedName) ||
105
99
  styledUtilities.has(importedName)
106
100
  ) {
107
- primerReactImports.set(importedName, {node, specifier})
101
+ primerReactImports.set(importedName, {node, specifier, importSource})
108
102
  }
109
103
  }
110
104
  }
111
- } else if (importSource === '@primer/styled-react') {
112
- // Track what's imported from styled-react
105
+ } else if (importSource === '@primer/styled-react' || importSource.startsWith('@primer/styled-react/')) {
106
+ // Track what's imported from styled-react and its subpaths
113
107
  for (const specifier of node.specifiers) {
114
108
  if (specifier.type === 'ImportSpecifier') {
115
109
  const importedName = specifier.imported.name
116
- const localName = specifier.local.name
117
- styledReactImports.set(importedName, {node, specifier})
118
-
119
- // Track alias mapping for styled-react imports
120
- if (localName !== importedName) {
121
- aliasMapping.set(localName, importedName)
122
- }
110
+ styledReactImports.set(importedName, {node, specifier, importSource})
123
111
  }
124
112
  }
125
113
  }
@@ -129,12 +117,12 @@ module.exports = {
129
117
  const openingElement = node.openingElement
130
118
  const componentName = getJSXOpeningElementName(openingElement)
131
119
 
132
- // Check if this is an aliased component from styled-react
133
- const originalComponentName = aliasMapping.get(componentName) || componentName
120
+ // For compound components like "ActionList.Item", we need to check the parent component
121
+ const parentComponentName = componentName.includes('.') ? componentName.split('.')[0] : componentName
134
122
 
135
123
  // Track all used components that are in our styled components list
136
- if (styledComponents.has(originalComponentName)) {
137
- allUsedComponents.add(originalComponentName)
124
+ if (styledComponents.has(parentComponentName)) {
125
+ allUsedComponents.add(parentComponentName)
138
126
 
139
127
  // Check if this component has an sx prop
140
128
  const hasSxProp = openingElement.attributes.some(
@@ -142,20 +130,9 @@ module.exports = {
142
130
  )
143
131
 
144
132
  if (hasSxProp) {
145
- componentsWithSx.add(originalComponentName)
146
- jsxElementsWithSx.push({node, componentName: originalComponentName, openingElement})
133
+ componentsWithSx.add(parentComponentName)
147
134
  } else {
148
- componentsWithoutSx.add(originalComponentName)
149
-
150
- // If this is an aliased component without sx, we need to track it for renaming
151
- if (aliasMapping.has(componentName)) {
152
- jsxElementsWithoutSx.push({
153
- node,
154
- localName: componentName,
155
- originalName: originalComponentName,
156
- openingElement,
157
- })
158
- }
135
+ componentsWithoutSx.add(parentComponentName)
159
136
  }
160
137
  }
161
138
  },
@@ -168,23 +145,16 @@ module.exports = {
168
145
  for (const componentName of componentsWithSx) {
169
146
  const importInfo = primerReactImports.get(componentName)
170
147
  if (importInfo && !styledReactImports.has(componentName)) {
171
- const hasConflict = componentsWithoutSx.has(componentName)
172
148
  const {node: importNode} = importInfo
173
149
 
174
150
  if (!importNodeChanges.has(importNode)) {
175
151
  importNodeChanges.set(importNode, {
176
152
  toMove: [],
177
- toAlias: [],
178
153
  originalSpecifiers: [...importNode.specifiers],
179
154
  })
180
155
  }
181
156
 
182
- const changes = importNodeChanges.get(importNode)
183
- if (hasConflict) {
184
- changes.toAlias.push(componentName)
185
- } else {
186
- changes.toMove.push(componentName)
187
- }
157
+ importNodeChanges.get(importNode).toMove.push(componentName)
188
158
  }
189
159
  }
190
160
 
@@ -192,15 +162,12 @@ module.exports = {
192
162
  for (const componentName of componentsWithSx) {
193
163
  const importInfo = primerReactImports.get(componentName)
194
164
  if (importInfo && !styledReactImports.has(componentName)) {
195
- // Check if this component is also used without sx prop (conflict scenario)
196
- const hasConflict = componentsWithoutSx.has(componentName)
197
-
198
165
  context.report({
199
166
  node: importInfo.specifier,
200
- messageId: hasConflict ? 'useStyledReactImportWithAlias' : 'useStyledReactImport',
201
- data: hasConflict ? {componentName, aliasName: `Styled${componentName}`} : {componentName},
167
+ messageId: 'useStyledReactImport',
168
+ data: {componentName},
202
169
  fix(fixer) {
203
- const {node: importNode, specifier} = importInfo
170
+ const {node: importNode, importSource} = importInfo
204
171
  const changes = importNodeChanges.get(importNode)
205
172
 
206
173
  if (!changes) {
@@ -208,10 +175,7 @@ module.exports = {
208
175
  }
209
176
 
210
177
  // Only apply the fix once per import node (for the first component processed)
211
- const isFirstComponent =
212
- changes.originalSpecifiers[0] === specifier ||
213
- (changes.toMove.length > 0 && changes.toMove[0] === componentName) ||
214
- (changes.toAlias.length > 0 && changes.toAlias[0] === componentName)
178
+ const isFirstComponent = changes.toMove[0] === componentName
215
179
 
216
180
  if (!isFirstComponent) {
217
181
  return null
@@ -223,84 +187,28 @@ module.exports = {
223
187
  // Find specifiers that remain in original import
224
188
  const remainingSpecifiers = changes.originalSpecifiers.filter(spec => {
225
189
  const name = spec.imported.name
226
- // Keep components that are not being moved (only aliased components stay for non-sx usage)
227
190
  return !componentsToMove.has(name)
228
191
  })
229
192
 
230
- // If no components remain, replace with new imports directly
231
- if (remainingSpecifiers.length === 0) {
232
- // Build the new imports to replace the original
233
- const newImports = []
234
-
235
- // Add imports for moved components
236
- for (const componentName of changes.toMove) {
237
- newImports.push(`import { ${componentName} } from '@primer/styled-react'`)
238
- }
193
+ // Convert @primer/react path to @primer/styled-react path
194
+ const styledReactPath = importSource.replace('@primer/react', '@primer/styled-react')
239
195
 
240
- // Add aliased imports for conflicted components
241
- for (const componentName of changes.toAlias) {
242
- const aliasName = `Styled${componentName}`
243
- newImports.push(`import { ${componentName} as ${aliasName} } from '@primer/styled-react'`)
244
- }
245
-
246
- fixes.push(fixer.replaceText(importNode, newImports.join('\n')))
196
+ // If no components remain, replace with new import directly
197
+ if (remainingSpecifiers.length === 0) {
198
+ const movedComponents = changes.toMove.join(', ')
199
+ fixes.push(fixer.replaceText(importNode, `import { ${movedComponents} } from '${styledReactPath}'`))
247
200
  } else {
248
201
  // Otherwise, update the import to only include remaining components
249
202
  const remainingNames = remainingSpecifiers.map(spec => spec.imported.name)
250
203
  fixes.push(
251
- fixer.replaceText(importNode, `import { ${remainingNames.join(', ')} } from '@primer/react'`),
204
+ fixer.replaceText(importNode, `import { ${remainingNames.join(', ')} } from '${importSource}'`),
252
205
  )
253
206
 
254
- // Combine all styled-react imports into a single import statement
255
- const styledReactImports = []
256
-
257
- // Add aliased components first
258
- for (const componentName of changes.toAlias) {
259
- const aliasName = `Styled${componentName}`
260
- styledReactImports.push(`${componentName} as ${aliasName}`)
261
- }
262
-
263
- // Add moved components second
264
- for (const componentName of changes.toMove) {
265
- styledReactImports.push(componentName)
266
- }
267
-
268
- if (styledReactImports.length > 0) {
269
- fixes.push(
270
- fixer.insertTextAfter(
271
- importNode,
272
- `\nimport { ${styledReactImports.join(', ')} } from '@primer/styled-react'`,
273
- ),
274
- )
275
- }
276
- }
277
-
278
- return fixes
279
- },
280
- })
281
- }
282
- }
283
-
284
- // Report on JSX elements that should use aliased components
285
- for (const {node: jsxNode, componentName, openingElement} of jsxElementsWithSx) {
286
- const hasConflict = componentsWithoutSx.has(componentName)
287
- const isImportedFromPrimerReact = primerReactImports.has(componentName)
288
-
289
- if (hasConflict && isImportedFromPrimerReact && !styledReactImports.has(componentName)) {
290
- const aliasName = `Styled${componentName}`
291
- context.report({
292
- node: openingElement,
293
- messageId: 'useAliasedComponent',
294
- data: {componentName, aliasName},
295
- fix(fixer) {
296
- const fixes = []
297
-
298
- // Replace the component name in the JSX opening tag
299
- fixes.push(fixer.replaceText(openingElement.name, aliasName))
300
-
301
- // Replace the component name in the JSX closing tag if it exists
302
- if (jsxNode.closingElement) {
303
- fixes.push(fixer.replaceText(jsxNode.closingElement.name, aliasName))
207
+ // Add new styled-react import
208
+ const movedComponents = changes.toMove.join(', ')
209
+ fixes.push(
210
+ fixer.insertTextAfter(importNode, `\nimport { ${movedComponents} } from '${styledReactPath}'`),
211
+ )
304
212
  }
305
213
 
306
214
  return fixes
@@ -345,7 +253,7 @@ module.exports = {
345
253
  messageId: 'usePrimerReactImport',
346
254
  data: {componentName},
347
255
  fix(fixer) {
348
- const {node: importNode} = importInfo
256
+ const {node: importNode, importSource} = importInfo
349
257
  const changes = styledReactImportNodeChanges.get(importNode)
350
258
 
351
259
  if (!changes) {
@@ -368,6 +276,9 @@ module.exports = {
368
276
  return !componentsToMove.has(name)
369
277
  })
370
278
 
279
+ // Convert @primer/styled-react path to @primer/react path
280
+ const primerReactPath = importSource.replace('@primer/styled-react', '@primer/react')
281
+
371
282
  // Check if there's an existing primer-react import to merge with
372
283
  const existingPrimerReactImport = Array.from(primerReactImportNodes)[0]
373
284
 
@@ -381,7 +292,7 @@ module.exports = {
381
292
  fixes.push(
382
293
  fixer.replaceText(
383
294
  existingPrimerReactImport,
384
- `import { ${newSpecifiers.join(', ')} } from '@primer/react'`,
295
+ `import { ${newSpecifiers.join(', ')} } from '${primerReactPath}'`,
385
296
  ),
386
297
  )
387
298
  fixes.push(fixer.remove(importNode))
@@ -395,57 +306,29 @@ module.exports = {
395
306
  fixes.push(
396
307
  fixer.replaceText(
397
308
  existingPrimerReactImport,
398
- `import { ${newSpecifiers.join(', ')} } from '@primer/react'`,
309
+ `import { ${newSpecifiers.join(', ')} } from '${primerReactPath}'`,
399
310
  ),
400
311
  )
401
312
 
402
313
  const remainingNames = remainingSpecifiers.map(spec => spec.imported.name)
403
314
  fixes.push(
404
- fixer.replaceText(
405
- importNode,
406
- `import { ${remainingNames.join(', ')} } from '@primer/styled-react'`,
407
- ),
315
+ fixer.replaceText(importNode, `import { ${remainingNames.join(', ')} } from '${importSource}'`),
408
316
  )
409
317
  } else if (remainingSpecifiers.length === 0) {
410
318
  // Case: No existing primer-react import, no remaining styled-react imports
411
319
  const movedComponents = changes.toMove.join(', ')
412
- fixes.push(fixer.replaceText(importNode, `import { ${movedComponents} } from '@primer/react'`))
320
+ fixes.push(fixer.replaceText(importNode, `import { ${movedComponents} } from '${primerReactPath}'`))
413
321
  } else {
414
322
  // Case: No existing primer-react import, some styled-react imports remain
415
323
  const remainingNames = remainingSpecifiers.map(spec => spec.imported.name)
416
324
  fixes.push(
417
- fixer.replaceText(
418
- importNode,
419
- `import { ${remainingNames.join(', ')} } from '@primer/styled-react'`,
420
- ),
325
+ fixer.replaceText(importNode, `import { ${remainingNames.join(', ')} } from '${importSource}'`),
421
326
  )
422
327
 
423
328
  const movedComponents = changes.toMove.join(', ')
424
- fixes.push(fixer.insertTextAfter(importNode, `\nimport { ${movedComponents} } from '@primer/react'`))
425
- }
426
-
427
- return fixes
428
- },
429
- })
430
- }
431
- }
432
-
433
- // Report and fix JSX elements that use aliased components without sx prop
434
- for (const {node: jsxNode, originalName, openingElement} of jsxElementsWithoutSx) {
435
- if (!componentsWithSx.has(originalName) && styledReactImports.has(originalName)) {
436
- context.report({
437
- node: openingElement,
438
- messageId: 'usePrimerReactImport',
439
- data: {componentName: originalName},
440
- fix(fixer) {
441
- const fixes = []
442
-
443
- // Replace the aliased component name with the original component name in JSX opening tag
444
- fixes.push(fixer.replaceText(openingElement.name, originalName))
445
-
446
- // Replace the aliased component name in JSX closing tag if it exists
447
- if (jsxNode.closingElement) {
448
- fixes.push(fixer.replaceText(jsxNode.closingElement.name, originalName))
329
+ fixes.push(
330
+ fixer.insertTextAfter(importNode, `\nimport { ${movedComponents} } from '${primerReactPath}'`),
331
+ )
449
332
  }
450
333
 
451
334
  return fixes
@@ -462,13 +345,16 @@ module.exports = {
462
345
  messageId: 'moveToStyledReact',
463
346
  data: {importName},
464
347
  fix(fixer) {
465
- const {node: importNode, specifier} = importInfo
348
+ const {node: importNode, specifier, importSource} = importInfo
466
349
  const otherSpecifiers = importNode.specifiers.filter(s => s !== specifier)
467
350
 
351
+ // Convert @primer/react path to @primer/styled-react path
352
+ const styledReactPath = importSource.replace('@primer/react', '@primer/styled-react')
353
+
468
354
  // If this is the only import, replace the whole import
469
355
  if (otherSpecifiers.length === 0) {
470
356
  const prefix = styledTypes.has(importName) ? 'type ' : ''
471
- return fixer.replaceText(importNode, `import { ${prefix}${importName} } from '@primer/styled-react'`)
357
+ return fixer.replaceText(importNode, `import { ${prefix}${importName} } from '${styledReactPath}'`)
472
358
  }
473
359
 
474
360
  // Otherwise, remove from current import and add new import
@@ -496,7 +382,7 @@ module.exports = {
496
382
  // Add new import
497
383
  const prefix = styledTypes.has(importName) ? 'type ' : ''
498
384
  fixes.push(
499
- fixer.insertTextAfter(importNode, `\nimport { ${prefix}${importName} } from '@primer/styled-react'`),
385
+ fixer.insertTextAfter(importNode, `\nimport { ${prefix}${importName} } from '${styledReactPath}'`),
500
386
  )
501
387
 
502
388
  return fixes