2015-03-25 16:27:45 +08:00
|
|
|
|
## react-codemod
|
|
|
|
|
|
|
2015-07-31 06:19:16 +08:00
|
|
|
|
This repository contains a collection of codemod scripts based for use with
|
2015-03-25 16:27:45 +08:00
|
|
|
|
[JSCodeshift](https://github.com/facebook/jscodeshift) that help update React
|
|
|
|
|
|
APIs.
|
|
|
|
|
|
|
|
|
|
|
|
### Setup & Run
|
|
|
|
|
|
|
2015-07-31 06:19:16 +08:00
|
|
|
|
* `npm install -g jscodeshift`
|
|
|
|
|
|
* `git clone https://github.com/facebook/react.git` or download a zip file
|
|
|
|
|
|
from `https://github.com/facebook/react/archive/master.zip`
|
|
|
|
|
|
* `jscodeshift -t <codemod-script> <file>`
|
2015-03-25 16:27:45 +08:00
|
|
|
|
* Use the `-d` option for a dry-run and use `-p` to print the output
|
|
|
|
|
|
for comparison
|
|
|
|
|
|
|
2015-03-25 16:29:48 +08:00
|
|
|
|
### Included Scripts
|
|
|
|
|
|
|
2015-03-26 07:15:07 +08:00
|
|
|
|
`findDOMNode` updates `this.getDOMNode()` or `this.refs.foo.getDOMNode()`
|
2015-03-25 16:29:48 +08:00
|
|
|
|
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.
|
|
|
|
|
|
|
2015-07-31 06:19:16 +08:00
|
|
|
|
* `jscodeshift -t react/packages/react-codemod/transforms/findDOMNode.js <file>`
|
2015-03-25 16:29:48 +08:00
|
|
|
|
|
2015-03-26 07:15:07 +08:00
|
|
|
|
`pure-render-mixin` removes `PureRenderMixin` and inlines
|
2015-08-14 10:08:25 +08:00
|
|
|
|
`shouldComponentUpdate` so that the ES2015 class transform can pick up the React
|
|
|
|
|
|
component and turn it into an ES2015 class. NOTE: This currently only works if you
|
2015-03-25 16:30:23 +08:00
|
|
|
|
are using the master version (>0.13.1) of React as it is using
|
|
|
|
|
|
`React.addons.shallowCompare`
|
|
|
|
|
|
|
2015-07-31 06:19:16 +08:00
|
|
|
|
* `jscodeshift -t react/packages/react-codemod/transforms/pure-render-mixin.js <file>`
|
2015-03-25 16:30:23 +08:00
|
|
|
|
* If `--mixin-name=<name>` is specified it will look for the specified name
|
|
|
|
|
|
instead of `PureRenderMixin`. Note that it is not possible to use a
|
|
|
|
|
|
namespaced name for the mixin. `mixins: [React.addons.PureRenderMixin]` will
|
|
|
|
|
|
not currently work.
|
|
|
|
|
|
|
2015-08-14 10:08:25 +08:00
|
|
|
|
`class` transforms `React.createClass` calls into ES2015 classes.
|
2015-03-25 16:30:35 +08:00
|
|
|
|
|
2015-07-31 06:19:16 +08:00
|
|
|
|
* `jscodeshift -t react/packages/react-codemod/transforms/class.js <file>`
|
2015-03-25 16:30:35 +08:00
|
|
|
|
* If `--no-super-class=true` is specified it will not extend
|
|
|
|
|
|
`React.Component` if `setState` and `forceUpdate` aren't being called in a
|
|
|
|
|
|
class. We do recommend always extending from `React.Component`, especially
|
|
|
|
|
|
if you are using or planning to use [Flow](http://flowtype.org/). Also make
|
|
|
|
|
|
sure you are not calling `setState` anywhere outside of your component.
|
|
|
|
|
|
|
|
|
|
|
|
All scripts take an option `--no-explicit-require=true` if you don't have a
|
|
|
|
|
|
`require('React')` statement in your code files and if you access React as a
|
|
|
|
|
|
global.
|
|
|
|
|
|
|
2015-08-14 10:08:25 +08:00
|
|
|
|
### Explanation of the ES2015 class transform
|
2015-03-25 16:30:35 +08:00
|
|
|
|
|
|
|
|
|
|
* Ignore components with calls to deprecated APIs. This is very defensive, if
|
|
|
|
|
|
the script finds any identifiers called `isMounted`, `getDOMNode`,
|
|
|
|
|
|
`replaceProps`, `replaceState` or `setProps` it will skip the component.
|
|
|
|
|
|
* Replaces `var A = React.createClass(spec)` with
|
|
|
|
|
|
`class A (extends React.Component) {spec}`.
|
|
|
|
|
|
* Pulls out all statics defined on `statics` plus the few special cased
|
|
|
|
|
|
statics like `propTypes`, `childContextTypes`, `contextTypes` and
|
|
|
|
|
|
`displayName` and assigns them after the class is created.
|
|
|
|
|
|
`class A {}; A.foo = bar;`
|
|
|
|
|
|
* Takes `getDefaultProps` and inlines it as a static `defaultProps`.
|
|
|
|
|
|
If `getDefaultProps` is defined as a function with a single statement that
|
|
|
|
|
|
returns an object, it optimizes and transforms
|
|
|
|
|
|
`getDefaultProps() { return {foo: 'bar'}; }` into
|
|
|
|
|
|
`A.defaultProps = {foo: 'bar'};`. If `getDefaultProps` contains more than
|
|
|
|
|
|
one statement it will transform into a self-invoking function like this:
|
|
|
|
|
|
`A.defaultProps = function() {…}();`. Note that this means that the function
|
|
|
|
|
|
will be executed only a single time per app-lifetime. In practice this
|
|
|
|
|
|
hasn't caused any issues – `getDefaultProps` should not contain any
|
|
|
|
|
|
side-effects.
|
|
|
|
|
|
* Binds class methods to the instance if methods are referenced without being
|
|
|
|
|
|
called directly. It checks for `this.foo` but also traces variable
|
|
|
|
|
|
assignments like `var self = this; self.foo`. It does not bind functions
|
|
|
|
|
|
from the React API and ignores functions that are being called directly
|
|
|
|
|
|
(unless it is both called directly and passed around to somewhere else)
|
|
|
|
|
|
* Creates a constructor if necessary. This is necessary if either
|
|
|
|
|
|
`getInitialState` exists in the `React.createClass` spec OR if functions
|
|
|
|
|
|
need to be bound to the instance.
|
|
|
|
|
|
* When `--no-super-class=true` is passed it only optionally extends
|
|
|
|
|
|
`React.Component` when `setState` or `forceUpdate` are used within the
|
|
|
|
|
|
class.
|
|
|
|
|
|
|
|
|
|
|
|
The constructor logic is as follows:
|
|
|
|
|
|
* Call `super(props, context)` if the base class needs to be extended.
|
|
|
|
|
|
* Bind all functions that are passed around,
|
|
|
|
|
|
like `this.foo = this.foo.bind(this)`
|
|
|
|
|
|
* Inline `getInitialState` (and remove `getInitialState` from the spec). It
|
|
|
|
|
|
also updates access of `this.props.foo` to `props.foo` and adds `props` as
|
|
|
|
|
|
argument to the constructor. This is necessary in the case when the base
|
|
|
|
|
|
class does not need to be extended where `this.props` will only be set by
|
|
|
|
|
|
React after the constructor has been run.
|
|
|
|
|
|
* Changes `return StateObject` from `getInitialState` to assign `this.state`
|
|
|
|
|
|
directly.
|
|
|
|
|
|
|
2015-03-25 16:27:45 +08:00
|
|
|
|
### Recast Options
|
|
|
|
|
|
|
|
|
|
|
|
Options to [recast](https://github.com/benjamn/recast)'s printer can be provided
|
|
|
|
|
|
through the `printOptions` command line argument
|
|
|
|
|
|
|
2015-07-31 06:19:16 +08:00
|
|
|
|
* `jscodeshift -t transform.js <file> --printOptions='{"quote":"double"}'`
|