Add findDOMNode transform

This commit is contained in:
cpojer
2015-03-25 01:29:48 -07:00
parent 328274bbba
commit 20004e94d3
5 changed files with 217 additions and 0 deletions
+11
View File
@@ -11,6 +11,17 @@ APIs.
* Use the `-d` option for a dry-run and use `-p` to print the output
for comparison
### Included Scripts
`findDOMNode.js` updates `this.getDOMNode()` or `this.refs.foo.getDOMNode()`
calls inside of `React.createClass` components to `React.findDOMNode(foo)`. Note
that it will only look at code inside of `React.createClass` calls and only
update calls on the component instance or its refs. You can use this script to
update most calls to `getDOMNode` and then manually go through the remaining
calls.
* `react-codemod findDOMNode <file>`
### Recast Options
Options to [recast](https://github.com/benjamn/recast)'s printer can be provided
@@ -34,6 +34,9 @@ function test(transformName, testFileName, options) {
describe('Transform Tests', () => {
it('transforms the "findDOMNode" tests correctly', () => {
test('findDOMNode', 'findDOMNode-test');
});
});
@@ -0,0 +1,34 @@
'use strict';
var React = require('React');
var Composer = React.createClass({
componentWillReceiveProps: function(nextProps) {
this.getDOMNode();
return foo(this.refs.input.getDOMNode());
},
foo: function() {
var ref = 'foo';
var element = this.refs[ref];
var domNode = element.getDOMNode();
},
bar: function() {
var thing = this.refs.foo;
thing.getDOMNode();
},
foobar: function() {
passThisOn(this.refs.main.refs.list.getDOMNode());
}
});
var SomeDialog = React.createClass({
render: function() {
call(this.refs.SomeThing);
return (
<div />
);
}
});
@@ -0,0 +1,34 @@
'use strict';
var React = require('React');
var Composer = React.createClass({
componentWillReceiveProps: function(nextProps) {
React.findDOMNode(this);
return foo(React.findDOMNode(this.refs.input));
},
foo: function() {
var ref = 'foo';
var element = this.refs[ref];
var domNode = React.findDOMNode(element);
},
bar: function() {
var thing = this.refs.foo;
React.findDOMNode(thing);
},
foobar: function() {
passThisOn(React.findDOMNode(this.refs.main.refs.list));
}
});
var SomeDialog = React.createClass({
render: function() {
call(this.refs.SomeThing);
return (
<div />
);
}
});
+135
View File
@@ -0,0 +1,135 @@
/*eslint-disable no-comma-dangle*/
'use strict';
function getDOMNodeToFindDOMNode(file, api, options) {
const j = api.jscodeshift;
require('./utils/array-polyfills');
const ReactUtils = require('./utils/ReactUtils')(j);
const printOptions = options.printOptions || {quote: 'single'};
const root = j(file.source);
const createReactFindDOMNodeCall = arg => j.callExpression(
j.memberExpression(
j.identifier('React'),
j.identifier('findDOMNode'),
false
),
[arg]
);
const updateRefCall = (path, refName) => {
j(path)
.find(j.CallExpression, {
callee: {
object: {
type: 'Identifier',
name: refName,
},
property: {
type: 'Identifier',
name: 'getDOMNode',
},
},
})
.forEach(callPath => j(callPath).replaceWith(
createReactFindDOMNodeCall(j.identifier(refName))
));
};
const updateToFindDOMNode = classPath => {
var sum = 0;
// this.getDOMNode()
sum += j(classPath)
.find(j.CallExpression, {
callee: {
object: {
type: 'ThisExpression',
},
property: {
type: 'Identifier',
name: 'getDOMNode',
},
},
})
.forEach(path => j(path).replaceWith(
createReactFindDOMNodeCall(j.thisExpression())
))
.size();
// this.refs.xxx.getDOMNode() or this.refs.xxx.refs.yyy.getDOMNode()
sum += j(classPath)
.find(j.MemberExpression, {
object: {
type: 'MemberExpression',
object: {
type: 'MemberExpression',
object: {
type: 'ThisExpression',
},
property: {
type: 'Identifier',
name: 'refs',
},
},
},
})
.closest(j.CallExpression)
.filter(path => (
path.value.callee.property &&
path.value.callee.property.type === 'Identifier' &&
path.value.callee.property.name === 'getDOMNode'
))
.forEach(path => j(path).replaceWith(
createReactFindDOMNodeCall(path.value.callee.object)
))
.size();
// someVariable.getDOMNode() wherre `someVariable = this.refs.xxx`
sum += j(classPath)
.findVariableDeclarators()
.filter(path => {
const init = path.value.init;
const value = init && init.object;
return (
value &&
value.type === 'MemberExpression' &&
value.object &&
value.object.type === 'ThisExpression' &&
value.property &&
value.property.type === 'Identifier' &&
value.property.name === 'refs' &&
init.property &&
init.property.type === 'Identifier'
);
})
.forEach(path => j(path)
.closest(j.FunctionExpression)
.forEach(fnPath => updateRefCall(fnPath, path.value.id.name))
)
.size();
return sum > 0;
};
if (
options['no-explicit-require'] ||
ReactUtils.hasReact(root)
) {
const didTransform = ReactUtils
.findReactCreateClass(root)
.filter(updateToFindDOMNode)
.size() > 0;
if (didTransform) {
return root.toSource(printOptions) + '\n';
}
}
return null;
}
module.exports = getDOMNodeToFindDOMNode;