@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,63 @@
|
|
|
1
|
+
import {ExecutionContext, Recipe, TreeVisitor} from "@openrewrite/rewrite";
|
|
2
|
+
import {JavaScriptVisitor, maybeAddImport, maybeRemoveImport} from "@openrewrite/rewrite/javascript";
|
|
3
|
+
import {J} from "@openrewrite/rewrite/java";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Replaces `View.propTypes` with `ViewPropTypes` from the `deprecated-react-native-prop-types` package.
|
|
7
|
+
*
|
|
8
|
+
* React Native removed `View.propTypes` in newer versions. This recipe
|
|
9
|
+
* replaces references to `View.propTypes` with the `ViewPropTypes` export.
|
|
10
|
+
*
|
|
11
|
+
* Before:
|
|
12
|
+
* ```tsx
|
|
13
|
+
* import { View } from 'react-native';
|
|
14
|
+
* const styles = View.propTypes;
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* After:
|
|
18
|
+
* ```tsx
|
|
19
|
+
* import { ViewPropTypes } from 'deprecated-react-native-prop-types';
|
|
20
|
+
* const styles = ViewPropTypes;
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @see https://github.com/reactjs/react-codemod#reactnative-view-proptypes
|
|
24
|
+
*/
|
|
25
|
+
export class ViewPropTypes extends Recipe {
|
|
26
|
+
readonly name = "org.openrewrite.react.native.view-prop-types";
|
|
27
|
+
readonly displayName: string = "Replace `View.propTypes` with `ViewPropTypes`";
|
|
28
|
+
readonly description: string = "Migrates deprecated `View.propTypes` references to `ViewPropTypes` from `deprecated-react-native-prop-types`.";
|
|
29
|
+
|
|
30
|
+
async editor(): Promise<TreeVisitor<any, ExecutionContext>> {
|
|
31
|
+
return new class extends JavaScriptVisitor<ExecutionContext> {
|
|
32
|
+
private transformed = false;
|
|
33
|
+
|
|
34
|
+
override async visitJsCompilationUnit(cu: any, ctx: ExecutionContext): Promise<J | undefined> {
|
|
35
|
+
this.transformed = false;
|
|
36
|
+
let result = await super.visitJsCompilationUnit(cu, ctx);
|
|
37
|
+
if (this.transformed) {
|
|
38
|
+
maybeAddImport(this, {module: "deprecated-react-native-prop-types", member: "ViewPropTypes", onlyIfReferenced: false});
|
|
39
|
+
maybeRemoveImport(this, "react-native", "View");
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
override async visitFieldAccess(fieldAccess: J.FieldAccess, ctx: ExecutionContext): Promise<J | undefined> {
|
|
45
|
+
let fa = await super.visitFieldAccess(fieldAccess, ctx) as J.FieldAccess;
|
|
46
|
+
|
|
47
|
+
// Match View.propTypes
|
|
48
|
+
if (fa.target.kind !== J.Kind.Identifier) return fa;
|
|
49
|
+
if ((fa.target as J.Identifier).simpleName !== 'View') return fa;
|
|
50
|
+
if (fa.name.element.simpleName !== 'propTypes') return fa;
|
|
51
|
+
|
|
52
|
+
this.transformed = true;
|
|
53
|
+
|
|
54
|
+
// Replace View.propTypes with just ViewPropTypes
|
|
55
|
+
return {
|
|
56
|
+
...fa.target,
|
|
57
|
+
simpleName: 'ViewPropTypes',
|
|
58
|
+
prefix: fa.prefix
|
|
59
|
+
} as J.Identifier;
|
|
60
|
+
}
|
|
61
|
+
}();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import {ExecutionContext, Recipe, TreeVisitor} from "@openrewrite/rewrite";
|
|
2
|
+
import {JavaScriptVisitor} from "@openrewrite/rewrite/javascript";
|
|
3
|
+
import {J} from "@openrewrite/rewrite/java";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Renames `unstable_handleError` to `componentDidCatch`.
|
|
7
|
+
*
|
|
8
|
+
* React 16 introduced error boundaries with a stable API. This recipe
|
|
9
|
+
* renames the unstable API to the official one.
|
|
10
|
+
*
|
|
11
|
+
* Before:
|
|
12
|
+
* ```tsx
|
|
13
|
+
* class ErrorBoundary extends React.Component {
|
|
14
|
+
* unstable_handleError(error) { ... }
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* After:
|
|
19
|
+
* ```tsx
|
|
20
|
+
* class ErrorBoundary extends React.Component {
|
|
21
|
+
* componentDidCatch(error) { ... }
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export class ErrorBoundaries extends Recipe {
|
|
26
|
+
readonly name = "org.openrewrite.react.16.error-boundaries";
|
|
27
|
+
readonly displayName: string = "Rename `unstable_handleError` to `componentDidCatch`";
|
|
28
|
+
readonly description: string = "Renames the unstable error boundary method to the official `componentDidCatch` API introduced in React 16.";
|
|
29
|
+
|
|
30
|
+
async editor(): Promise<TreeVisitor<any, ExecutionContext>> {
|
|
31
|
+
return new class extends JavaScriptVisitor<ExecutionContext> {
|
|
32
|
+
override async visitIdentifier(ident: J.Identifier, ctx: ExecutionContext): Promise<J | undefined> {
|
|
33
|
+
let id = await super.visitIdentifier(ident, ctx) as J.Identifier;
|
|
34
|
+
|
|
35
|
+
if (id.simpleName === 'unstable_handleError') {
|
|
36
|
+
return {
|
|
37
|
+
...id,
|
|
38
|
+
simpleName: 'componentDidCatch'
|
|
39
|
+
} as J.Identifier;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return id;
|
|
43
|
+
}
|
|
44
|
+
}();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import {ExecutionContext, Recipe, TreeVisitor} from "@openrewrite/rewrite";
|
|
2
|
+
import {
|
|
3
|
+
capture,
|
|
4
|
+
JavaScriptVisitor,
|
|
5
|
+
pattern,
|
|
6
|
+
rewrite,
|
|
7
|
+
template
|
|
8
|
+
} from "@openrewrite/rewrite/javascript";
|
|
9
|
+
import {Expression, J} from "@openrewrite/rewrite/java";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Replaces `this.getDOMNode()` with `React.findDOMNode(this)`.
|
|
13
|
+
*
|
|
14
|
+
* In React 0.13+, `getDOMNode()` on component instances was deprecated
|
|
15
|
+
* in favor of `React.findDOMNode()`.
|
|
16
|
+
*
|
|
17
|
+
* Before:
|
|
18
|
+
* ```tsx
|
|
19
|
+
* this.getDOMNode()
|
|
20
|
+
* this.refs.myRef.getDOMNode()
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* After:
|
|
24
|
+
* ```tsx
|
|
25
|
+
* React.findDOMNode(this)
|
|
26
|
+
* React.findDOMNode(this.refs.myRef)
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export class FindDomNode extends Recipe {
|
|
30
|
+
readonly name = "org.openrewrite.react.16.find-dom-node";
|
|
31
|
+
readonly displayName: string = "Replace `getDOMNode()` with `React.findDOMNode()`";
|
|
32
|
+
readonly description: string = "Migrates deprecated `getDOMNode()` calls to `React.findDOMNode()`.";
|
|
33
|
+
|
|
34
|
+
async editor(): Promise<TreeVisitor<any, ExecutionContext>> {
|
|
35
|
+
const target = capture<Expression>();
|
|
36
|
+
|
|
37
|
+
const rule = rewrite(() => ({
|
|
38
|
+
before: pattern`${target}.getDOMNode()`,
|
|
39
|
+
after: template`React.findDOMNode(${target})`
|
|
40
|
+
}));
|
|
41
|
+
|
|
42
|
+
return new class extends JavaScriptVisitor<ExecutionContext> {
|
|
43
|
+
override async visitMethodInvocation(method: J.MethodInvocation, p: ExecutionContext): Promise<J | undefined> {
|
|
44
|
+
let m = await super.visitMethodInvocation(method, p) as J.MethodInvocation;
|
|
45
|
+
|
|
46
|
+
const result = await rule.tryOn(this.cursor, m!);
|
|
47
|
+
if (result) {
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return m;
|
|
52
|
+
}
|
|
53
|
+
}();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import {ExecutionContext, Recipe, TreeVisitor} from "@openrewrite/rewrite";
|
|
2
|
+
import {
|
|
3
|
+
capture,
|
|
4
|
+
JavaScriptVisitor,
|
|
5
|
+
pattern,
|
|
6
|
+
rewrite,
|
|
7
|
+
template
|
|
8
|
+
} from "@openrewrite/rewrite/javascript";
|
|
9
|
+
import {Expression, J} from "@openrewrite/rewrite/java";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Converts `React.DOM.xxx()` factory calls to `React.createElement('xxx', ...)`.
|
|
13
|
+
*
|
|
14
|
+
* React.DOM factories were deprecated in React 15.6 and removed in React 16.
|
|
15
|
+
*
|
|
16
|
+
* Before:
|
|
17
|
+
* ```tsx
|
|
18
|
+
* React.DOM.div({ className: 'foo' }, 'Hello')
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* After:
|
|
22
|
+
* ```tsx
|
|
23
|
+
* React.createElement('div', { className: 'foo' }, 'Hello')
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export class ReactDomFactories extends Recipe {
|
|
27
|
+
readonly name = "org.openrewrite.react.16.react-dom-factories";
|
|
28
|
+
readonly displayName: string = "Replace `React.DOM` factories with `createElement`";
|
|
29
|
+
readonly description: string = "Converts deprecated `React.DOM.xxx()` factory calls to `React.createElement('xxx', ...)`.";
|
|
30
|
+
|
|
31
|
+
async editor(): Promise<TreeVisitor<any, ExecutionContext>> {
|
|
32
|
+
return new class extends JavaScriptVisitor<ExecutionContext> {
|
|
33
|
+
override async visitMethodInvocation(method: J.MethodInvocation, p: ExecutionContext): Promise<J | undefined> {
|
|
34
|
+
let m = await super.visitMethodInvocation(method, p) as J.MethodInvocation;
|
|
35
|
+
|
|
36
|
+
// Match React.DOM.xxx() pattern
|
|
37
|
+
if (!m.select) return m;
|
|
38
|
+
const select = (m.select as any).element ?? m.select;
|
|
39
|
+
if (select.kind !== J.Kind.FieldAccess) return m;
|
|
40
|
+
|
|
41
|
+
const domAccess = select as J.FieldAccess;
|
|
42
|
+
if (domAccess.name.element.simpleName !== 'DOM') return m;
|
|
43
|
+
if (domAccess.target.kind !== J.Kind.Identifier) return m;
|
|
44
|
+
if ((domAccess.target as J.Identifier).simpleName !== 'React') return m;
|
|
45
|
+
|
|
46
|
+
// Get the element name (e.g., 'div', 'span')
|
|
47
|
+
const elementName = m.name.simpleName;
|
|
48
|
+
|
|
49
|
+
// Build React.createElement('elementName', ...args)
|
|
50
|
+
// Replace the select from React.DOM to React
|
|
51
|
+
// Replace the method name from 'div' to 'createElement'
|
|
52
|
+
// Prepend the element name as a string literal to the arguments
|
|
53
|
+
const elementLiteral: J.Literal = {
|
|
54
|
+
kind: J.Kind.Literal,
|
|
55
|
+
id: m.name.id,
|
|
56
|
+
prefix: m.arguments.elements[0]?.element?.prefix ?? {whitespace: '', comments: []},
|
|
57
|
+
markers: m.name.markers,
|
|
58
|
+
value: elementName,
|
|
59
|
+
valueSource: `'${elementName}'`
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// Add a space prefix to the original first arg so it follows the comma naturally
|
|
63
|
+
const originalElements = m.arguments.elements.map((el: any, i: number) => {
|
|
64
|
+
if (i === 0 && el.element) {
|
|
65
|
+
return {
|
|
66
|
+
...el,
|
|
67
|
+
element: {
|
|
68
|
+
...el.element,
|
|
69
|
+
prefix: {whitespace: ' ', comments: []}
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
return el;
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const newArgs = [
|
|
77
|
+
{element: elementLiteral, after: {whitespace: '', comments: []}},
|
|
78
|
+
...originalElements
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
...m,
|
|
83
|
+
select: {
|
|
84
|
+
...(m.select as any),
|
|
85
|
+
element: domAccess.target
|
|
86
|
+
},
|
|
87
|
+
name: {
|
|
88
|
+
...m.name,
|
|
89
|
+
simpleName: 'createElement'
|
|
90
|
+
},
|
|
91
|
+
arguments: {
|
|
92
|
+
...m.arguments,
|
|
93
|
+
elements: newArgs
|
|
94
|
+
}
|
|
95
|
+
} as any as J.MethodInvocation;
|
|
96
|
+
}
|
|
97
|
+
}();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import {ExecutionContext, Recipe, TreeVisitor} from "@openrewrite/rewrite";
|
|
2
|
+
import {JavaScriptVisitor, maybeAddImport, maybeRemoveImport} from "@openrewrite/rewrite/javascript";
|
|
3
|
+
import {J} from "@openrewrite/rewrite/java";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Moves `React.PropTypes` to the separate `prop-types` package.
|
|
7
|
+
*
|
|
8
|
+
* Starting with React 15.5, PropTypes was extracted into its own package.
|
|
9
|
+
*
|
|
10
|
+
* Before:
|
|
11
|
+
* ```tsx
|
|
12
|
+
* import React from 'react';
|
|
13
|
+
* MyComponent.propTypes = {
|
|
14
|
+
* name: React.PropTypes.string
|
|
15
|
+
* };
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* After:
|
|
19
|
+
* ```tsx
|
|
20
|
+
* import React from 'react';
|
|
21
|
+
* import PropTypes from 'prop-types';
|
|
22
|
+
* MyComponent.propTypes = {
|
|
23
|
+
* name: PropTypes.string
|
|
24
|
+
* };
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export class ReactPropTypes extends Recipe {
|
|
28
|
+
readonly name = "org.openrewrite.react.16.react-prop-types";
|
|
29
|
+
readonly displayName: string = "Move `React.PropTypes` to `prop-types` package";
|
|
30
|
+
readonly description: string = "Extracts PropTypes usage from the React namespace to the separate `prop-types` package introduced in React 15.5.";
|
|
31
|
+
|
|
32
|
+
async editor(): Promise<TreeVisitor<any, ExecutionContext>> {
|
|
33
|
+
return new class extends JavaScriptVisitor<ExecutionContext> {
|
|
34
|
+
private transformed = false;
|
|
35
|
+
|
|
36
|
+
override async visitFieldAccess(fieldAccess: J.FieldAccess, ctx: ExecutionContext): Promise<J | undefined> {
|
|
37
|
+
let fa = await super.visitFieldAccess(fieldAccess, ctx) as J.FieldAccess;
|
|
38
|
+
|
|
39
|
+
// Match React.PropTypes
|
|
40
|
+
if (fa.target.kind !== J.Kind.Identifier) {
|
|
41
|
+
return fa;
|
|
42
|
+
}
|
|
43
|
+
const target = fa.target as J.Identifier;
|
|
44
|
+
if (target.simpleName !== 'React') {
|
|
45
|
+
return fa;
|
|
46
|
+
}
|
|
47
|
+
if (fa.name.element.simpleName !== 'PropTypes') {
|
|
48
|
+
return fa;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
this.transformed = true;
|
|
52
|
+
|
|
53
|
+
// Replace React.PropTypes with just PropTypes
|
|
54
|
+
return {
|
|
55
|
+
...fa.name.element,
|
|
56
|
+
prefix: fa.prefix
|
|
57
|
+
} as J.Identifier;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
override async visitJsCompilationUnit(cu: any, ctx: ExecutionContext): Promise<J | undefined> {
|
|
61
|
+
this.transformed = false;
|
|
62
|
+
let result = await super.visitJsCompilationUnit(cu, ctx);
|
|
63
|
+
if (this.transformed) {
|
|
64
|
+
maybeAddImport(this, {module: "prop-types", member: "default", alias: "PropTypes", onlyIfReferenced: false});
|
|
65
|
+
maybeRemoveImport(this, "react", "PropTypes");
|
|
66
|
+
}
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
}();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
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
|
+
const DOM_METHODS = new Set([
|
|
7
|
+
'render',
|
|
8
|
+
'findDOMNode',
|
|
9
|
+
'unmountComponentAtNode',
|
|
10
|
+
'unstable_batchedUpdates',
|
|
11
|
+
'unstable_renderSubtreeIntoContainer',
|
|
12
|
+
]);
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Splits `React.render()` and other DOM methods to `ReactDOM`.
|
|
16
|
+
*
|
|
17
|
+
* In React 0.14+, DOM-specific methods were moved to the `react-dom` package.
|
|
18
|
+
*
|
|
19
|
+
* Before:
|
|
20
|
+
* ```tsx
|
|
21
|
+
* import React from 'react';
|
|
22
|
+
* React.render(<App />, document.getElementById('root'));
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* After:
|
|
26
|
+
* ```tsx
|
|
27
|
+
* import React from 'react';
|
|
28
|
+
* import ReactDOM from 'react-dom';
|
|
29
|
+
* ReactDOM.render(<App />, document.getElementById('root'));
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export class ReactToReactDom extends Recipe {
|
|
33
|
+
readonly name = "org.openrewrite.react.16.react-to-react-dom";
|
|
34
|
+
readonly displayName: string = "Split `React` DOM methods to `ReactDOM`";
|
|
35
|
+
readonly description: string = "Moves DOM-specific methods like `React.render()` and `React.findDOMNode()` to `ReactDOM` from the `react-dom` package.";
|
|
36
|
+
|
|
37
|
+
async editor(): Promise<TreeVisitor<any, ExecutionContext>> {
|
|
38
|
+
return new class extends JavaScriptVisitor<ExecutionContext> {
|
|
39
|
+
private needsReactDOM = false;
|
|
40
|
+
|
|
41
|
+
override async visitJsCompilationUnit(cu: any, ctx: ExecutionContext): Promise<J | undefined> {
|
|
42
|
+
this.needsReactDOM = false;
|
|
43
|
+
let result = await super.visitJsCompilationUnit(cu, ctx);
|
|
44
|
+
if (this.needsReactDOM) {
|
|
45
|
+
maybeAddImport(this, {module: "react-dom", member: "default", alias: "ReactDOM", onlyIfReferenced: false});
|
|
46
|
+
}
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
override async visitFieldAccess(fieldAccess: J.FieldAccess, ctx: ExecutionContext): Promise<J | undefined> {
|
|
51
|
+
let fa = await super.visitFieldAccess(fieldAccess, ctx) as J.FieldAccess;
|
|
52
|
+
|
|
53
|
+
if (fa.target.kind !== J.Kind.Identifier) {
|
|
54
|
+
return fa;
|
|
55
|
+
}
|
|
56
|
+
const target = fa.target as J.Identifier;
|
|
57
|
+
if (target.simpleName !== 'React') {
|
|
58
|
+
return fa;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const methodName = fa.name.element.simpleName;
|
|
62
|
+
if (!DOM_METHODS.has(methodName)) {
|
|
63
|
+
return fa;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
this.needsReactDOM = true;
|
|
67
|
+
|
|
68
|
+
// Replace React with ReactDOM
|
|
69
|
+
return {
|
|
70
|
+
...fa,
|
|
71
|
+
target: {
|
|
72
|
+
...target,
|
|
73
|
+
simpleName: 'ReactDOM'
|
|
74
|
+
} as J.Identifier
|
|
75
|
+
} as any as J.FieldAccess;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
override async visitMethodInvocation(method: J.MethodInvocation, p: ExecutionContext): Promise<J | undefined> {
|
|
79
|
+
let m = await super.visitMethodInvocation(method, p) as J.MethodInvocation;
|
|
80
|
+
|
|
81
|
+
if (!m.select) return m;
|
|
82
|
+
const select = (m.select as any).element ?? m.select;
|
|
83
|
+
if (select.kind !== J.Kind.Identifier) return m;
|
|
84
|
+
if ((select as J.Identifier).simpleName !== 'React') return m;
|
|
85
|
+
|
|
86
|
+
const methodName = m.name.simpleName;
|
|
87
|
+
if (!DOM_METHODS.has(methodName)) return m;
|
|
88
|
+
|
|
89
|
+
this.needsReactDOM = true;
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
...m,
|
|
93
|
+
select: {
|
|
94
|
+
...(m.select as any),
|
|
95
|
+
element: {
|
|
96
|
+
...select,
|
|
97
|
+
simpleName: 'ReactDOM'
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
} as any as J.MethodInvocation;
|
|
101
|
+
}
|
|
102
|
+
}();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import {ExecutionContext, Recipe, TreeVisitor} from "@openrewrite/rewrite";
|
|
2
|
+
import {JavaScriptVisitor, JS} from "@openrewrite/rewrite/javascript";
|
|
3
|
+
import {J} from "@openrewrite/rewrite/java";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Replaces `React.createFactory(type)(props, children)` with
|
|
7
|
+
* `React.createElement(type, props, children)`.
|
|
8
|
+
*
|
|
9
|
+
* `React.createFactory` was deprecated in React 15.6 and removed in React 16.
|
|
10
|
+
* This recipe handles the case where the factory is immediately invoked inline
|
|
11
|
+
* (chained call), transforming it into the equivalent `createElement` call.
|
|
12
|
+
*
|
|
13
|
+
* Before:
|
|
14
|
+
* ```tsx
|
|
15
|
+
* const el = React.createFactory('div')({className: 'foo'}, 'Hello');
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* After:
|
|
19
|
+
* ```tsx
|
|
20
|
+
* const el = React.createElement('div', {className: 'foo'}, 'Hello');
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export class ReplaceCreateFactory extends Recipe {
|
|
24
|
+
readonly name = "org.openrewrite.react.16.replace-create-factory";
|
|
25
|
+
readonly displayName: string = "Replace `React.createFactory` with `React.createElement`";
|
|
26
|
+
readonly description: string = "Replaces `React.createFactory(type)(props, children)` with `React.createElement(type, props, children)`. React.createFactory was deprecated in React 15.6 and removed in React 16.";
|
|
27
|
+
|
|
28
|
+
async editor(): Promise<TreeVisitor<any, ExecutionContext>> {
|
|
29
|
+
return new class extends JavaScriptVisitor<ExecutionContext> {
|
|
30
|
+
override async visitFunctionCall(functionCall: JS.FunctionCall, p: ExecutionContext): Promise<J | undefined> {
|
|
31
|
+
let fc = await super.visitFunctionCall(functionCall, p) as JS.FunctionCall;
|
|
32
|
+
|
|
33
|
+
// The function field is a RightPadded wrapping the callee expression
|
|
34
|
+
if (!fc.function) return fc;
|
|
35
|
+
const callee = (fc.function as any).element ?? fc.function;
|
|
36
|
+
|
|
37
|
+
// Check if the callee is a MethodInvocation (React.createFactory(...))
|
|
38
|
+
if (callee.kind !== J.Kind.MethodInvocation) return fc;
|
|
39
|
+
const innerCall = callee as J.MethodInvocation;
|
|
40
|
+
|
|
41
|
+
// Check if inner call is createFactory
|
|
42
|
+
if (innerCall.name.simpleName !== 'createFactory') return fc;
|
|
43
|
+
|
|
44
|
+
// Require a select (React.createFactory, not bare createFactory)
|
|
45
|
+
if (!innerCall.select) return fc;
|
|
46
|
+
|
|
47
|
+
// Get the type argument from createFactory(type)
|
|
48
|
+
const innerArgs = innerCall.arguments?.elements;
|
|
49
|
+
if (!innerArgs || innerArgs.length !== 1) return fc;
|
|
50
|
+
|
|
51
|
+
const typeArg = innerArgs[0];
|
|
52
|
+
|
|
53
|
+
// Build new argument list: prepend typeArg to outer args
|
|
54
|
+
// Filter out J.Empty placeholders from outer args
|
|
55
|
+
const outerArgs = fc.arguments.elements.filter((el: any) => {
|
|
56
|
+
const element = el.element ?? el;
|
|
57
|
+
return element.kind !== J.Kind.Empty;
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Add a space prefix to the original first outer arg so it follows the comma naturally
|
|
61
|
+
const newOuterArgs = outerArgs.map((el: any, i: number) => {
|
|
62
|
+
if (i === 0 && el.element) {
|
|
63
|
+
return {
|
|
64
|
+
...el,
|
|
65
|
+
element: {
|
|
66
|
+
...el.element,
|
|
67
|
+
prefix: {whitespace: ' ', comments: []}
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return el;
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const newArgs = outerArgs.length > 0
|
|
75
|
+
? [typeArg, ...newOuterArgs]
|
|
76
|
+
: [typeArg];
|
|
77
|
+
|
|
78
|
+
// Build a MethodInvocation: React.createElement(type, props, children)
|
|
79
|
+
// Preserve the prefix from the outer FunctionCall node
|
|
80
|
+
return {
|
|
81
|
+
...innerCall,
|
|
82
|
+
prefix: (fc as any).prefix,
|
|
83
|
+
select: innerCall.select,
|
|
84
|
+
name: {
|
|
85
|
+
...innerCall.name,
|
|
86
|
+
simpleName: 'createElement'
|
|
87
|
+
},
|
|
88
|
+
arguments: {
|
|
89
|
+
...fc.arguments,
|
|
90
|
+
elements: newArgs
|
|
91
|
+
}
|
|
92
|
+
} as any as J.MethodInvocation;
|
|
93
|
+
}
|
|
94
|
+
}();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import {Recipe} from "@openrewrite/rewrite";
|
|
2
|
+
import {ErrorBoundaries} from "./error-boundaries";
|
|
3
|
+
import {FindDomNode} from "./find-dom-node";
|
|
4
|
+
import {ReactPropTypes} from "./react-prop-types";
|
|
5
|
+
import {ReactDomFactories} from "./react-dom-factories";
|
|
6
|
+
import {ReactToReactDom} from "./react-to-react-dom";
|
|
7
|
+
import {ReplaceCreateFactory} from "./replace-create-factory";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Composite recipe that applies all React 16 migration recipes.
|
|
11
|
+
*
|
|
12
|
+
* Changes include:
|
|
13
|
+
* - Move `React.PropTypes` to `prop-types` package
|
|
14
|
+
* - Replace `React.DOM` factories with `createElement`
|
|
15
|
+
* - Split `React` DOM methods to `ReactDOM`
|
|
16
|
+
* - Replace `getDOMNode()` with `React.findDOMNode()`
|
|
17
|
+
* - Rename `unstable_handleError` to `componentDidCatch`
|
|
18
|
+
* - Replace `React.createFactory` with `React.createElement`
|
|
19
|
+
*
|
|
20
|
+
* @see https://reactjs.org/blog/2017/09/26/react-v16.0.html
|
|
21
|
+
*/
|
|
22
|
+
export class UpgradeToReact16 extends Recipe {
|
|
23
|
+
readonly name = "org.openrewrite.react.migrate.upgrade-to-react-16";
|
|
24
|
+
readonly displayName = "Upgrade to React 16";
|
|
25
|
+
readonly description = "Migrate deprecated APIs for React 16 compatibility. Includes PropTypes extraction, ReactDOM split, DOM factory replacement, createFactory replacement, and error boundary API updates.";
|
|
26
|
+
|
|
27
|
+
async recipeList(): Promise<Recipe[]> {
|
|
28
|
+
return [
|
|
29
|
+
new ReactPropTypes(),
|
|
30
|
+
new ReactDomFactories(),
|
|
31
|
+
new ReactToReactDom(),
|
|
32
|
+
new FindDomNode(),
|
|
33
|
+
new ErrorBoundaries(),
|
|
34
|
+
new ReplaceCreateFactory(),
|
|
35
|
+
];
|
|
36
|
+
}
|
|
37
|
+
}
|