@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.
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +130 -0
- package/dist/index.js.map +1 -0
- package/dist/migration/change-component-prop-value.d.ts +20 -0
- package/dist/migration/change-component-prop-value.d.ts.map +1 -0
- package/dist/migration/change-component-prop-value.js +217 -0
- package/dist/migration/change-component-prop-value.js.map +1 -0
- package/dist/react-native/view-prop-types.d.ts +8 -0
- package/dist/react-native/view-prop-types.d.ts.map +1 -0
- package/dist/react-native/view-prop-types.js +65 -0
- package/dist/react-native/view-prop-types.js.map +1 -0
- package/dist/react16/error-boundaries.d.ts +8 -0
- package/dist/react16/error-boundaries.d.ts.map +1 -0
- package/dist/react16/error-boundaries.js +42 -0
- package/dist/react16/error-boundaries.js.map +1 -0
- package/dist/react16/find-dom-node.d.ts +8 -0
- package/dist/react16/find-dom-node.d.ts.map +1 -0
- package/dist/react16/find-dom-node.js +48 -0
- package/dist/react16/find-dom-node.js.map +1 -0
- package/dist/react16/react-dom-factories.d.ts +8 -0
- package/dist/react16/react-dom-factories.d.ts.map +1 -0
- package/dist/react16/react-dom-factories.js +72 -0
- package/dist/react16/react-dom-factories.js.map +1 -0
- package/dist/react16/react-prop-types.d.ts +8 -0
- package/dist/react16/react-prop-types.d.ts.map +1 -0
- package/dist/react16/react-prop-types.js +69 -0
- package/dist/react16/react-prop-types.js.map +1 -0
- package/dist/react16/react-to-react-dom.d.ts +8 -0
- package/dist/react16/react-to-react-dom.d.ts.map +1 -0
- package/dist/react16/react-to-react-dom.js +97 -0
- package/dist/react16/react-to-react-dom.js.map +1 -0
- package/dist/react16/replace-create-factory.d.ts +8 -0
- package/dist/react16/replace-create-factory.d.ts.map +1 -0
- package/dist/react16/replace-create-factory.js +69 -0
- package/dist/react16/replace-create-factory.js.map +1 -0
- package/dist/react16/upgrade-to-react-16.d.ts +8 -0
- package/dist/react16/upgrade-to-react-16.d.ts.map +1 -0
- package/dist/react16/upgrade-to-react-16.js +41 -0
- package/dist/react16/upgrade-to-react-16.js.map +1 -0
- package/dist/react17/remove-event-persist.d.ts +8 -0
- package/dist/react17/remove-event-persist.d.ts.map +1 -0
- package/dist/react17/remove-event-persist.js +114 -0
- package/dist/react17/remove-event-persist.js.map +1 -0
- package/dist/react17/rename-unsafe-lifecycles.d.ts +8 -0
- package/dist/react17/rename-unsafe-lifecycles.d.ts.map +1 -0
- package/dist/react17/rename-unsafe-lifecycles.js +48 -0
- package/dist/react17/rename-unsafe-lifecycles.js.map +1 -0
- package/dist/react17/update-react-imports.d.ts +8 -0
- package/dist/react17/update-react-imports.d.ts.map +1 -0
- package/dist/react17/update-react-imports.js +40 -0
- package/dist/react17/update-react-imports.js.map +1 -0
- package/dist/react17/upgrade-to-react-17.d.ts +8 -0
- package/dist/react17/upgrade-to-react-17.d.ts.map +1 -0
- package/dist/react17/upgrade-to-react-17.js +37 -0
- package/dist/react17/upgrade-to-react-17.js.map +1 -0
- package/dist/react18/remove-unstable-batched-updates.d.ts +8 -0
- package/dist/react18/remove-unstable-batched-updates.d.ts.map +1 -0
- package/dist/react18/remove-unstable-batched-updates.js +170 -0
- package/dist/react18/remove-unstable-batched-updates.js.map +1 -0
- package/dist/react18/replace-reactdom-render.d.ts +8 -0
- package/dist/react18/replace-reactdom-render.d.ts.map +1 -0
- package/dist/react18/replace-reactdom-render.js +55 -0
- package/dist/react18/replace-reactdom-render.js.map +1 -0
- package/dist/react18/replace-render-callback.d.ts +8 -0
- package/dist/react18/replace-render-callback.d.ts.map +1 -0
- package/dist/react18/replace-render-callback.js +60 -0
- package/dist/react18/replace-render-callback.js.map +1 -0
- package/dist/react18/replace-unmount-component-at-node.d.ts +8 -0
- package/dist/react18/replace-unmount-component-at-node.d.ts.map +1 -0
- package/dist/react18/replace-unmount-component-at-node.js +54 -0
- package/dist/react18/replace-unmount-component-at-node.js.map +1 -0
- package/dist/react18/upgrade-to-react-18.d.ts +8 -0
- package/dist/react18/upgrade-to-react-18.d.ts.map +1 -0
- package/dist/react18/upgrade-to-react-18.js +39 -0
- package/dist/react18/upgrade-to-react-18.js.map +1 -0
- package/dist/react19/deprecated-react-types.d.ts +8 -0
- package/dist/react19/deprecated-react-types.d.ts.map +1 -0
- package/dist/react19/deprecated-react-types.js +135 -0
- package/dist/react19/deprecated-react-types.js.map +1 -0
- package/dist/react19/find-context-consumer.d.ts +9 -0
- package/dist/react19/find-context-consumer.d.ts.map +1 -0
- package/dist/react19/find-context-consumer.js +128 -0
- package/dist/react19/find-context-consumer.js.map +1 -0
- package/dist/react19/find-deprecated-reactdom-apis.d.ts +9 -0
- package/dist/react19/find-deprecated-reactdom-apis.d.ts.map +1 -0
- package/dist/react19/find-deprecated-reactdom-apis.js +132 -0
- package/dist/react19/find-deprecated-reactdom-apis.js.map +1 -0
- package/dist/react19/find-element-ref.d.ts +9 -0
- package/dist/react19/find-element-ref.d.ts.map +1 -0
- package/dist/react19/find-element-ref.js +88 -0
- package/dist/react19/find-element-ref.js.map +1 -0
- package/dist/react19/find-legacy-context-api.d.ts +9 -0
- package/dist/react19/find-legacy-context-api.d.ts.map +1 -0
- package/dist/react19/find-legacy-context-api.js +163 -0
- package/dist/react19/find-legacy-context-api.js.map +1 -0
- package/dist/react19/no-implicit-ref-callback-return.d.ts +8 -0
- package/dist/react19/no-implicit-ref-callback-return.d.ts.map +1 -0
- package/dist/react19/no-implicit-ref-callback-return.js +107 -0
- package/dist/react19/no-implicit-ref-callback-return.js.map +1 -0
- package/dist/react19/remove-context-provider.d.ts +8 -0
- package/dist/react19/remove-context-provider.d.ts.map +1 -0
- package/dist/react19/remove-context-provider.js +59 -0
- package/dist/react19/remove-context-provider.js.map +1 -0
- package/dist/react19/remove-forward-ref.d.ts +8 -0
- package/dist/react19/remove-forward-ref.d.ts.map +1 -0
- package/dist/react19/remove-forward-ref.js +73 -0
- package/dist/react19/remove-forward-ref.js.map +1 -0
- package/dist/react19/remove-prop-types.d.ts +8 -0
- package/dist/react19/remove-prop-types.d.ts.map +1 -0
- package/dist/react19/remove-prop-types.js +76 -0
- package/dist/react19/remove-prop-types.js.map +1 -0
- package/dist/react19/remove-react-fc.d.ts +8 -0
- package/dist/react19/remove-react-fc.d.ts.map +1 -0
- package/dist/react19/remove-react-fc.js +149 -0
- package/dist/react19/remove-react-fc.js.map +1 -0
- package/dist/react19/replace-act-import.d.ts +9 -0
- package/dist/react19/replace-act-import.d.ts.map +1 -0
- package/dist/react19/replace-act-import.js +34 -0
- package/dist/react19/replace-act-import.js.map +1 -0
- package/dist/react19/replace-default-props.d.ts +8 -0
- package/dist/react19/replace-default-props.d.ts.map +1 -0
- package/dist/react19/replace-default-props.js +195 -0
- package/dist/react19/replace-default-props.js.map +1 -0
- package/dist/react19/replace-react-shallow-renderer.d.ts +8 -0
- package/dist/react19/replace-react-shallow-renderer.d.ts.map +1 -0
- package/dist/react19/replace-react-shallow-renderer.js +69 -0
- package/dist/react19/replace-react-shallow-renderer.js.map +1 -0
- package/dist/react19/replace-reactdom-hydrate.d.ts +8 -0
- package/dist/react19/replace-reactdom-hydrate.d.ts.map +1 -0
- package/dist/react19/replace-reactdom-hydrate.js +55 -0
- package/dist/react19/replace-reactdom-hydrate.js.map +1 -0
- package/dist/react19/replace-string-ref.d.ts +8 -0
- package/dist/react19/replace-string-ref.d.ts.map +1 -0
- package/dist/react19/replace-string-ref.js +75 -0
- package/dist/react19/replace-string-ref.js.map +1 -0
- package/dist/react19/replace-use-form-state.d.ts +8 -0
- package/dist/react19/replace-use-form-state.d.ts.map +1 -0
- package/dist/react19/replace-use-form-state.js +54 -0
- package/dist/react19/replace-use-form-state.js.map +1 -0
- package/dist/react19/upgrade-to-react-19.d.ts +8 -0
- package/dist/react19/upgrade-to-react-19.d.ts.map +1 -0
- package/dist/react19/upgrade-to-react-19.js +59 -0
- package/dist/react19/upgrade-to-react-19.js.map +1 -0
- package/dist/react19/use-context-hook.d.ts +8 -0
- package/dist/react19/use-context-hook.d.ts.map +1 -0
- package/dist/react19/use-context-hook.js +54 -0
- package/dist/react19/use-context-hook.js.map +1 -0
- package/dist/react19/use-ref-required-initial.d.ts +8 -0
- package/dist/react19/use-ref-required-initial.d.ts.map +1 -0
- package/dist/react19/use-ref-required-initial.js +74 -0
- package/dist/react19/use-ref-required-initial.js.map +1 -0
- package/dist/refactoring/class-to-functional.d.ts +8 -0
- package/dist/refactoring/class-to-functional.d.ts.map +1 -0
- package/dist/refactoring/class-to-functional.js +205 -0
- package/dist/refactoring/class-to-functional.js.map +1 -0
- package/dist/refactoring/create-class-to-es6.d.ts +8 -0
- package/dist/refactoring/create-class-to-es6.d.ts.map +1 -0
- package/dist/refactoring/create-class-to-es6.js +289 -0
- package/dist/refactoring/create-class-to-es6.js.map +1 -0
- package/dist/refactoring/create-element-to-jsx.d.ts +8 -0
- package/dist/refactoring/create-element-to-jsx.d.ts.map +1 -0
- package/dist/refactoring/create-element-to-jsx.js +167 -0
- package/dist/refactoring/create-element-to-jsx.js.map +1 -0
- package/dist/refactoring/manual-bind-to-arrow.d.ts +8 -0
- package/dist/refactoring/manual-bind-to-arrow.d.ts.map +1 -0
- package/dist/refactoring/manual-bind-to-arrow.js +134 -0
- package/dist/refactoring/manual-bind-to-arrow.js.map +1 -0
- package/dist/refactoring/pure-render-mixin.d.ts +8 -0
- package/dist/refactoring/pure-render-mixin.d.ts.map +1 -0
- package/dist/refactoring/pure-render-mixin.js +253 -0
- package/dist/refactoring/pure-render-mixin.js.map +1 -0
- package/dist/refactoring/sort-comp.d.ts +8 -0
- package/dist/refactoring/sort-comp.d.ts.map +1 -0
- package/dist/refactoring/sort-comp.js +128 -0
- package/dist/refactoring/sort-comp.js.map +1 -0
- package/dist/search/find-hook-usage.d.ts +9 -0
- package/dist/search/find-hook-usage.d.ts.map +1 -0
- package/dist/search/find-hook-usage.js +262 -0
- package/dist/search/find-hook-usage.js.map +1 -0
- package/dist/search/find-prop-usage.d.ts +15 -0
- package/dist/search/find-prop-usage.d.ts.map +1 -0
- package/dist/search/find-prop-usage.js +177 -0
- package/dist/search/find-prop-usage.js.map +1 -0
- package/dist/search/find-react-component.d.ts +15 -0
- package/dist/search/find-react-component.d.ts.map +1 -0
- package/dist/search/find-react-component.js +260 -0
- package/dist/search/find-react-component.js.map +1 -0
- package/dist/search/find-server-rendering-usage.d.ts +9 -0
- package/dist/search/find-server-rendering-usage.d.ts.map +1 -0
- package/dist/search/find-server-rendering-usage.js +131 -0
- package/dist/search/find-server-rendering-usage.js.map +1 -0
- package/dist/simplify-object-pattern-property.d.ts +8 -0
- package/dist/simplify-object-pattern-property.d.ts.map +1 -0
- package/dist/simplify-object-pattern-property.js +59 -0
- package/dist/simplify-object-pattern-property.js.map +1 -0
- package/dist/simplify-react-imports.d.ts +8 -0
- package/dist/simplify-react-imports.d.ts.map +1 -0
- package/dist/simplify-react-imports.js +199 -0
- package/dist/simplify-react-imports.js.map +1 -0
- package/package.json +39 -0
- package/src/index.ts +149 -0
- package/src/migration/change-component-prop-value.ts +268 -0
- package/src/react-native/view-prop-types.ts +63 -0
- package/src/react16/error-boundaries.ts +46 -0
- package/src/react16/find-dom-node.ts +55 -0
- package/src/react16/react-dom-factories.ts +99 -0
- package/src/react16/react-prop-types.ts +71 -0
- package/src/react16/react-to-react-dom.ts +104 -0
- package/src/react16/replace-create-factory.ts +96 -0
- package/src/react16/upgrade-to-react-16.ts +37 -0
- package/src/react17/remove-event-persist.ts +121 -0
- package/src/react17/rename-unsafe-lifecycles.ts +57 -0
- package/src/react17/update-react-imports.ts +50 -0
- package/src/react17/upgrade-to-react-17.ts +30 -0
- package/src/react18/remove-unstable-batched-updates.ts +192 -0
- package/src/react18/replace-reactdom-render.ts +68 -0
- package/src/react18/replace-render-callback.ts +66 -0
- package/src/react18/replace-unmount-component-at-node.ts +66 -0
- package/src/react18/upgrade-to-react-18.ts +33 -0
- package/src/react19/deprecated-react-types.ts +120 -0
- package/src/react19/find-context-consumer.ts +127 -0
- package/src/react19/find-deprecated-reactdom-apis.ts +125 -0
- package/src/react19/find-element-ref.ts +86 -0
- package/src/react19/find-legacy-context-api.ts +157 -0
- package/src/react19/no-implicit-ref-callback-return.ts +123 -0
- package/src/react19/remove-context-provider.ts +87 -0
- package/src/react19/remove-forward-ref.ts +69 -0
- package/src/react19/remove-prop-types.ts +86 -0
- package/src/react19/remove-react-fc.ts +247 -0
- package/src/react19/replace-act-import.ts +36 -0
- package/src/react19/replace-default-props.ts +220 -0
- package/src/react19/replace-react-shallow-renderer.ts +75 -0
- package/src/react19/replace-reactdom-hydrate.ts +67 -0
- package/src/react19/replace-string-ref.ts +89 -0
- package/src/react19/replace-use-form-state.ts +66 -0
- package/src/react19/upgrade-to-react-19.ts +66 -0
- package/src/react19/use-context-hook.ts +67 -0
- package/src/react19/use-ref-required-initial.ts +75 -0
- package/src/refactoring/class-to-functional.ts +229 -0
- package/src/refactoring/create-class-to-es6.ts +309 -0
- package/src/refactoring/create-element-to-jsx.ts +200 -0
- package/src/refactoring/manual-bind-to-arrow.ts +139 -0
- package/src/refactoring/pure-render-mixin.ts +346 -0
- package/src/refactoring/sort-comp.ts +135 -0
- package/src/search/find-hook-usage.ts +226 -0
- package/src/search/find-prop-usage.ts +176 -0
- package/src/search/find-react-component.ts +254 -0
- package/src/search/find-server-rendering-usage.ts +120 -0
- package/src/simplify-object-pattern-property.ts +71 -0
- 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
|
+
}
|