@openrewrite/recipes-react 0.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (251) hide show
  1. package/dist/index.d.ts +4 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +130 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/migration/change-component-prop-value.d.ts +20 -0
  6. package/dist/migration/change-component-prop-value.d.ts.map +1 -0
  7. package/dist/migration/change-component-prop-value.js +217 -0
  8. package/dist/migration/change-component-prop-value.js.map +1 -0
  9. package/dist/react-native/view-prop-types.d.ts +8 -0
  10. package/dist/react-native/view-prop-types.d.ts.map +1 -0
  11. package/dist/react-native/view-prop-types.js +65 -0
  12. package/dist/react-native/view-prop-types.js.map +1 -0
  13. package/dist/react16/error-boundaries.d.ts +8 -0
  14. package/dist/react16/error-boundaries.d.ts.map +1 -0
  15. package/dist/react16/error-boundaries.js +42 -0
  16. package/dist/react16/error-boundaries.js.map +1 -0
  17. package/dist/react16/find-dom-node.d.ts +8 -0
  18. package/dist/react16/find-dom-node.d.ts.map +1 -0
  19. package/dist/react16/find-dom-node.js +48 -0
  20. package/dist/react16/find-dom-node.js.map +1 -0
  21. package/dist/react16/react-dom-factories.d.ts +8 -0
  22. package/dist/react16/react-dom-factories.d.ts.map +1 -0
  23. package/dist/react16/react-dom-factories.js +72 -0
  24. package/dist/react16/react-dom-factories.js.map +1 -0
  25. package/dist/react16/react-prop-types.d.ts +8 -0
  26. package/dist/react16/react-prop-types.d.ts.map +1 -0
  27. package/dist/react16/react-prop-types.js +69 -0
  28. package/dist/react16/react-prop-types.js.map +1 -0
  29. package/dist/react16/react-to-react-dom.d.ts +8 -0
  30. package/dist/react16/react-to-react-dom.d.ts.map +1 -0
  31. package/dist/react16/react-to-react-dom.js +97 -0
  32. package/dist/react16/react-to-react-dom.js.map +1 -0
  33. package/dist/react16/replace-create-factory.d.ts +8 -0
  34. package/dist/react16/replace-create-factory.d.ts.map +1 -0
  35. package/dist/react16/replace-create-factory.js +69 -0
  36. package/dist/react16/replace-create-factory.js.map +1 -0
  37. package/dist/react16/upgrade-to-react-16.d.ts +8 -0
  38. package/dist/react16/upgrade-to-react-16.d.ts.map +1 -0
  39. package/dist/react16/upgrade-to-react-16.js +41 -0
  40. package/dist/react16/upgrade-to-react-16.js.map +1 -0
  41. package/dist/react17/remove-event-persist.d.ts +8 -0
  42. package/dist/react17/remove-event-persist.d.ts.map +1 -0
  43. package/dist/react17/remove-event-persist.js +114 -0
  44. package/dist/react17/remove-event-persist.js.map +1 -0
  45. package/dist/react17/rename-unsafe-lifecycles.d.ts +8 -0
  46. package/dist/react17/rename-unsafe-lifecycles.d.ts.map +1 -0
  47. package/dist/react17/rename-unsafe-lifecycles.js +48 -0
  48. package/dist/react17/rename-unsafe-lifecycles.js.map +1 -0
  49. package/dist/react17/update-react-imports.d.ts +8 -0
  50. package/dist/react17/update-react-imports.d.ts.map +1 -0
  51. package/dist/react17/update-react-imports.js +40 -0
  52. package/dist/react17/update-react-imports.js.map +1 -0
  53. package/dist/react17/upgrade-to-react-17.d.ts +8 -0
  54. package/dist/react17/upgrade-to-react-17.d.ts.map +1 -0
  55. package/dist/react17/upgrade-to-react-17.js +37 -0
  56. package/dist/react17/upgrade-to-react-17.js.map +1 -0
  57. package/dist/react18/remove-unstable-batched-updates.d.ts +8 -0
  58. package/dist/react18/remove-unstable-batched-updates.d.ts.map +1 -0
  59. package/dist/react18/remove-unstable-batched-updates.js +170 -0
  60. package/dist/react18/remove-unstable-batched-updates.js.map +1 -0
  61. package/dist/react18/replace-reactdom-render.d.ts +8 -0
  62. package/dist/react18/replace-reactdom-render.d.ts.map +1 -0
  63. package/dist/react18/replace-reactdom-render.js +55 -0
  64. package/dist/react18/replace-reactdom-render.js.map +1 -0
  65. package/dist/react18/replace-render-callback.d.ts +8 -0
  66. package/dist/react18/replace-render-callback.d.ts.map +1 -0
  67. package/dist/react18/replace-render-callback.js +60 -0
  68. package/dist/react18/replace-render-callback.js.map +1 -0
  69. package/dist/react18/replace-unmount-component-at-node.d.ts +8 -0
  70. package/dist/react18/replace-unmount-component-at-node.d.ts.map +1 -0
  71. package/dist/react18/replace-unmount-component-at-node.js +54 -0
  72. package/dist/react18/replace-unmount-component-at-node.js.map +1 -0
  73. package/dist/react18/upgrade-to-react-18.d.ts +8 -0
  74. package/dist/react18/upgrade-to-react-18.d.ts.map +1 -0
  75. package/dist/react18/upgrade-to-react-18.js +39 -0
  76. package/dist/react18/upgrade-to-react-18.js.map +1 -0
  77. package/dist/react19/deprecated-react-types.d.ts +8 -0
  78. package/dist/react19/deprecated-react-types.d.ts.map +1 -0
  79. package/dist/react19/deprecated-react-types.js +135 -0
  80. package/dist/react19/deprecated-react-types.js.map +1 -0
  81. package/dist/react19/find-context-consumer.d.ts +9 -0
  82. package/dist/react19/find-context-consumer.d.ts.map +1 -0
  83. package/dist/react19/find-context-consumer.js +128 -0
  84. package/dist/react19/find-context-consumer.js.map +1 -0
  85. package/dist/react19/find-deprecated-reactdom-apis.d.ts +9 -0
  86. package/dist/react19/find-deprecated-reactdom-apis.d.ts.map +1 -0
  87. package/dist/react19/find-deprecated-reactdom-apis.js +132 -0
  88. package/dist/react19/find-deprecated-reactdom-apis.js.map +1 -0
  89. package/dist/react19/find-element-ref.d.ts +9 -0
  90. package/dist/react19/find-element-ref.d.ts.map +1 -0
  91. package/dist/react19/find-element-ref.js +88 -0
  92. package/dist/react19/find-element-ref.js.map +1 -0
  93. package/dist/react19/find-legacy-context-api.d.ts +9 -0
  94. package/dist/react19/find-legacy-context-api.d.ts.map +1 -0
  95. package/dist/react19/find-legacy-context-api.js +163 -0
  96. package/dist/react19/find-legacy-context-api.js.map +1 -0
  97. package/dist/react19/no-implicit-ref-callback-return.d.ts +8 -0
  98. package/dist/react19/no-implicit-ref-callback-return.d.ts.map +1 -0
  99. package/dist/react19/no-implicit-ref-callback-return.js +107 -0
  100. package/dist/react19/no-implicit-ref-callback-return.js.map +1 -0
  101. package/dist/react19/remove-context-provider.d.ts +8 -0
  102. package/dist/react19/remove-context-provider.d.ts.map +1 -0
  103. package/dist/react19/remove-context-provider.js +59 -0
  104. package/dist/react19/remove-context-provider.js.map +1 -0
  105. package/dist/react19/remove-forward-ref.d.ts +8 -0
  106. package/dist/react19/remove-forward-ref.d.ts.map +1 -0
  107. package/dist/react19/remove-forward-ref.js +73 -0
  108. package/dist/react19/remove-forward-ref.js.map +1 -0
  109. package/dist/react19/remove-prop-types.d.ts +8 -0
  110. package/dist/react19/remove-prop-types.d.ts.map +1 -0
  111. package/dist/react19/remove-prop-types.js +76 -0
  112. package/dist/react19/remove-prop-types.js.map +1 -0
  113. package/dist/react19/remove-react-fc.d.ts +8 -0
  114. package/dist/react19/remove-react-fc.d.ts.map +1 -0
  115. package/dist/react19/remove-react-fc.js +149 -0
  116. package/dist/react19/remove-react-fc.js.map +1 -0
  117. package/dist/react19/replace-act-import.d.ts +9 -0
  118. package/dist/react19/replace-act-import.d.ts.map +1 -0
  119. package/dist/react19/replace-act-import.js +34 -0
  120. package/dist/react19/replace-act-import.js.map +1 -0
  121. package/dist/react19/replace-default-props.d.ts +8 -0
  122. package/dist/react19/replace-default-props.d.ts.map +1 -0
  123. package/dist/react19/replace-default-props.js +195 -0
  124. package/dist/react19/replace-default-props.js.map +1 -0
  125. package/dist/react19/replace-react-shallow-renderer.d.ts +8 -0
  126. package/dist/react19/replace-react-shallow-renderer.d.ts.map +1 -0
  127. package/dist/react19/replace-react-shallow-renderer.js +69 -0
  128. package/dist/react19/replace-react-shallow-renderer.js.map +1 -0
  129. package/dist/react19/replace-reactdom-hydrate.d.ts +8 -0
  130. package/dist/react19/replace-reactdom-hydrate.d.ts.map +1 -0
  131. package/dist/react19/replace-reactdom-hydrate.js +55 -0
  132. package/dist/react19/replace-reactdom-hydrate.js.map +1 -0
  133. package/dist/react19/replace-string-ref.d.ts +8 -0
  134. package/dist/react19/replace-string-ref.d.ts.map +1 -0
  135. package/dist/react19/replace-string-ref.js +75 -0
  136. package/dist/react19/replace-string-ref.js.map +1 -0
  137. package/dist/react19/replace-use-form-state.d.ts +8 -0
  138. package/dist/react19/replace-use-form-state.d.ts.map +1 -0
  139. package/dist/react19/replace-use-form-state.js +54 -0
  140. package/dist/react19/replace-use-form-state.js.map +1 -0
  141. package/dist/react19/upgrade-to-react-19.d.ts +8 -0
  142. package/dist/react19/upgrade-to-react-19.d.ts.map +1 -0
  143. package/dist/react19/upgrade-to-react-19.js +59 -0
  144. package/dist/react19/upgrade-to-react-19.js.map +1 -0
  145. package/dist/react19/use-context-hook.d.ts +8 -0
  146. package/dist/react19/use-context-hook.d.ts.map +1 -0
  147. package/dist/react19/use-context-hook.js +54 -0
  148. package/dist/react19/use-context-hook.js.map +1 -0
  149. package/dist/react19/use-ref-required-initial.d.ts +8 -0
  150. package/dist/react19/use-ref-required-initial.d.ts.map +1 -0
  151. package/dist/react19/use-ref-required-initial.js +74 -0
  152. package/dist/react19/use-ref-required-initial.js.map +1 -0
  153. package/dist/refactoring/class-to-functional.d.ts +8 -0
  154. package/dist/refactoring/class-to-functional.d.ts.map +1 -0
  155. package/dist/refactoring/class-to-functional.js +205 -0
  156. package/dist/refactoring/class-to-functional.js.map +1 -0
  157. package/dist/refactoring/create-class-to-es6.d.ts +8 -0
  158. package/dist/refactoring/create-class-to-es6.d.ts.map +1 -0
  159. package/dist/refactoring/create-class-to-es6.js +289 -0
  160. package/dist/refactoring/create-class-to-es6.js.map +1 -0
  161. package/dist/refactoring/create-element-to-jsx.d.ts +8 -0
  162. package/dist/refactoring/create-element-to-jsx.d.ts.map +1 -0
  163. package/dist/refactoring/create-element-to-jsx.js +167 -0
  164. package/dist/refactoring/create-element-to-jsx.js.map +1 -0
  165. package/dist/refactoring/manual-bind-to-arrow.d.ts +8 -0
  166. package/dist/refactoring/manual-bind-to-arrow.d.ts.map +1 -0
  167. package/dist/refactoring/manual-bind-to-arrow.js +134 -0
  168. package/dist/refactoring/manual-bind-to-arrow.js.map +1 -0
  169. package/dist/refactoring/pure-render-mixin.d.ts +8 -0
  170. package/dist/refactoring/pure-render-mixin.d.ts.map +1 -0
  171. package/dist/refactoring/pure-render-mixin.js +253 -0
  172. package/dist/refactoring/pure-render-mixin.js.map +1 -0
  173. package/dist/refactoring/sort-comp.d.ts +8 -0
  174. package/dist/refactoring/sort-comp.d.ts.map +1 -0
  175. package/dist/refactoring/sort-comp.js +128 -0
  176. package/dist/refactoring/sort-comp.js.map +1 -0
  177. package/dist/search/find-hook-usage.d.ts +9 -0
  178. package/dist/search/find-hook-usage.d.ts.map +1 -0
  179. package/dist/search/find-hook-usage.js +262 -0
  180. package/dist/search/find-hook-usage.js.map +1 -0
  181. package/dist/search/find-prop-usage.d.ts +15 -0
  182. package/dist/search/find-prop-usage.d.ts.map +1 -0
  183. package/dist/search/find-prop-usage.js +177 -0
  184. package/dist/search/find-prop-usage.js.map +1 -0
  185. package/dist/search/find-react-component.d.ts +15 -0
  186. package/dist/search/find-react-component.d.ts.map +1 -0
  187. package/dist/search/find-react-component.js +260 -0
  188. package/dist/search/find-react-component.js.map +1 -0
  189. package/dist/search/find-server-rendering-usage.d.ts +9 -0
  190. package/dist/search/find-server-rendering-usage.d.ts.map +1 -0
  191. package/dist/search/find-server-rendering-usage.js +131 -0
  192. package/dist/search/find-server-rendering-usage.js.map +1 -0
  193. package/dist/simplify-object-pattern-property.d.ts +8 -0
  194. package/dist/simplify-object-pattern-property.d.ts.map +1 -0
  195. package/dist/simplify-object-pattern-property.js +59 -0
  196. package/dist/simplify-object-pattern-property.js.map +1 -0
  197. package/dist/simplify-react-imports.d.ts +8 -0
  198. package/dist/simplify-react-imports.d.ts.map +1 -0
  199. package/dist/simplify-react-imports.js +199 -0
  200. package/dist/simplify-react-imports.js.map +1 -0
  201. package/package.json +39 -0
  202. package/src/index.ts +149 -0
  203. package/src/migration/change-component-prop-value.ts +268 -0
  204. package/src/react-native/view-prop-types.ts +63 -0
  205. package/src/react16/error-boundaries.ts +46 -0
  206. package/src/react16/find-dom-node.ts +55 -0
  207. package/src/react16/react-dom-factories.ts +99 -0
  208. package/src/react16/react-prop-types.ts +71 -0
  209. package/src/react16/react-to-react-dom.ts +104 -0
  210. package/src/react16/replace-create-factory.ts +96 -0
  211. package/src/react16/upgrade-to-react-16.ts +37 -0
  212. package/src/react17/remove-event-persist.ts +121 -0
  213. package/src/react17/rename-unsafe-lifecycles.ts +57 -0
  214. package/src/react17/update-react-imports.ts +50 -0
  215. package/src/react17/upgrade-to-react-17.ts +30 -0
  216. package/src/react18/remove-unstable-batched-updates.ts +192 -0
  217. package/src/react18/replace-reactdom-render.ts +68 -0
  218. package/src/react18/replace-render-callback.ts +66 -0
  219. package/src/react18/replace-unmount-component-at-node.ts +66 -0
  220. package/src/react18/upgrade-to-react-18.ts +33 -0
  221. package/src/react19/deprecated-react-types.ts +120 -0
  222. package/src/react19/find-context-consumer.ts +127 -0
  223. package/src/react19/find-deprecated-reactdom-apis.ts +125 -0
  224. package/src/react19/find-element-ref.ts +86 -0
  225. package/src/react19/find-legacy-context-api.ts +157 -0
  226. package/src/react19/no-implicit-ref-callback-return.ts +123 -0
  227. package/src/react19/remove-context-provider.ts +87 -0
  228. package/src/react19/remove-forward-ref.ts +69 -0
  229. package/src/react19/remove-prop-types.ts +86 -0
  230. package/src/react19/remove-react-fc.ts +247 -0
  231. package/src/react19/replace-act-import.ts +36 -0
  232. package/src/react19/replace-default-props.ts +220 -0
  233. package/src/react19/replace-react-shallow-renderer.ts +75 -0
  234. package/src/react19/replace-reactdom-hydrate.ts +67 -0
  235. package/src/react19/replace-string-ref.ts +89 -0
  236. package/src/react19/replace-use-form-state.ts +66 -0
  237. package/src/react19/upgrade-to-react-19.ts +66 -0
  238. package/src/react19/use-context-hook.ts +67 -0
  239. package/src/react19/use-ref-required-initial.ts +75 -0
  240. package/src/refactoring/class-to-functional.ts +229 -0
  241. package/src/refactoring/create-class-to-es6.ts +309 -0
  242. package/src/refactoring/create-element-to-jsx.ts +200 -0
  243. package/src/refactoring/manual-bind-to-arrow.ts +139 -0
  244. package/src/refactoring/pure-render-mixin.ts +346 -0
  245. package/src/refactoring/sort-comp.ts +135 -0
  246. package/src/search/find-hook-usage.ts +226 -0
  247. package/src/search/find-prop-usage.ts +176 -0
  248. package/src/search/find-react-component.ts +254 -0
  249. package/src/search/find-server-rendering-usage.ts +120 -0
  250. package/src/simplify-object-pattern-property.ts +71 -0
  251. package/src/simplify-react-imports.ts +241 -0
@@ -0,0 +1,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
+ }