@openrewrite/recipes-react 0.2.9

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.
Files changed (251) hide show
  1. package/dist/index.d.ts +4 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +130 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/migration/change-component-prop-value.d.ts +20 -0
  6. package/dist/migration/change-component-prop-value.d.ts.map +1 -0
  7. package/dist/migration/change-component-prop-value.js +217 -0
  8. package/dist/migration/change-component-prop-value.js.map +1 -0
  9. package/dist/react-native/view-prop-types.d.ts +8 -0
  10. package/dist/react-native/view-prop-types.d.ts.map +1 -0
  11. package/dist/react-native/view-prop-types.js +65 -0
  12. package/dist/react-native/view-prop-types.js.map +1 -0
  13. package/dist/react16/error-boundaries.d.ts +8 -0
  14. package/dist/react16/error-boundaries.d.ts.map +1 -0
  15. package/dist/react16/error-boundaries.js +42 -0
  16. package/dist/react16/error-boundaries.js.map +1 -0
  17. package/dist/react16/find-dom-node.d.ts +8 -0
  18. package/dist/react16/find-dom-node.d.ts.map +1 -0
  19. package/dist/react16/find-dom-node.js +48 -0
  20. package/dist/react16/find-dom-node.js.map +1 -0
  21. package/dist/react16/react-dom-factories.d.ts +8 -0
  22. package/dist/react16/react-dom-factories.d.ts.map +1 -0
  23. package/dist/react16/react-dom-factories.js +72 -0
  24. package/dist/react16/react-dom-factories.js.map +1 -0
  25. package/dist/react16/react-prop-types.d.ts +8 -0
  26. package/dist/react16/react-prop-types.d.ts.map +1 -0
  27. package/dist/react16/react-prop-types.js +69 -0
  28. package/dist/react16/react-prop-types.js.map +1 -0
  29. package/dist/react16/react-to-react-dom.d.ts +8 -0
  30. package/dist/react16/react-to-react-dom.d.ts.map +1 -0
  31. package/dist/react16/react-to-react-dom.js +97 -0
  32. package/dist/react16/react-to-react-dom.js.map +1 -0
  33. package/dist/react16/replace-create-factory.d.ts +8 -0
  34. package/dist/react16/replace-create-factory.d.ts.map +1 -0
  35. package/dist/react16/replace-create-factory.js +69 -0
  36. package/dist/react16/replace-create-factory.js.map +1 -0
  37. package/dist/react16/upgrade-to-react-16.d.ts +8 -0
  38. package/dist/react16/upgrade-to-react-16.d.ts.map +1 -0
  39. package/dist/react16/upgrade-to-react-16.js +41 -0
  40. package/dist/react16/upgrade-to-react-16.js.map +1 -0
  41. package/dist/react17/remove-event-persist.d.ts +8 -0
  42. package/dist/react17/remove-event-persist.d.ts.map +1 -0
  43. package/dist/react17/remove-event-persist.js +114 -0
  44. package/dist/react17/remove-event-persist.js.map +1 -0
  45. package/dist/react17/rename-unsafe-lifecycles.d.ts +8 -0
  46. package/dist/react17/rename-unsafe-lifecycles.d.ts.map +1 -0
  47. package/dist/react17/rename-unsafe-lifecycles.js +48 -0
  48. package/dist/react17/rename-unsafe-lifecycles.js.map +1 -0
  49. package/dist/react17/update-react-imports.d.ts +8 -0
  50. package/dist/react17/update-react-imports.d.ts.map +1 -0
  51. package/dist/react17/update-react-imports.js +40 -0
  52. package/dist/react17/update-react-imports.js.map +1 -0
  53. package/dist/react17/upgrade-to-react-17.d.ts +8 -0
  54. package/dist/react17/upgrade-to-react-17.d.ts.map +1 -0
  55. package/dist/react17/upgrade-to-react-17.js +37 -0
  56. package/dist/react17/upgrade-to-react-17.js.map +1 -0
  57. package/dist/react18/remove-unstable-batched-updates.d.ts +8 -0
  58. package/dist/react18/remove-unstable-batched-updates.d.ts.map +1 -0
  59. package/dist/react18/remove-unstable-batched-updates.js +170 -0
  60. package/dist/react18/remove-unstable-batched-updates.js.map +1 -0
  61. package/dist/react18/replace-reactdom-render.d.ts +8 -0
  62. package/dist/react18/replace-reactdom-render.d.ts.map +1 -0
  63. package/dist/react18/replace-reactdom-render.js +55 -0
  64. package/dist/react18/replace-reactdom-render.js.map +1 -0
  65. package/dist/react18/replace-render-callback.d.ts +8 -0
  66. package/dist/react18/replace-render-callback.d.ts.map +1 -0
  67. package/dist/react18/replace-render-callback.js +60 -0
  68. package/dist/react18/replace-render-callback.js.map +1 -0
  69. package/dist/react18/replace-unmount-component-at-node.d.ts +8 -0
  70. package/dist/react18/replace-unmount-component-at-node.d.ts.map +1 -0
  71. package/dist/react18/replace-unmount-component-at-node.js +54 -0
  72. package/dist/react18/replace-unmount-component-at-node.js.map +1 -0
  73. package/dist/react18/upgrade-to-react-18.d.ts +8 -0
  74. package/dist/react18/upgrade-to-react-18.d.ts.map +1 -0
  75. package/dist/react18/upgrade-to-react-18.js +39 -0
  76. package/dist/react18/upgrade-to-react-18.js.map +1 -0
  77. package/dist/react19/deprecated-react-types.d.ts +8 -0
  78. package/dist/react19/deprecated-react-types.d.ts.map +1 -0
  79. package/dist/react19/deprecated-react-types.js +135 -0
  80. package/dist/react19/deprecated-react-types.js.map +1 -0
  81. package/dist/react19/find-context-consumer.d.ts +9 -0
  82. package/dist/react19/find-context-consumer.d.ts.map +1 -0
  83. package/dist/react19/find-context-consumer.js +128 -0
  84. package/dist/react19/find-context-consumer.js.map +1 -0
  85. package/dist/react19/find-deprecated-reactdom-apis.d.ts +9 -0
  86. package/dist/react19/find-deprecated-reactdom-apis.d.ts.map +1 -0
  87. package/dist/react19/find-deprecated-reactdom-apis.js +132 -0
  88. package/dist/react19/find-deprecated-reactdom-apis.js.map +1 -0
  89. package/dist/react19/find-element-ref.d.ts +9 -0
  90. package/dist/react19/find-element-ref.d.ts.map +1 -0
  91. package/dist/react19/find-element-ref.js +88 -0
  92. package/dist/react19/find-element-ref.js.map +1 -0
  93. package/dist/react19/find-legacy-context-api.d.ts +9 -0
  94. package/dist/react19/find-legacy-context-api.d.ts.map +1 -0
  95. package/dist/react19/find-legacy-context-api.js +163 -0
  96. package/dist/react19/find-legacy-context-api.js.map +1 -0
  97. package/dist/react19/no-implicit-ref-callback-return.d.ts +8 -0
  98. package/dist/react19/no-implicit-ref-callback-return.d.ts.map +1 -0
  99. package/dist/react19/no-implicit-ref-callback-return.js +107 -0
  100. package/dist/react19/no-implicit-ref-callback-return.js.map +1 -0
  101. package/dist/react19/remove-context-provider.d.ts +8 -0
  102. package/dist/react19/remove-context-provider.d.ts.map +1 -0
  103. package/dist/react19/remove-context-provider.js +59 -0
  104. package/dist/react19/remove-context-provider.js.map +1 -0
  105. package/dist/react19/remove-forward-ref.d.ts +8 -0
  106. package/dist/react19/remove-forward-ref.d.ts.map +1 -0
  107. package/dist/react19/remove-forward-ref.js +73 -0
  108. package/dist/react19/remove-forward-ref.js.map +1 -0
  109. package/dist/react19/remove-prop-types.d.ts +8 -0
  110. package/dist/react19/remove-prop-types.d.ts.map +1 -0
  111. package/dist/react19/remove-prop-types.js +76 -0
  112. package/dist/react19/remove-prop-types.js.map +1 -0
  113. package/dist/react19/remove-react-fc.d.ts +8 -0
  114. package/dist/react19/remove-react-fc.d.ts.map +1 -0
  115. package/dist/react19/remove-react-fc.js +149 -0
  116. package/dist/react19/remove-react-fc.js.map +1 -0
  117. package/dist/react19/replace-act-import.d.ts +9 -0
  118. package/dist/react19/replace-act-import.d.ts.map +1 -0
  119. package/dist/react19/replace-act-import.js +34 -0
  120. package/dist/react19/replace-act-import.js.map +1 -0
  121. package/dist/react19/replace-default-props.d.ts +8 -0
  122. package/dist/react19/replace-default-props.d.ts.map +1 -0
  123. package/dist/react19/replace-default-props.js +195 -0
  124. package/dist/react19/replace-default-props.js.map +1 -0
  125. package/dist/react19/replace-react-shallow-renderer.d.ts +8 -0
  126. package/dist/react19/replace-react-shallow-renderer.d.ts.map +1 -0
  127. package/dist/react19/replace-react-shallow-renderer.js +69 -0
  128. package/dist/react19/replace-react-shallow-renderer.js.map +1 -0
  129. package/dist/react19/replace-reactdom-hydrate.d.ts +8 -0
  130. package/dist/react19/replace-reactdom-hydrate.d.ts.map +1 -0
  131. package/dist/react19/replace-reactdom-hydrate.js +55 -0
  132. package/dist/react19/replace-reactdom-hydrate.js.map +1 -0
  133. package/dist/react19/replace-string-ref.d.ts +8 -0
  134. package/dist/react19/replace-string-ref.d.ts.map +1 -0
  135. package/dist/react19/replace-string-ref.js +75 -0
  136. package/dist/react19/replace-string-ref.js.map +1 -0
  137. package/dist/react19/replace-use-form-state.d.ts +8 -0
  138. package/dist/react19/replace-use-form-state.d.ts.map +1 -0
  139. package/dist/react19/replace-use-form-state.js +54 -0
  140. package/dist/react19/replace-use-form-state.js.map +1 -0
  141. package/dist/react19/upgrade-to-react-19.d.ts +8 -0
  142. package/dist/react19/upgrade-to-react-19.d.ts.map +1 -0
  143. package/dist/react19/upgrade-to-react-19.js +59 -0
  144. package/dist/react19/upgrade-to-react-19.js.map +1 -0
  145. package/dist/react19/use-context-hook.d.ts +8 -0
  146. package/dist/react19/use-context-hook.d.ts.map +1 -0
  147. package/dist/react19/use-context-hook.js +54 -0
  148. package/dist/react19/use-context-hook.js.map +1 -0
  149. package/dist/react19/use-ref-required-initial.d.ts +8 -0
  150. package/dist/react19/use-ref-required-initial.d.ts.map +1 -0
  151. package/dist/react19/use-ref-required-initial.js +74 -0
  152. package/dist/react19/use-ref-required-initial.js.map +1 -0
  153. package/dist/refactoring/class-to-functional.d.ts +8 -0
  154. package/dist/refactoring/class-to-functional.d.ts.map +1 -0
  155. package/dist/refactoring/class-to-functional.js +205 -0
  156. package/dist/refactoring/class-to-functional.js.map +1 -0
  157. package/dist/refactoring/create-class-to-es6.d.ts +8 -0
  158. package/dist/refactoring/create-class-to-es6.d.ts.map +1 -0
  159. package/dist/refactoring/create-class-to-es6.js +289 -0
  160. package/dist/refactoring/create-class-to-es6.js.map +1 -0
  161. package/dist/refactoring/create-element-to-jsx.d.ts +8 -0
  162. package/dist/refactoring/create-element-to-jsx.d.ts.map +1 -0
  163. package/dist/refactoring/create-element-to-jsx.js +167 -0
  164. package/dist/refactoring/create-element-to-jsx.js.map +1 -0
  165. package/dist/refactoring/manual-bind-to-arrow.d.ts +8 -0
  166. package/dist/refactoring/manual-bind-to-arrow.d.ts.map +1 -0
  167. package/dist/refactoring/manual-bind-to-arrow.js +134 -0
  168. package/dist/refactoring/manual-bind-to-arrow.js.map +1 -0
  169. package/dist/refactoring/pure-render-mixin.d.ts +8 -0
  170. package/dist/refactoring/pure-render-mixin.d.ts.map +1 -0
  171. package/dist/refactoring/pure-render-mixin.js +253 -0
  172. package/dist/refactoring/pure-render-mixin.js.map +1 -0
  173. package/dist/refactoring/sort-comp.d.ts +8 -0
  174. package/dist/refactoring/sort-comp.d.ts.map +1 -0
  175. package/dist/refactoring/sort-comp.js +128 -0
  176. package/dist/refactoring/sort-comp.js.map +1 -0
  177. package/dist/search/find-hook-usage.d.ts +9 -0
  178. package/dist/search/find-hook-usage.d.ts.map +1 -0
  179. package/dist/search/find-hook-usage.js +262 -0
  180. package/dist/search/find-hook-usage.js.map +1 -0
  181. package/dist/search/find-prop-usage.d.ts +15 -0
  182. package/dist/search/find-prop-usage.d.ts.map +1 -0
  183. package/dist/search/find-prop-usage.js +177 -0
  184. package/dist/search/find-prop-usage.js.map +1 -0
  185. package/dist/search/find-react-component.d.ts +15 -0
  186. package/dist/search/find-react-component.d.ts.map +1 -0
  187. package/dist/search/find-react-component.js +260 -0
  188. package/dist/search/find-react-component.js.map +1 -0
  189. package/dist/search/find-server-rendering-usage.d.ts +9 -0
  190. package/dist/search/find-server-rendering-usage.d.ts.map +1 -0
  191. package/dist/search/find-server-rendering-usage.js +131 -0
  192. package/dist/search/find-server-rendering-usage.js.map +1 -0
  193. package/dist/simplify-object-pattern-property.d.ts +8 -0
  194. package/dist/simplify-object-pattern-property.d.ts.map +1 -0
  195. package/dist/simplify-object-pattern-property.js +59 -0
  196. package/dist/simplify-object-pattern-property.js.map +1 -0
  197. package/dist/simplify-react-imports.d.ts +8 -0
  198. package/dist/simplify-react-imports.d.ts.map +1 -0
  199. package/dist/simplify-react-imports.js +199 -0
  200. package/dist/simplify-react-imports.js.map +1 -0
  201. package/package.json +39 -0
  202. package/src/index.ts +149 -0
  203. package/src/migration/change-component-prop-value.ts +268 -0
  204. package/src/react-native/view-prop-types.ts +63 -0
  205. package/src/react16/error-boundaries.ts +46 -0
  206. package/src/react16/find-dom-node.ts +55 -0
  207. package/src/react16/react-dom-factories.ts +99 -0
  208. package/src/react16/react-prop-types.ts +71 -0
  209. package/src/react16/react-to-react-dom.ts +104 -0
  210. package/src/react16/replace-create-factory.ts +96 -0
  211. package/src/react16/upgrade-to-react-16.ts +37 -0
  212. package/src/react17/remove-event-persist.ts +121 -0
  213. package/src/react17/rename-unsafe-lifecycles.ts +57 -0
  214. package/src/react17/update-react-imports.ts +50 -0
  215. package/src/react17/upgrade-to-react-17.ts +30 -0
  216. package/src/react18/remove-unstable-batched-updates.ts +192 -0
  217. package/src/react18/replace-reactdom-render.ts +68 -0
  218. package/src/react18/replace-render-callback.ts +66 -0
  219. package/src/react18/replace-unmount-component-at-node.ts +66 -0
  220. package/src/react18/upgrade-to-react-18.ts +33 -0
  221. package/src/react19/deprecated-react-types.ts +120 -0
  222. package/src/react19/find-context-consumer.ts +127 -0
  223. package/src/react19/find-deprecated-reactdom-apis.ts +125 -0
  224. package/src/react19/find-element-ref.ts +86 -0
  225. package/src/react19/find-legacy-context-api.ts +157 -0
  226. package/src/react19/no-implicit-ref-callback-return.ts +123 -0
  227. package/src/react19/remove-context-provider.ts +87 -0
  228. package/src/react19/remove-forward-ref.ts +69 -0
  229. package/src/react19/remove-prop-types.ts +86 -0
  230. package/src/react19/remove-react-fc.ts +247 -0
  231. package/src/react19/replace-act-import.ts +36 -0
  232. package/src/react19/replace-default-props.ts +220 -0
  233. package/src/react19/replace-react-shallow-renderer.ts +75 -0
  234. package/src/react19/replace-reactdom-hydrate.ts +67 -0
  235. package/src/react19/replace-string-ref.ts +89 -0
  236. package/src/react19/replace-use-form-state.ts +66 -0
  237. package/src/react19/upgrade-to-react-19.ts +66 -0
  238. package/src/react19/use-context-hook.ts +67 -0
  239. package/src/react19/use-ref-required-initial.ts +75 -0
  240. package/src/refactoring/class-to-functional.ts +229 -0
  241. package/src/refactoring/create-class-to-es6.ts +309 -0
  242. package/src/refactoring/create-element-to-jsx.ts +200 -0
  243. package/src/refactoring/manual-bind-to-arrow.ts +139 -0
  244. package/src/refactoring/pure-render-mixin.ts +346 -0
  245. package/src/refactoring/sort-comp.ts +135 -0
  246. package/src/search/find-hook-usage.ts +226 -0
  247. package/src/search/find-prop-usage.ts +176 -0
  248. package/src/search/find-react-component.ts +254 -0
  249. package/src/search/find-server-rendering-usage.ts +120 -0
  250. package/src/simplify-object-pattern-property.ts +71 -0
  251. package/src/simplify-react-imports.ts +241 -0
@@ -0,0 +1,241 @@
1
+ import {ExecutionContext, Recipe, TreeVisitor} from "@openrewrite/rewrite";
2
+ import {JavaScriptVisitor, maybeAddImport} from "@openrewrite/rewrite/javascript";
3
+ import {J} from "@openrewrite/rewrite/java";
4
+ import {JS} from "@openrewrite/rewrite/javascript";
5
+
6
+ /**
7
+ * Common React hooks and utilities that can be imported directly instead of
8
+ * accessed through the React namespace.
9
+ */
10
+ const REACT_EXPORTS = new Set([
11
+ // Hooks
12
+ 'useState',
13
+ 'useEffect',
14
+ 'useContext',
15
+ 'useReducer',
16
+ 'useCallback',
17
+ 'useMemo',
18
+ 'useRef',
19
+ 'useImperativeHandle',
20
+ 'useLayoutEffect',
21
+ 'useDebugValue',
22
+ 'useDeferredValue',
23
+ 'useTransition',
24
+ 'useId',
25
+ 'useSyncExternalStore',
26
+ 'useInsertionEffect',
27
+ // React 19 hooks
28
+ 'useActionState',
29
+ 'useFormStatus',
30
+ 'useOptimistic',
31
+ 'use',
32
+ // React 19 APIs
33
+ 'cache',
34
+ // Components
35
+ 'Fragment',
36
+ 'Suspense',
37
+ 'StrictMode',
38
+ 'Profiler',
39
+ // APIs
40
+ 'createContext',
41
+ 'forwardRef',
42
+ 'lazy',
43
+ 'memo',
44
+ 'startTransition',
45
+ 'Children',
46
+ 'cloneElement',
47
+ 'createElement',
48
+ 'createRef',
49
+ 'isValidElement',
50
+ ]);
51
+
52
+ /**
53
+ * Check if a MethodInvocation is `React.xxx()` where xxx is a known React export.
54
+ * Returns the method name if it is, undefined otherwise.
55
+ */
56
+ function getReactMethodName(method: J.MethodInvocation): string | undefined {
57
+ const methodName = method.name?.simpleName;
58
+ if (!methodName || !REACT_EXPORTS.has(methodName)) return undefined;
59
+
60
+ // Check if the select (the target) is the React identifier
61
+ // In J.MethodInvocation, select is wrapped in RightPadded
62
+ const select = method.select;
63
+ if (!select) return undefined;
64
+
65
+ // The select might be a RightPadded<Expression> or directly an Expression
66
+ // Let's check if it's an Identifier named "React"
67
+ const selectExpr = (select as any).element ?? select;
68
+ if (selectExpr?.kind !== J.Kind.Identifier) return undefined;
69
+
70
+ const identifier = selectExpr as J.Identifier;
71
+ if (identifier.simpleName !== 'React') return undefined;
72
+
73
+ return methodName;
74
+ }
75
+
76
+ /**
77
+ * Simplifies React namespace usage by converting `React.xxx` to direct imports.
78
+ *
79
+ * Instead of:
80
+ * ```tsx
81
+ * import React from 'react';
82
+ * const [count, setCount] = React.useState(0);
83
+ * ```
84
+ *
85
+ * This recipe produces:
86
+ * ```tsx
87
+ * import React, { useState } from 'react';
88
+ * const [count, setCount] = useState(0);
89
+ * ```
90
+ *
91
+ * This is a modern best practice that:
92
+ * - Reduces bundle size when tree-shaking is applied
93
+ * - Makes code more readable
94
+ * - Aligns with React team recommendations
95
+ */
96
+ export class SimplifyReactImports extends Recipe {
97
+ readonly name = "org.openrewrite.react.simplify-react-imports";
98
+ readonly displayName: string = "Simplify `React.xxx` to direct imports";
99
+ readonly description: string = "Converts `React.useState`, `React.useEffect`, and other React namespace accesses to direct named imports.";
100
+
101
+ async editor(): Promise<TreeVisitor<any, ExecutionContext>> {
102
+ return new class extends JavaScriptVisitor<ExecutionContext> {
103
+ // Track which React exports we've used in this file
104
+ private usedExports = new Set<string>();
105
+ // Track locally defined identifiers to avoid naming conflicts
106
+ private localIdentifiers = new Set<string>();
107
+
108
+ override async visitJsCompilationUnit(cu: JS.CompilationUnit, ctx: ExecutionContext): Promise<J | undefined> {
109
+ // Reset tracking for each file
110
+ this.usedExports = new Set<string>();
111
+ this.localIdentifiers = new Set<string>();
112
+
113
+ // First pass: collect all locally defined identifiers
114
+ await this.collectLocalIdentifiers(cu, ctx);
115
+
116
+ // Second pass: visit and transform all React.xxx usages
117
+ let result = await super.visitJsCompilationUnit(cu, ctx) as JS.CompilationUnit;
118
+
119
+ // Second pass: add imports for all used exports
120
+ // We set onlyIfReferenced: false since we already know these are used (we just transformed them)
121
+ for (const exportName of this.usedExports) {
122
+ maybeAddImport(this, {module: "react", member: exportName, onlyIfReferenced: false});
123
+ }
124
+
125
+ return result;
126
+ }
127
+
128
+ /**
129
+ * Collect all locally defined identifiers to detect potential naming conflicts.
130
+ * This includes variable declarations, function declarations, and non-React imports.
131
+ */
132
+ private async collectLocalIdentifiers(cu: JS.CompilationUnit, ctx: ExecutionContext): Promise<void> {
133
+ const collector = new class extends JavaScriptVisitor<ExecutionContext> {
134
+ constructor(private identifiers: Set<string>) {
135
+ super();
136
+ }
137
+
138
+ override async visitVariableDeclarations(varDecl: J.VariableDeclarations, ctx: ExecutionContext): Promise<J | undefined> {
139
+ for (const v of varDecl.variables) {
140
+ const name = v.element.name;
141
+ if (name.kind === J.Kind.Identifier) {
142
+ this.identifiers.add((name as J.Identifier).simpleName);
143
+ }
144
+ }
145
+ return super.visitVariableDeclarations(varDecl, ctx);
146
+ }
147
+
148
+ override async visitMethodDeclaration(method: J.MethodDeclaration, ctx: ExecutionContext): Promise<J | undefined> {
149
+ this.identifiers.add(method.name.simpleName);
150
+ return super.visitMethodDeclaration(method, ctx);
151
+ }
152
+
153
+ override async visitImportSpecifier(spec: JS.ImportSpecifier, ctx: ExecutionContext): Promise<J | undefined> {
154
+ // Track named imports
155
+ const specifier = spec.specifier;
156
+
157
+ if (specifier.kind === JS.Kind.Alias) {
158
+ // Aliased import: import { useState as myUseState }
159
+ const alias = specifier as JS.Alias;
160
+ const aliasIdent = alias.alias;
161
+ if (aliasIdent.kind === J.Kind.Identifier) {
162
+ this.identifiers.add((aliasIdent as J.Identifier).simpleName);
163
+ }
164
+ } else if (specifier.kind === J.Kind.Identifier) {
165
+ // Direct import: import { useState }
166
+ // We don't track these as conflicts since they're the imports we manage
167
+ }
168
+
169
+ return super.visitImportSpecifier(spec, ctx);
170
+ }
171
+ }(this.localIdentifiers);
172
+
173
+ await collector.visit(cu, ctx);
174
+ }
175
+
176
+ override async visitMethodInvocation(method: J.MethodInvocation, ctx: ExecutionContext): Promise<J | undefined> {
177
+ let m = await super.visitMethodInvocation(method, ctx) as J.MethodInvocation;
178
+
179
+ const methodName = getReactMethodName(m);
180
+ if (!methodName) {
181
+ return m;
182
+ }
183
+
184
+ // Skip transformation if there's a local identifier with the same name
185
+ if (this.localIdentifiers.has(methodName)) {
186
+ return m;
187
+ }
188
+
189
+ // Track that we used this export
190
+ this.usedExports.add(methodName);
191
+
192
+ // Transform React.xxx() to xxx() by removing the select
193
+ // The original structure is: [prefix]React.useState(...)
194
+ // We need: [prefix]useState(...)
195
+ // The method name's prefix currently has the dot's spacing, we need to use the original prefix
196
+ const result: J.MethodInvocation = {
197
+ ...m,
198
+ select: undefined,
199
+ name: m.name // Keep the name as-is
200
+ };
201
+
202
+ return result;
203
+ }
204
+
205
+ override async visitFieldAccess(fieldAccess: J.FieldAccess, ctx: ExecutionContext): Promise<J | undefined> {
206
+ let fa = await super.visitFieldAccess(fieldAccess, ctx) as J.FieldAccess;
207
+
208
+ // Check if this is React.xxx access (for non-call usages like JSX element names)
209
+ if (fa.target.kind !== J.Kind.Identifier) {
210
+ return fa;
211
+ }
212
+
213
+ const target = fa.target as J.Identifier;
214
+ if (target.simpleName !== 'React') {
215
+ return fa;
216
+ }
217
+
218
+ const memberName = fa.name.element.simpleName;
219
+ if (!REACT_EXPORTS.has(memberName)) {
220
+ return fa;
221
+ }
222
+
223
+ // Skip transformation if there's a local identifier with the same name
224
+ if (this.localIdentifiers.has(memberName)) {
225
+ return fa;
226
+ }
227
+
228
+ // Track that we used this export
229
+ this.usedExports.add(memberName);
230
+
231
+ // Return just the identifier (removing React. prefix)
232
+ const identifier: J.Identifier = {
233
+ ...fa.name.element,
234
+ prefix: fa.prefix // Preserve the original whitespace
235
+ };
236
+
237
+ return identifier;
238
+ }
239
+ }();
240
+ }
241
+ }