@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,199 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.SimplifyReactImports = void 0;
|
|
13
|
+
const rewrite_1 = require("@openrewrite/rewrite");
|
|
14
|
+
const javascript_1 = require("@openrewrite/rewrite/javascript");
|
|
15
|
+
const java_1 = require("@openrewrite/rewrite/java");
|
|
16
|
+
const javascript_2 = require("@openrewrite/rewrite/javascript");
|
|
17
|
+
const REACT_EXPORTS = new Set([
|
|
18
|
+
'useState',
|
|
19
|
+
'useEffect',
|
|
20
|
+
'useContext',
|
|
21
|
+
'useReducer',
|
|
22
|
+
'useCallback',
|
|
23
|
+
'useMemo',
|
|
24
|
+
'useRef',
|
|
25
|
+
'useImperativeHandle',
|
|
26
|
+
'useLayoutEffect',
|
|
27
|
+
'useDebugValue',
|
|
28
|
+
'useDeferredValue',
|
|
29
|
+
'useTransition',
|
|
30
|
+
'useId',
|
|
31
|
+
'useSyncExternalStore',
|
|
32
|
+
'useInsertionEffect',
|
|
33
|
+
'useActionState',
|
|
34
|
+
'useFormStatus',
|
|
35
|
+
'useOptimistic',
|
|
36
|
+
'use',
|
|
37
|
+
'cache',
|
|
38
|
+
'Fragment',
|
|
39
|
+
'Suspense',
|
|
40
|
+
'StrictMode',
|
|
41
|
+
'Profiler',
|
|
42
|
+
'createContext',
|
|
43
|
+
'forwardRef',
|
|
44
|
+
'lazy',
|
|
45
|
+
'memo',
|
|
46
|
+
'startTransition',
|
|
47
|
+
'Children',
|
|
48
|
+
'cloneElement',
|
|
49
|
+
'createElement',
|
|
50
|
+
'createRef',
|
|
51
|
+
'isValidElement',
|
|
52
|
+
]);
|
|
53
|
+
function getReactMethodName(method) {
|
|
54
|
+
var _a, _b;
|
|
55
|
+
const methodName = (_a = method.name) === null || _a === void 0 ? void 0 : _a.simpleName;
|
|
56
|
+
if (!methodName || !REACT_EXPORTS.has(methodName))
|
|
57
|
+
return undefined;
|
|
58
|
+
const select = method.select;
|
|
59
|
+
if (!select)
|
|
60
|
+
return undefined;
|
|
61
|
+
const selectExpr = (_b = select.element) !== null && _b !== void 0 ? _b : select;
|
|
62
|
+
if ((selectExpr === null || selectExpr === void 0 ? void 0 : selectExpr.kind) !== java_1.J.Kind.Identifier)
|
|
63
|
+
return undefined;
|
|
64
|
+
const identifier = selectExpr;
|
|
65
|
+
if (identifier.simpleName !== 'React')
|
|
66
|
+
return undefined;
|
|
67
|
+
return methodName;
|
|
68
|
+
}
|
|
69
|
+
class SimplifyReactImports extends rewrite_1.Recipe {
|
|
70
|
+
constructor() {
|
|
71
|
+
super(...arguments);
|
|
72
|
+
this.name = "org.openrewrite.react.simplify-react-imports";
|
|
73
|
+
this.displayName = "Simplify `React.xxx` to direct imports";
|
|
74
|
+
this.description = "Converts `React.useState`, `React.useEffect`, and other React namespace accesses to direct named imports.";
|
|
75
|
+
}
|
|
76
|
+
editor() {
|
|
77
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
78
|
+
return new class extends javascript_1.JavaScriptVisitor {
|
|
79
|
+
constructor() {
|
|
80
|
+
super(...arguments);
|
|
81
|
+
this.usedExports = new Set();
|
|
82
|
+
this.localIdentifiers = new Set();
|
|
83
|
+
}
|
|
84
|
+
visitJsCompilationUnit(cu, ctx) {
|
|
85
|
+
const _super = Object.create(null, {
|
|
86
|
+
visitJsCompilationUnit: { get: () => super.visitJsCompilationUnit }
|
|
87
|
+
});
|
|
88
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
89
|
+
this.usedExports = new Set();
|
|
90
|
+
this.localIdentifiers = new Set();
|
|
91
|
+
yield this.collectLocalIdentifiers(cu, ctx);
|
|
92
|
+
let result = yield _super.visitJsCompilationUnit.call(this, cu, ctx);
|
|
93
|
+
for (const exportName of this.usedExports) {
|
|
94
|
+
(0, javascript_1.maybeAddImport)(this, { module: "react", member: exportName, onlyIfReferenced: false });
|
|
95
|
+
}
|
|
96
|
+
return result;
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
collectLocalIdentifiers(cu, ctx) {
|
|
100
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
101
|
+
const collector = new class extends javascript_1.JavaScriptVisitor {
|
|
102
|
+
constructor(identifiers) {
|
|
103
|
+
super();
|
|
104
|
+
this.identifiers = identifiers;
|
|
105
|
+
}
|
|
106
|
+
visitVariableDeclarations(varDecl, ctx) {
|
|
107
|
+
const _super = Object.create(null, {
|
|
108
|
+
visitVariableDeclarations: { get: () => super.visitVariableDeclarations }
|
|
109
|
+
});
|
|
110
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
111
|
+
for (const v of varDecl.variables) {
|
|
112
|
+
const name = v.element.name;
|
|
113
|
+
if (name.kind === java_1.J.Kind.Identifier) {
|
|
114
|
+
this.identifiers.add(name.simpleName);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return _super.visitVariableDeclarations.call(this, varDecl, ctx);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
visitMethodDeclaration(method, ctx) {
|
|
121
|
+
const _super = Object.create(null, {
|
|
122
|
+
visitMethodDeclaration: { get: () => super.visitMethodDeclaration }
|
|
123
|
+
});
|
|
124
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
125
|
+
this.identifiers.add(method.name.simpleName);
|
|
126
|
+
return _super.visitMethodDeclaration.call(this, method, ctx);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
visitImportSpecifier(spec, ctx) {
|
|
130
|
+
const _super = Object.create(null, {
|
|
131
|
+
visitImportSpecifier: { get: () => super.visitImportSpecifier }
|
|
132
|
+
});
|
|
133
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
134
|
+
const specifier = spec.specifier;
|
|
135
|
+
if (specifier.kind === javascript_2.JS.Kind.Alias) {
|
|
136
|
+
const alias = specifier;
|
|
137
|
+
const aliasIdent = alias.alias;
|
|
138
|
+
if (aliasIdent.kind === java_1.J.Kind.Identifier) {
|
|
139
|
+
this.identifiers.add(aliasIdent.simpleName);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
else if (specifier.kind === java_1.J.Kind.Identifier) {
|
|
143
|
+
}
|
|
144
|
+
return _super.visitImportSpecifier.call(this, spec, ctx);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}(this.localIdentifiers);
|
|
148
|
+
yield collector.visit(cu, ctx);
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
visitMethodInvocation(method, ctx) {
|
|
152
|
+
const _super = Object.create(null, {
|
|
153
|
+
visitMethodInvocation: { get: () => super.visitMethodInvocation }
|
|
154
|
+
});
|
|
155
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
156
|
+
let m = yield _super.visitMethodInvocation.call(this, method, ctx);
|
|
157
|
+
const methodName = getReactMethodName(m);
|
|
158
|
+
if (!methodName) {
|
|
159
|
+
return m;
|
|
160
|
+
}
|
|
161
|
+
if (this.localIdentifiers.has(methodName)) {
|
|
162
|
+
return m;
|
|
163
|
+
}
|
|
164
|
+
this.usedExports.add(methodName);
|
|
165
|
+
const result = Object.assign(Object.assign({}, m), { select: undefined, name: m.name });
|
|
166
|
+
return result;
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
visitFieldAccess(fieldAccess, ctx) {
|
|
170
|
+
const _super = Object.create(null, {
|
|
171
|
+
visitFieldAccess: { get: () => super.visitFieldAccess }
|
|
172
|
+
});
|
|
173
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
174
|
+
let fa = yield _super.visitFieldAccess.call(this, fieldAccess, ctx);
|
|
175
|
+
if (fa.target.kind !== java_1.J.Kind.Identifier) {
|
|
176
|
+
return fa;
|
|
177
|
+
}
|
|
178
|
+
const target = fa.target;
|
|
179
|
+
if (target.simpleName !== 'React') {
|
|
180
|
+
return fa;
|
|
181
|
+
}
|
|
182
|
+
const memberName = fa.name.element.simpleName;
|
|
183
|
+
if (!REACT_EXPORTS.has(memberName)) {
|
|
184
|
+
return fa;
|
|
185
|
+
}
|
|
186
|
+
if (this.localIdentifiers.has(memberName)) {
|
|
187
|
+
return fa;
|
|
188
|
+
}
|
|
189
|
+
this.usedExports.add(memberName);
|
|
190
|
+
const identifier = Object.assign(Object.assign({}, fa.name.element), { prefix: fa.prefix });
|
|
191
|
+
return identifier;
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}();
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
exports.SimplifyReactImports = SimplifyReactImports;
|
|
199
|
+
//# sourceMappingURL=simplify-react-imports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"simplify-react-imports.js","sourceRoot":"","sources":["../src/simplify-react-imports.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@openrewrite/recipes-react",
|
|
3
|
+
"version": "0.2.9",
|
|
4
|
+
"license": "Moderne Source Available License",
|
|
5
|
+
"description": "OpenRewrite recipes for React.",
|
|
6
|
+
"homepage": "https://github.com/openrewrite/rewrite",
|
|
7
|
+
"main": "./dist/src/index.js",
|
|
8
|
+
"types": "./dist/src/index.d.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist/src/**",
|
|
11
|
+
"src/**"
|
|
12
|
+
],
|
|
13
|
+
"exports": {
|
|
14
|
+
".": "./dist/src/index.js"
|
|
15
|
+
},
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"prebuild": "bun -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && bun -e \"require('fs').rmSync('tsconfig.build.tsbuildinfo',{force:true})\"",
|
|
21
|
+
"build": "tsc --build tsconfig.build.json",
|
|
22
|
+
"dev": "tsc --watch -p tsconfig.json",
|
|
23
|
+
"test": "npm run build && jest",
|
|
24
|
+
"ci:test": "NODE_OPTIONS=--max-old-space-size=6144 jest --runInBand"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@openrewrite/rewrite": "next",
|
|
28
|
+
"mutative": "^1.1.0"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/jest": "^29.5.13",
|
|
32
|
+
"bun": "^1.3.5",
|
|
33
|
+
"jest": "^29.7.0",
|
|
34
|
+
"tmp-promise": "^3.0.3",
|
|
35
|
+
"ts-jest": "^29.2.5",
|
|
36
|
+
"ts-node": "^10.9.2",
|
|
37
|
+
"typescript": "^5.6.2"
|
|
38
|
+
}
|
|
39
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import {CategoryDescriptor, JavaScript, RecipeMarketplace} from "@openrewrite/rewrite";
|
|
2
|
+
|
|
3
|
+
// React 19
|
|
4
|
+
import {RemoveForwardRef} from './react19/remove-forward-ref';
|
|
5
|
+
import {RemoveReactFC} from './react19/remove-react-fc';
|
|
6
|
+
import {ReplaceActImport} from './react19/replace-act-import';
|
|
7
|
+
import {RemoveContextProvider} from './react19/remove-context-provider';
|
|
8
|
+
import {UseContextHook} from './react19/use-context-hook';
|
|
9
|
+
import {ReplaceUseFormState} from './react19/replace-use-form-state';
|
|
10
|
+
import {ReplaceStringRef} from './react19/replace-string-ref';
|
|
11
|
+
import {ReplaceDefaultProps} from './react19/replace-default-props';
|
|
12
|
+
import {ReplaceReactDomHydrate} from './react19/replace-reactdom-hydrate';
|
|
13
|
+
import {UseRefRequiredInitial} from './react19/use-ref-required-initial';
|
|
14
|
+
import {RemovePropTypes} from './react19/remove-prop-types';
|
|
15
|
+
import {NoImplicitRefCallbackReturn} from './react19/no-implicit-ref-callback-return';
|
|
16
|
+
import {DeprecatedReactTypes} from './react19/deprecated-react-types';
|
|
17
|
+
import {FindLegacyContextAPI} from './react19/find-legacy-context-api';
|
|
18
|
+
import {FindDeprecatedReactDomAPIs} from './react19/find-deprecated-reactdom-apis';
|
|
19
|
+
import {FindContextConsumer} from './react19/find-context-consumer';
|
|
20
|
+
import {UpgradeToReact19} from './react19/upgrade-to-react-19';
|
|
21
|
+
|
|
22
|
+
import {FindElementRef} from './react19/find-element-ref';
|
|
23
|
+
import {ReplaceReactShallowRenderer} from './react19/replace-react-shallow-renderer';
|
|
24
|
+
|
|
25
|
+
// React 18
|
|
26
|
+
import {ReplaceReactDomRender} from './react18/replace-reactdom-render';
|
|
27
|
+
import {RemoveUnstableBatchedUpdates} from './react18/remove-unstable-batched-updates';
|
|
28
|
+
import {ReplaceUnmountComponentAtNode} from './react18/replace-unmount-component-at-node';
|
|
29
|
+
import {ReplaceRenderCallback} from './react18/replace-render-callback';
|
|
30
|
+
import {UpgradeToReact18} from './react18/upgrade-to-react-18';
|
|
31
|
+
|
|
32
|
+
// React 17
|
|
33
|
+
import {RenameUnsafeLifecycles} from './react17/rename-unsafe-lifecycles';
|
|
34
|
+
import {UpdateReactImports} from './react17/update-react-imports';
|
|
35
|
+
import {RemoveEventPersist} from './react17/remove-event-persist';
|
|
36
|
+
import {UpgradeToReact17} from './react17/upgrade-to-react-17';
|
|
37
|
+
|
|
38
|
+
// React 16
|
|
39
|
+
import {ErrorBoundaries} from './react16/error-boundaries';
|
|
40
|
+
import {FindDomNode} from './react16/find-dom-node';
|
|
41
|
+
import {ReactPropTypes} from './react16/react-prop-types';
|
|
42
|
+
import {ReactDomFactories} from './react16/react-dom-factories';
|
|
43
|
+
import {ReactToReactDom} from './react16/react-to-react-dom';
|
|
44
|
+
import {ReplaceCreateFactory} from './react16/replace-create-factory';
|
|
45
|
+
import {UpgradeToReact16} from './react16/upgrade-to-react-16';
|
|
46
|
+
|
|
47
|
+
// Refactoring
|
|
48
|
+
import {CreateClassToES6} from './refactoring/create-class-to-es6';
|
|
49
|
+
import {ClassToFunctional} from './refactoring/class-to-functional';
|
|
50
|
+
import {ManualBindToArrow} from './refactoring/manual-bind-to-arrow';
|
|
51
|
+
import {CreateElementToJsx} from './refactoring/create-element-to-jsx';
|
|
52
|
+
import {SortComp} from './refactoring/sort-comp';
|
|
53
|
+
import {PureRenderMixin} from './refactoring/pure-render-mixin';
|
|
54
|
+
|
|
55
|
+
// React Native
|
|
56
|
+
import {ViewPropTypes} from './react-native/view-prop-types';
|
|
57
|
+
|
|
58
|
+
// Search & Analysis
|
|
59
|
+
import {FindReactComponent} from './search/find-react-component';
|
|
60
|
+
import {FindHookUsage} from './search/find-hook-usage';
|
|
61
|
+
import {FindPropUsage} from './search/find-prop-usage';
|
|
62
|
+
import {FindServerRenderingUsage} from './search/find-server-rendering-usage';
|
|
63
|
+
|
|
64
|
+
// General
|
|
65
|
+
import {SimplifyReactImports} from './simplify-react-imports';
|
|
66
|
+
import {SimplifyObjectPatternProperty} from './simplify-object-pattern-property';
|
|
67
|
+
import {ChangeComponentPropValue} from './migration/change-component-prop-value';
|
|
68
|
+
|
|
69
|
+
// Categories
|
|
70
|
+
const React: CategoryDescriptor[] = [...JavaScript, {displayName: "React"}];
|
|
71
|
+
const ReactMigrate: CategoryDescriptor[] = [...React, {displayName: "Migrate"}];
|
|
72
|
+
const React16: CategoryDescriptor[] = [...ReactMigrate, {displayName: "React 16"}];
|
|
73
|
+
const React17: CategoryDescriptor[] = [...ReactMigrate, {displayName: "React 17"}];
|
|
74
|
+
const React18: CategoryDescriptor[] = [...ReactMigrate, {displayName: "React 18"}];
|
|
75
|
+
const React19: CategoryDescriptor[] = [...ReactMigrate, {displayName: "React 19"}];
|
|
76
|
+
const ReactMigration: CategoryDescriptor[] = [...React, {displayName: "Migration"}];
|
|
77
|
+
const ReactRefactoring: CategoryDescriptor[] = [...React, {displayName: "Refactoring"}];
|
|
78
|
+
const ReactNative: CategoryDescriptor[] = [...React, {displayName: "React Native"}];
|
|
79
|
+
const ReactSearch: CategoryDescriptor[] = [...React, {displayName: "Search"}];
|
|
80
|
+
const JavaScriptCleanup: CategoryDescriptor[] = [...JavaScript, {displayName: "Cleanup"}];
|
|
81
|
+
|
|
82
|
+
export async function activate(marketplace: RecipeMarketplace) {
|
|
83
|
+
// React 19
|
|
84
|
+
await marketplace.install(RemoveForwardRef, React19);
|
|
85
|
+
await marketplace.install(RemoveReactFC, React19);
|
|
86
|
+
await marketplace.install(ReplaceActImport, React19);
|
|
87
|
+
await marketplace.install(RemoveContextProvider, React19);
|
|
88
|
+
await marketplace.install(UseContextHook, React19);
|
|
89
|
+
await marketplace.install(ReplaceUseFormState, React19);
|
|
90
|
+
await marketplace.install(ReplaceStringRef, React19);
|
|
91
|
+
await marketplace.install(ReplaceDefaultProps, React19);
|
|
92
|
+
await marketplace.install(ReplaceReactDomHydrate, React19);
|
|
93
|
+
await marketplace.install(UseRefRequiredInitial, React19);
|
|
94
|
+
await marketplace.install(RemovePropTypes, React19);
|
|
95
|
+
await marketplace.install(NoImplicitRefCallbackReturn, React19);
|
|
96
|
+
await marketplace.install(DeprecatedReactTypes, React19);
|
|
97
|
+
await marketplace.install(FindLegacyContextAPI, React19);
|
|
98
|
+
await marketplace.install(FindDeprecatedReactDomAPIs, React19);
|
|
99
|
+
await marketplace.install(FindContextConsumer, React19);
|
|
100
|
+
await marketplace.install(FindElementRef, React19);
|
|
101
|
+
await marketplace.install(ReplaceReactShallowRenderer, React19);
|
|
102
|
+
await marketplace.install(UpgradeToReact19, ReactMigrate);
|
|
103
|
+
|
|
104
|
+
// React 18
|
|
105
|
+
await marketplace.install(ReplaceReactDomRender, React18);
|
|
106
|
+
await marketplace.install(RemoveUnstableBatchedUpdates, React18);
|
|
107
|
+
await marketplace.install(ReplaceUnmountComponentAtNode, React18);
|
|
108
|
+
await marketplace.install(ReplaceRenderCallback, React18);
|
|
109
|
+
await marketplace.install(UpgradeToReact18, ReactMigrate);
|
|
110
|
+
|
|
111
|
+
// React 17
|
|
112
|
+
await marketplace.install(RenameUnsafeLifecycles, React17);
|
|
113
|
+
await marketplace.install(UpdateReactImports, React17);
|
|
114
|
+
await marketplace.install(RemoveEventPersist, React17);
|
|
115
|
+
await marketplace.install(UpgradeToReact17, ReactMigrate);
|
|
116
|
+
|
|
117
|
+
// React 16
|
|
118
|
+
await marketplace.install(ErrorBoundaries, React16);
|
|
119
|
+
await marketplace.install(FindDomNode, React16);
|
|
120
|
+
await marketplace.install(ReactPropTypes, React16);
|
|
121
|
+
await marketplace.install(ReactDomFactories, React16);
|
|
122
|
+
await marketplace.install(ReactToReactDom, React16);
|
|
123
|
+
await marketplace.install(ReplaceCreateFactory, React16);
|
|
124
|
+
await marketplace.install(UpgradeToReact16, ReactMigrate);
|
|
125
|
+
|
|
126
|
+
// Refactoring
|
|
127
|
+
await marketplace.install(CreateClassToES6, ReactRefactoring);
|
|
128
|
+
await marketplace.install(ClassToFunctional, ReactRefactoring);
|
|
129
|
+
await marketplace.install(ManualBindToArrow, ReactRefactoring);
|
|
130
|
+
await marketplace.install(CreateElementToJsx, ReactRefactoring);
|
|
131
|
+
await marketplace.install(SortComp, ReactRefactoring);
|
|
132
|
+
await marketplace.install(PureRenderMixin, ReactRefactoring);
|
|
133
|
+
|
|
134
|
+
// React Native
|
|
135
|
+
await marketplace.install(ViewPropTypes, ReactNative);
|
|
136
|
+
|
|
137
|
+
// Search & Analysis
|
|
138
|
+
await marketplace.install(FindReactComponent, ReactSearch);
|
|
139
|
+
await marketplace.install(FindHookUsage, ReactSearch);
|
|
140
|
+
await marketplace.install(FindPropUsage, ReactSearch);
|
|
141
|
+
await marketplace.install(FindServerRenderingUsage, ReactSearch);
|
|
142
|
+
|
|
143
|
+
// General
|
|
144
|
+
await marketplace.install(SimplifyReactImports, React);
|
|
145
|
+
await marketplace.install(SimplifyObjectPatternProperty, JavaScriptCleanup);
|
|
146
|
+
await marketplace.install(ChangeComponentPropValue, ReactMigration);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export {ChangeComponentPropValue} from './migration/change-component-prop-value';
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import {ExecutionContext, Option, Recipe, TreeVisitor} from "@openrewrite/rewrite";
|
|
2
|
+
import {JavaScriptVisitor, JS, JSX} from "@openrewrite/rewrite/javascript";
|
|
3
|
+
import {J, isIdentifier} from "@openrewrite/rewrite/java";
|
|
4
|
+
import {create} from "mutative";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Changes literal prop values on React components during library upgrades.
|
|
8
|
+
*
|
|
9
|
+
* This recipe is useful when upgrading UI libraries that rename prop values
|
|
10
|
+
* (e.g., Material-UI, Ant Design). It only transforms literal string values,
|
|
11
|
+
* skipping variables and expressions to avoid unintended changes.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* // Exact match
|
|
15
|
+
* const recipe = new ChangeComponentPropValue({
|
|
16
|
+
* componentName: "Button",
|
|
17
|
+
* propName: "variant",
|
|
18
|
+
* oldValue: "outlined",
|
|
19
|
+
* newValue: "outlined-primary"
|
|
20
|
+
* });
|
|
21
|
+
* // Before: <Button variant="outlined">Click me</Button>
|
|
22
|
+
* // After: <Button variant="outlined-primary">Click me</Button>
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* // Regex with capture groups
|
|
26
|
+
* const recipe = new ChangeComponentPropValue({
|
|
27
|
+
* componentName: "Button",
|
|
28
|
+
* propName: "variant",
|
|
29
|
+
* oldValue: "^(outlined|text|contained)$",
|
|
30
|
+
* newValue: "$1-primary",
|
|
31
|
+
* regex: true
|
|
32
|
+
* });
|
|
33
|
+
* // Before: <Button variant="outlined">Click me</Button>
|
|
34
|
+
* // After: <Button variant="outlined-primary">Click me</Button>
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* // Change all values (omit oldValue)
|
|
38
|
+
* const recipe = new ChangeComponentPropValue({
|
|
39
|
+
* componentName: "Button",
|
|
40
|
+
* propName: "variant",
|
|
41
|
+
* newValue: "primary"
|
|
42
|
+
* });
|
|
43
|
+
* // Before: <Button variant="outlined">Click me</Button>
|
|
44
|
+
* // After: <Button variant="primary">Click me</Button>
|
|
45
|
+
*/
|
|
46
|
+
export class ChangeComponentPropValue extends Recipe {
|
|
47
|
+
readonly name = "org.openrewrite.react.migration.change-component-prop-value";
|
|
48
|
+
readonly displayName: string = "Change React component prop value";
|
|
49
|
+
readonly description: string = "Changes literal prop values on React components. Useful for library upgrades where prop values were renamed (e.g., Material-UI, Ant Design).";
|
|
50
|
+
|
|
51
|
+
@Option({
|
|
52
|
+
displayName: "Component name",
|
|
53
|
+
description: "The name of the React component to target",
|
|
54
|
+
example: "Button"
|
|
55
|
+
})
|
|
56
|
+
componentName!: string;
|
|
57
|
+
|
|
58
|
+
@Option({
|
|
59
|
+
displayName: "Prop name",
|
|
60
|
+
description: "The name of the prop whose value should be changed",
|
|
61
|
+
example: "variant"
|
|
62
|
+
})
|
|
63
|
+
propName!: string;
|
|
64
|
+
|
|
65
|
+
@Option({
|
|
66
|
+
displayName: "Old value",
|
|
67
|
+
description: "The old value to match. If `regex` is `true`, interpreted as a regular expression pattern. Supports `/pattern/flags` format for specifying regex flags (e.g., `/pattern/i` for case-insensitive). If not provided, matches all values.",
|
|
68
|
+
example: "outlined",
|
|
69
|
+
required: false
|
|
70
|
+
})
|
|
71
|
+
oldValue?: string;
|
|
72
|
+
|
|
73
|
+
@Option({
|
|
74
|
+
displayName: "New value",
|
|
75
|
+
description: "The new value to replace with. Can use `$1`, `$2`, etc. to reference capture groups if `regex` is `true`.",
|
|
76
|
+
example: "outlined-primary"
|
|
77
|
+
})
|
|
78
|
+
newValue!: string;
|
|
79
|
+
|
|
80
|
+
@Option({
|
|
81
|
+
displayName: "Regex",
|
|
82
|
+
description: "If `true`, `oldValue` is interpreted as a regex pattern. Capture groups can be referenced in newValue using `$1`, `$2`, etc.",
|
|
83
|
+
required: false
|
|
84
|
+
})
|
|
85
|
+
regex?: boolean;
|
|
86
|
+
|
|
87
|
+
constructor(options?: {
|
|
88
|
+
componentName?: string;
|
|
89
|
+
propName?: string;
|
|
90
|
+
oldValue?: string;
|
|
91
|
+
newValue?: string;
|
|
92
|
+
regex?: boolean;
|
|
93
|
+
}) {
|
|
94
|
+
super(options);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async editor(): Promise<TreeVisitor<any, ExecutionContext>> {
|
|
98
|
+
const componentName = this.componentName;
|
|
99
|
+
const propName = this.propName;
|
|
100
|
+
const oldValue = this.oldValue;
|
|
101
|
+
const newValue = this.newValue;
|
|
102
|
+
const isRegex = this.regex ?? false;
|
|
103
|
+
|
|
104
|
+
// Build matcher based on regex flag and oldValue
|
|
105
|
+
let matcher: ((value: string) => string | null);
|
|
106
|
+
|
|
107
|
+
if (!oldValue) {
|
|
108
|
+
// No old value specified - match all values
|
|
109
|
+
matcher = (value: string) => newValue;
|
|
110
|
+
} else if (isRegex) {
|
|
111
|
+
// Compile regex pattern, supporting /pattern/flags format
|
|
112
|
+
let pattern = oldValue;
|
|
113
|
+
let flags = '';
|
|
114
|
+
|
|
115
|
+
// Check if pattern is in /pattern/flags format
|
|
116
|
+
const regexMatch = oldValue.match(/^\/(.+?)\/([gimsuvy]*)$/);
|
|
117
|
+
if (regexMatch) {
|
|
118
|
+
pattern = regexMatch[1];
|
|
119
|
+
flags = regexMatch[2];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const regex = new RegExp(pattern, flags);
|
|
123
|
+
|
|
124
|
+
matcher = (value: string) => {
|
|
125
|
+
const match = value.match(regex);
|
|
126
|
+
if (match) {
|
|
127
|
+
// Replace $1, $2, etc. with capture groups
|
|
128
|
+
return newValue.replace(/\$(\d+)/g, (_, num) => match[parseInt(num)] || '');
|
|
129
|
+
}
|
|
130
|
+
return null;
|
|
131
|
+
};
|
|
132
|
+
} else {
|
|
133
|
+
// Literal string match
|
|
134
|
+
matcher = (value: string) => value === oldValue ? newValue : null;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return new class extends JavaScriptVisitor<ExecutionContext> {
|
|
138
|
+
// FIXME: This manual import tracking should be removed once type attribution preserves
|
|
139
|
+
// module/package origin information. Currently, JSX element types show as generic
|
|
140
|
+
// function types (𝑓) without preserving where they were imported from. Ideally, we
|
|
141
|
+
// should be able to match components by checking if their type originates from the
|
|
142
|
+
// expected module (e.g., @mui/material.Button), which would automatically handle
|
|
143
|
+
// all import patterns (named, aliased, default, namespace) without manual tracking.
|
|
144
|
+
private componentAliases = new Map<string, string>();
|
|
145
|
+
|
|
146
|
+
override async visitCompilationUnit(cu: J.CompilationUnit, p: ExecutionContext): Promise<J | undefined> {
|
|
147
|
+
// Reset aliases for each file
|
|
148
|
+
this.componentAliases.clear();
|
|
149
|
+
return super.visitCompilationUnit(cu, p);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
override async visitImportSpecifier(spec: JS.ImportSpecifier, p: ExecutionContext): Promise<J | undefined> {
|
|
153
|
+
// Track named imports with potential aliases
|
|
154
|
+
const specifier = spec.specifier;
|
|
155
|
+
|
|
156
|
+
if (specifier.kind === JS.Kind.Alias) {
|
|
157
|
+
const alias = specifier as JS.Alias;
|
|
158
|
+
const propertyName = alias.propertyName.element;
|
|
159
|
+
|
|
160
|
+
if (isIdentifier(propertyName) && propertyName.simpleName === componentName) {
|
|
161
|
+
// Aliased import: import { Button as CustomButton }
|
|
162
|
+
const aliasIdent = alias.alias;
|
|
163
|
+
if (isIdentifier(aliasIdent)) {
|
|
164
|
+
this.componentAliases.set(aliasIdent.simpleName, componentName);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
} else if (isIdentifier(specifier) && specifier.simpleName === componentName) {
|
|
168
|
+
// Direct import: import { Button }
|
|
169
|
+
this.componentAliases.set(componentName, componentName);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return super.visitImportSpecifier(spec, p);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
override async visitImportClause(clause: JS.ImportClause, p: ExecutionContext): Promise<J | undefined> {
|
|
176
|
+
// Track default imports
|
|
177
|
+
if (clause.name) {
|
|
178
|
+
const identifier = clause.name.element;
|
|
179
|
+
if (isIdentifier(identifier) && identifier.simpleName === componentName) {
|
|
180
|
+
// Default import: import Button from '...'
|
|
181
|
+
this.componentAliases.set(componentName, componentName);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return super.visitImportClause(clause, p);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
override async visitJsxAttribute(attribute: JSX.Attribute, p: ExecutionContext): Promise<J | undefined> {
|
|
189
|
+
// Visit children first
|
|
190
|
+
const attr = await super.visitJsxAttribute(attribute, p) as JSX.Attribute;
|
|
191
|
+
|
|
192
|
+
// Check if this is the prop we're looking for
|
|
193
|
+
const key = attr.key;
|
|
194
|
+
if (!isIdentifier(key) || key.simpleName !== propName) {
|
|
195
|
+
return attr;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Verify this attribute belongs to the target component
|
|
199
|
+
const tag = this.cursor.firstEnclosing((t): t is JSX.Tag =>
|
|
200
|
+
t.kind === JS.Kind.JsxTag
|
|
201
|
+
);
|
|
202
|
+
if (!tag) {
|
|
203
|
+
return attr;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (!this.isTargetComponent(tag)) {
|
|
207
|
+
return attr;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Check if the value is a literal we should replace
|
|
211
|
+
if (!attr.value) {
|
|
212
|
+
return attr;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const value = attr.value.element;
|
|
216
|
+
const newValue = this.getReplacementValue(value);
|
|
217
|
+
if (!newValue) {
|
|
218
|
+
return attr;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Replace the value
|
|
222
|
+
return create(attr, draft => {
|
|
223
|
+
if (draft.value) {
|
|
224
|
+
draft.value.element = newValue;
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
private isTargetComponent(tag: JSX.Tag): boolean {
|
|
230
|
+
const openName = tag.openName.element;
|
|
231
|
+
|
|
232
|
+
if (isIdentifier(openName)) {
|
|
233
|
+
const tagName = openName.simpleName;
|
|
234
|
+
// Check if tagName matches our component or is an alias for it
|
|
235
|
+
return tagName === componentName ||
|
|
236
|
+
this.componentAliases.get(tagName) === componentName;
|
|
237
|
+
} else if (openName.kind === J.Kind.FieldAccess) {
|
|
238
|
+
const fieldAccess = openName as J.FieldAccess;
|
|
239
|
+
const nameIdent = fieldAccess.name.element;
|
|
240
|
+
if (isIdentifier(nameIdent)) {
|
|
241
|
+
return nameIdent.simpleName === componentName;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
private getReplacementValue(value: J): J | null {
|
|
249
|
+
// Only handle string literals (quoted values)
|
|
250
|
+
if (value.kind === J.Kind.Literal) {
|
|
251
|
+
const literal = value as J.Literal;
|
|
252
|
+
const literalValue = literal.value;
|
|
253
|
+
if (typeof literalValue === 'string') {
|
|
254
|
+
const replacement = matcher(literalValue);
|
|
255
|
+
if (replacement !== null) {
|
|
256
|
+
return create(literal, draft => {
|
|
257
|
+
draft.value = replacement;
|
|
258
|
+
draft.valueSource = `"${replacement}"`;
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
}();
|
|
267
|
+
}
|
|
268
|
+
}
|