@samitouri / QOS-React-2 / commits / 20004e94d3

Add findDOMNode transform

cpojer committed Mar 25, 2015 at 01:29 UTC 20004e94d399541da70d08fd12b64dafb498ebce
5 files changed +217
npm-react-codemod/README.md
+11
@@ -11,6 +11,17 @@ APIs.
11 * Use the `-d` option for a dry-run and use `-p` to print the output
12 for comparison
13
14 +### Included Scripts
15 +
16 +`findDOMNode.js` updates `this.getDOMNode()` or `this.refs.foo.getDOMNode()`
17 +calls inside of `React.createClass` components to `React.findDOMNode(foo)`. Note
18 +that it will only look at code inside of `React.createClass` calls and only
19 +update calls on the component instance or its refs. You can use this script to
20 +update most calls to `getDOMNode` and then manually go through the remaining
21 +calls.
22 +
23 + * `react-codemod findDOMNode <file>`
24 +
25 ### Recast Options
26
27 Options to [recast](https://github.com/benjamn/recast)'s printer can be provided
npm-react-codemod/test/__tests__/transform-tests.js
+3
@@ -34,6 +34,9 @@ function test(transformName, testFileName, options) {
34
35 describe('Transform Tests', () => {
36
37 + it('transforms the "findDOMNode" tests correctly', () => {
38 + test('findDOMNode', 'findDOMNode-test');
39 + });
40
41
42 });
npm-react-codemod/test/findDOMNode-test.js new
+34
@@ -0,0 +1,34 @@
1 +'use strict';
2 +
3 +var React = require('React');
4 +
5 +var Composer = React.createClass({
6 + componentWillReceiveProps: function(nextProps) {
7 + this.getDOMNode();
8 + return foo(this.refs.input.getDOMNode());
9 + },
10 +
11 + foo: function() {
12 + var ref = 'foo';
13 + var element = this.refs[ref];
14 + var domNode = element.getDOMNode();
15 + },
16 +
17 + bar: function() {
18 + var thing = this.refs.foo;
19 + thing.getDOMNode();
20 + },
21 +
22 + foobar: function() {
23 + passThisOn(this.refs.main.refs.list.getDOMNode());
24 + }
25 +});
26 +
27 +var SomeDialog = React.createClass({
28 + render: function() {
29 + call(this.refs.SomeThing);
30 + return (
31 + <div />
32 + );
33 + }
34 +});
npm-react-codemod/test/findDOMNode-test.output.js new
+34
@@ -0,0 +1,34 @@
1 +'use strict';
2 +
3 +var React = require('React');
4 +
5 +var Composer = React.createClass({
6 + componentWillReceiveProps: function(nextProps) {
7 + React.findDOMNode(this);
8 + return foo(React.findDOMNode(this.refs.input));
9 + },
10 +
11 + foo: function() {
12 + var ref = 'foo';
13 + var element = this.refs[ref];
14 + var domNode = React.findDOMNode(element);
15 + },
16 +
17 + bar: function() {
18 + var thing = this.refs.foo;
19 + React.findDOMNode(thing);
20 + },
21 +
22 + foobar: function() {
23 + passThisOn(React.findDOMNode(this.refs.main.refs.list));
24 + }
25 +});
26 +
27 +var SomeDialog = React.createClass({
28 + render: function() {
29 + call(this.refs.SomeThing);
30 + return (
31 + <div />
32 + );
33 + }
34 +});
npm-react-codemod/transforms/findDOMNode.js new
+135
@@ -0,0 +1,135 @@
1 +/*eslint-disable no-comma-dangle*/
2 +
3 +'use strict';
4 +
5 +function getDOMNodeToFindDOMNode(file, api, options) {
6 + const j = api.jscodeshift;
7 +
8 + require('./utils/array-polyfills');
9 + const ReactUtils = require('./utils/ReactUtils')(j);
10 +
11 + const printOptions = options.printOptions || {quote: 'single'};
12 + const root = j(file.source);
13 +
14 + const createReactFindDOMNodeCall = arg => j.callExpression(
15 + j.memberExpression(
16 + j.identifier('React'),
17 + j.identifier('findDOMNode'),
18 + false
19 + ),
20 + [arg]
21 + );
22 +
23 + const updateRefCall = (path, refName) => {
24 + j(path)
25 + .find(j.CallExpression, {
26 + callee: {
27 + object: {
28 + type: 'Identifier',
29 + name: refName,
30 + },
31 + property: {
32 + type: 'Identifier',
33 + name: 'getDOMNode',
34 + },
35 + },
36 + })
37 + .forEach(callPath => j(callPath).replaceWith(
38 + createReactFindDOMNodeCall(j.identifier(refName))
39 + ));
40 + };
41 +
42 + const updateToFindDOMNode = classPath => {
43 + var sum = 0;
44 +
45 + // this.getDOMNode()
46 + sum += j(classPath)
47 + .find(j.CallExpression, {
48 + callee: {
49 + object: {
50 + type: 'ThisExpression',
51 + },
52 + property: {
53 + type: 'Identifier',
54 + name: 'getDOMNode',
55 + },
56 + },
57 + })
58 + .forEach(path => j(path).replaceWith(
59 + createReactFindDOMNodeCall(j.thisExpression())
60 + ))
61 + .size();
62 +
63 + // this.refs.xxx.getDOMNode() or this.refs.xxx.refs.yyy.getDOMNode()
64 + sum += j(classPath)
65 + .find(j.MemberExpression, {
66 + object: {
67 + type: 'MemberExpression',
68 + object: {
69 + type: 'MemberExpression',
70 + object: {
71 + type: 'ThisExpression',
72 + },
73 + property: {
74 + type: 'Identifier',
75 + name: 'refs',
76 + },
77 + },
78 + },
79 + })
80 + .closest(j.CallExpression)
81 + .filter(path => (
82 + path.value.callee.property &&
83 + path.value.callee.property.type === 'Identifier' &&
84 + path.value.callee.property.name === 'getDOMNode'
85 + ))
86 + .forEach(path => j(path).replaceWith(
87 + createReactFindDOMNodeCall(path.value.callee.object)
88 + ))
89 + .size();
90 +
91 + // someVariable.getDOMNode() wherre `someVariable = this.refs.xxx`
92 + sum += j(classPath)
93 + .findVariableDeclarators()
94 + .filter(path => {
95 + const init = path.value.init;
96 + const value = init && init.object;
97 + return (
98 + value &&
99 + value.type === 'MemberExpression' &&
100 + value.object &&
101 + value.object.type === 'ThisExpression' &&
102 + value.property &&
103 + value.property.type === 'Identifier' &&
104 + value.property.name === 'refs' &&
105 + init.property &&
106 + init.property.type === 'Identifier'
107 + );
108 + })
109 + .forEach(path => j(path)
110 + .closest(j.FunctionExpression)
111 + .forEach(fnPath => updateRefCall(fnPath, path.value.id.name))
112 + )
113 + .size();
114 +
115 + return sum > 0;
116 + };
117 +
118 + if (
119 + options['no-explicit-require'] ||
120 + ReactUtils.hasReact(root)
121 + ) {
122 + const didTransform = ReactUtils
123 + .findReactCreateClass(root)
124 + .filter(updateToFindDOMNode)
125 + .size() > 0;
126 +
127 + if (didTransform) {
128 + return root.toSource(printOptions) + '\n';
129 + }
130 + }
131 +
132 + return null;
133 +}
134 +
135 +module.exports = getDOMNodeToFindDOMNode;