@samitouri / QOS-React-2 / commits / caece8b4b7

Remove react-codemod

Paul O’Shannessy committed Oct 19, 2015 at 14:31 UTC caece8b4b7d301b7ff9d246f81e45d11945e1bb0
28 files changed -2295
.eslintignore
-5
@@ -11,9 +11,4 @@ docs/vendor/bundle/
11 examples/
12 # Ignore built files.
13 build/
14 -# react-codemod
15 -packages/react-codemod/test/
16 -packages/react-codemod/scripts/
17 -packages/react-codemod/build/
18 -packages/react-codemod/node_modules/
14 vendor/react-dom.js
packages/react-codemod/README.md deleted
-111
@@ -1,111 +0,0 @@
1 -## react-codemod
2 -
3 -This repository contains a collection of codemod scripts based for use with
4 -[JSCodeshift](https://github.com/facebook/jscodeshift) that help update React
5 -APIs.
6 -
7 -### Setup & Run
8 -
9 - * `npm install -g jscodeshift`
10 - * `git clone https://github.com/facebook/react.git` or download a zip file
11 - from `https://github.com/facebook/react/archive/master.zip`
12 - * `jscodeshift -t <codemod-script> <file>`
13 - * Use the `-d` option for a dry-run and use `-p` to print the output
14 - for comparison
15 -
16 -### Included Scripts
17 -
18 -`findDOMNode` updates `this.getDOMNode()` or `this.refs.foo.getDOMNode()`
19 -calls inside of `React.createClass` components to `React.findDOMNode(foo)`. Note
20 -that it will only look at code inside of `React.createClass` calls and only
21 -update calls on the component instance or its refs. You can use this script to
22 -update most calls to `getDOMNode` and then manually go through the remaining
23 -calls.
24 -
25 - * `jscodeshift -t react/packages/react-codemod/transforms/findDOMNode.js <file>`
26 -
27 -`react-to-react-dom` updates code for the split of the `react` and `react-dom`
28 -packages (e.g., `React.render` to `ReactDOM.render`). It looks for
29 -`require('react')` and replaces the appropriate property accesses using
30 -`require('react-dom')`. It does not support ES6 modules or other non-CommonJS
31 -systems. We recommend performing the `findDOMNode` conversion first.
32 -
33 - * `jscodeshift -t react/packages/react-codemod/transforms/react-to-react-dom.js <file>`
34 - * After running the automated codemod, you may want to run a regex-based find-and-replace to remove extra whitespace between the added requires, such as `codemod.py -m -d src --extensions js '(var React\s*=\s*require\(.react.\);)\n\n(\s*var ReactDOM)' '\1\n\2'` using https://github.com/facebook/codemod.
35 -
36 -`pure-render-mixin` removes `PureRenderMixin` and inlines
37 -`shouldComponentUpdate` so that the ES2015 class transform can pick up the React
38 -component and turn it into an ES2015 class. NOTE: This currently only works if you
39 -are using the master version (>0.13.1) of React as it is using
40 -`React.addons.shallowCompare`
41 -
42 - * `jscodeshift -t react/packages/react-codemod/transforms/pure-render-mixin.js <file>`
43 - * If `--mixin-name=<name>` is specified it will look for the specified name
44 - instead of `PureRenderMixin`. Note that it is not possible to use a
45 - namespaced name for the mixin. `mixins: [React.addons.PureRenderMixin]` will
46 - not currently work.
47 -
48 -`class` transforms `React.createClass` calls into ES2015 classes.
49 -
50 - * `jscodeshift -t react/packages/react-codemod/transforms/class.js <file>`
51 - * If `--no-super-class` is specified it will not extend
52 - `React.Component` if `setState` and `forceUpdate` aren't being called in a
53 - class. We do recommend always extending from `React.Component`, especially
54 - if you are using or planning to use [Flow](http://flowtype.org/). Also make
55 - sure you are not calling `setState` anywhere outside of your component.
56 -
57 -These three scripts take an option `--no-explicit-require` if you don't have a
58 -`require('React')` statement in your code files and if you access React as a
59 -global.
60 -
61 -### Explanation of the ES2015 class transform
62 -
63 - * Ignore components with calls to deprecated APIs. This is very defensive, if
64 - the script finds any identifiers called `isMounted`, `getDOMNode`,
65 - `replaceProps`, `replaceState` or `setProps` it will skip the component.
66 - * Replaces `var A = React.createClass(spec)` with
67 - `class A (extends React.Component) {spec}`.
68 - * Pulls out all statics defined on `statics` plus the few special cased
69 - statics like `propTypes`, `childContextTypes`, `contextTypes` and
70 - `displayName` and assigns them after the class is created.
71 - `class A {}; A.foo = bar;`
72 - * Takes `getDefaultProps` and inlines it as a static `defaultProps`.
73 - If `getDefaultProps` is defined as a function with a single statement that
74 - returns an object, it optimizes and transforms
75 - `getDefaultProps() { return {foo: 'bar'}; }` into
76 - `A.defaultProps = {foo: 'bar'};`. If `getDefaultProps` contains more than
77 - one statement it will transform into a self-invoking function like this:
78 - `A.defaultProps = function() {…}();`. Note that this means that the function
79 - will be executed only a single time per app-lifetime. In practice this
80 - hasn't caused any issues – `getDefaultProps` should not contain any
81 - side-effects.
82 - * Binds class methods to the instance if methods are referenced without being
83 - called directly. It checks for `this.foo` but also traces variable
84 - assignments like `var self = this; self.foo`. It does not bind functions
85 - from the React API and ignores functions that are being called directly
86 - (unless it is both called directly and passed around to somewhere else)
87 - * Creates a constructor if necessary. This is necessary if either
88 - `getInitialState` exists in the `React.createClass` spec OR if functions
89 - need to be bound to the instance.
90 - * When `--no-super-class` is passed it only optionally extends
91 - `React.Component` when `setState` or `forceUpdate` are used within the
92 - class.
93 -
94 -The constructor logic is as follows:
95 - * Call `super(props, context)` if the base class needs to be extended.
96 - * Bind all functions that are passed around,
97 - like `this.foo = this.foo.bind(this)`
98 - * Inline `getInitialState` (and remove `getInitialState` from the spec). It
99 - also updates access of `this.props.foo` to `props.foo` and adds `props` as
100 - argument to the constructor. This is necessary in the case when the base
101 - class does not need to be extended where `this.props` will only be set by
102 - React after the constructor has been run.
103 - * Changes `return StateObject` from `getInitialState` to assign `this.state`
104 - directly.
105 -
106 -### Recast Options
107 -
108 -Options to [recast](https://github.com/benjamn/recast)'s printer can be provided
109 -through the `printOptions` command line argument
110 -
111 - * `jscodeshift -t transform.js <file> --printOptions='{"quote":"double"}'`
packages/react-codemod/package.json deleted
-26
@@ -1,26 +0,0 @@
1 -{
2 - "name": "react-codemod",
3 - "version": "3.0.0",
4 - "description": "React codemod scripts",
5 - "license": "BSD-3-Clause",
6 - "repository": {
7 - "type": "git",
8 - "url": "https://github.com/facebook/react"
9 - },
10 - "scripts": {
11 - "test": "jest"
12 - },
13 - "dependencies": {
14 - "jscodeshift": "^0.3.7"
15 - },
16 - "devDependencies": {
17 - "babel-jest": "^5.3.0",
18 - "jest-cli": "^0.5.1"
19 - },
20 - "jest": {
21 - "scriptPreprocessor": "./node_modules/babel-jest",
22 - "testPathDirs": [
23 - "test"
24 - ]
25 - }
26 -}
packages/react-codemod/test/__tests__/transform-tests.js deleted
-68
@@ -1,68 +0,0 @@
1 -/**
2 - * Copyright 2013-2015, Facebook, Inc.
3 - * All rights reserved.
4 - *
5 - * This source code is licensed under the BSD-style license found in the
6 - * LICENSE file in the root directory of this source tree. An additional grant
7 - * of patent rights can be found in the PATENTS file in the same directory.
8 - *
9 - */
10 -
11 -"use strict";
12 -
13 -jest.autoMockOff();
14 -
15 -var fs = require('fs');
16 -var jscodeshift = require('jscodeshift');
17 -
18 -function read(fileName) {
19 - return fs.readFileSync(__dirname + '/../' + fileName, 'utf8');
20 -}
21 -
22 -function test(transformName, testFileName, options) {
23 - var path = testFileName + '.js';
24 - var source = read(testFileName + '.js');
25 - var output = read(testFileName + '.output.js');
26 -
27 - var transform = require('../../transforms/' + transformName);
28 - expect(
29 - (transform({path, source}, {jscodeshift}, options || {}) || '').trim()
30 - ).toEqual(
31 - output.trim()
32 - );
33 -}
34 -
35 -describe('Transform Tests', () => {
36 -
37 - it('transforms the "findDOMNode" tests correctly', () => {
38 - test('findDOMNode', 'findDOMNode-test');
39 - });
40 -
41 - it('transforms the "pure-render-mixin" tests correctly', () => {
42 - test('pure-render-mixin', 'pure-render-mixin-test');
43 -
44 - test('pure-render-mixin', 'pure-render-mixin-test2');
45 -
46 - test('pure-render-mixin', 'pure-render-mixin-test3');
47 -
48 - test('pure-render-mixin', 'pure-render-mixin-test4', {
49 - 'mixin-name': 'ReactComponentWithPureRenderMixin',
50 - });
51 - });
52 -
53 - it('transforms the "class" tests correctly', () => {
54 - test('class', 'class-test');
55 -
56 - test('class', 'class-test2', {
57 - 'super-class': false
58 - });
59 -
60 - test('class', 'class-test3');
61 -
62 - });
63 -
64 - it('transforms exports class', () => {
65 - test('class', 'export-default-class-test');
66 - });
67 -
68 -});
packages/react-codemod/test/class-test.js deleted
-133
@@ -1,133 +0,0 @@
1 -'use strict';
2 -
3 -var React = require('React');
4 -var Relay = require('Relay');
5 -
6 -var Image = require('Image.react');
7 -
8 -/*
9 - * Multiline
10 - */
11 -var MyComponent = React.createClass({
12 - getInitialState: function() {
13 - var x = this.props.foo;
14 - return {
15 - heyoo: 23,
16 - };
17 - },
18 -
19 - foo: function() {
20 - this.setState({heyoo: 24});
21 - }
22 -});
23 -
24 -// Class comment
25 -var MyComponent2 = React.createClass({
26 - getDefaultProps: function() {
27 - return {a: 1};
28 - },
29 - foo: function() {
30 - pass(this.foo);
31 - this.forceUpdate();
32 - }
33 -});
34 -
35 -var MyComponent3 = React.createClass({
36 - statics: {
37 - someThing: 10,
38 - foo: function() {},
39 - },
40 - propTypes: {
41 - highlightEntities: React.PropTypes.bool,
42 - linkifyEntities: React.PropTypes.bool,
43 - text: React.PropTypes.shape({
44 - text: React.PropTypes.string,
45 - ranges: React.PropTypes.array
46 - }).isRequired
47 - },
48 -
49 - getDefaultProps: function() {
50 - foo();
51 - return {
52 - linkifyEntities: true,
53 - highlightEntities: false
54 - };
55 - },
56 -
57 - getInitialState: function() {
58 - this.props.foo();
59 - return {
60 - heyoo: 23,
61 - };
62 - },
63 -
64 - _renderText: function(text) {
65 - return <Text text={text} />;
66 - },
67 -
68 - _renderImageRange: function(text, range) {
69 - var image = range.image;
70 - if (image) {
71 - return (
72 - <Image
73 - src={image.uri}
74 - height={image.height / image.scale}
75 - width={image.width / image.scale}
76 - />
77 - );
78 - }
79 - },
80 -
81 - autobindMe: function() {},
82 - dontAutobindMe: function() {},
83 -
84 - // Function comment
85 - _renderRange: function(text, range) {
86 - var self = this;
87 -
88 - self.dontAutobindMe();
89 - call(self.autobindMe);
90 -
91 - var type = rage.type;
92 - var {highlightEntities} = this.props;
93 -
94 - if (type === 'ImageAtRange') {
95 - return this._renderImageRange(text, range);
96 - }
97 -
98 - if (this.props.linkifyEntities) {
99 - text =
100 - <Link href={usersURI}>
101 - {text}
102 - </Link>;
103 - } else {
104 - text = <span>{text}</span>;
105 - }
106 -
107 - return text;
108 - },
109 -
110 - /* This is a comment */
111 - render: function() {
112 - var content = this.props.text;
113 - return (
114 - <BaseText
115 - {...this.props}
116 - textRenderer={this._renderText}
117 - rangeRenderer={this._renderRange}
118 - text={content.text}
119 - />
120 - );
121 - }
122 -});
123 -
124 -var MyComponent4 = React.createClass({
125 - foo: callMeMaybe(),
126 - render: function() {},
127 -});
128 -
129 -module.exports = Relay.createContainer(MyComponent, {
130 - queries: {
131 - me: Relay.graphql`this is not graphql`,
132 - }
133 -});
packages/react-codemod/test/class-test.output.js deleted
-144
@@ -1,144 +0,0 @@
1 -'use strict';
2 -
3 -var React = require('React');
4 -var Relay = require('Relay');
5 -
6 -var Image = require('Image.react');
7 -
8 -/*
9 - * Multiline
10 - */
11 -class MyComponent extends React.Component {
12 - constructor(props, context) {
13 - super(props, context);
14 - var x = props.foo;
15 -
16 - this.state = {
17 - heyoo: 23,
18 - };
19 - }
20 -
21 - foo() {
22 - this.setState({heyoo: 24});
23 - }
24 -}
25 -
26 -// Class comment
27 -class MyComponent2 extends React.Component {
28 - constructor(props, context) {
29 - super(props, context);
30 - this.foo = this.foo.bind(this);
31 - }
32 -
33 - foo() {
34 - pass(this.foo);
35 - this.forceUpdate();
36 - }
37 -}
38 -
39 -MyComponent2.defaultProps = {a: 1};
40 -
41 -class MyComponent3 extends React.Component {
42 - constructor(props, context) {
43 - super(props, context);
44 - this._renderRange = this._renderRange.bind(this);
45 - this._renderText = this._renderText.bind(this);
46 - this.autobindMe = this.autobindMe.bind(this);
47 - props.foo();
48 -
49 - this.state = {
50 - heyoo: 23,
51 - };
52 - }
53 -
54 - _renderText(text) {
55 - return <Text text={text} />;
56 - }
57 -
58 - _renderImageRange(text, range) {
59 - var image = range.image;
60 - if (image) {
61 - return (
62 - <Image
63 - src={image.uri}
64 - height={image.height / image.scale}
65 - width={image.width / image.scale}
66 - />
67 - );
68 - }
69 - }
70 -
71 - autobindMe() {}
72 - dontAutobindMe() {}
73 -
74 - // Function comment
75 - _renderRange(text, range) {
76 - var self = this;
77 -
78 - self.dontAutobindMe();
79 - call(self.autobindMe);
80 -
81 - var type = rage.type;
82 - var {highlightEntities} = this.props;
83 -
84 - if (type === 'ImageAtRange') {
85 - return this._renderImageRange(text, range);
86 - }
87 -
88 - if (this.props.linkifyEntities) {
89 - text =
90 - <Link href={usersURI}>
91 - {text}
92 - </Link>;
93 - } else {
94 - text = <span>{text}</span>;
95 - }
96 -
97 - return text;
98 - }
99 -
100 - /* This is a comment */
101 - render() {
102 - var content = this.props.text;
103 - return (
104 - <BaseText
105 - {...this.props}
106 - textRenderer={this._renderText}
107 - rangeRenderer={this._renderRange}
108 - text={content.text}
109 - />
110 - );
111 - }
112 -}
113 -
114 -MyComponent3.defaultProps = function() {
115 - foo();
116 - return {
117 - linkifyEntities: true,
118 - highlightEntities: false
119 - };
120 -}();
121 -
122 -MyComponent3.foo = function() {};
123 -
124 -MyComponent3.propTypes = {
125 - highlightEntities: React.PropTypes.bool,
126 - linkifyEntities: React.PropTypes.bool,
127 - text: React.PropTypes.shape({
128 - text: React.PropTypes.string,
129 - ranges: React.PropTypes.array
130 - }).isRequired
131 -};
132 -
133 -MyComponent3.someThing = 10;
134 -
135 -var MyComponent4 = React.createClass({
136 - foo: callMeMaybe(),
137 - render: function() {},
138 -});
139 -
140 -module.exports = Relay.createContainer(MyComponent, {
141 - queries: {
142 - me: Relay.graphql`this is not graphql`,
143 - }
144 -});
packages/react-codemod/test/class-test2.js deleted
-33
@@ -1,33 +0,0 @@
1 -'use strict';
2 -
3 -var React = require('React');
4 -
5 -var IdontNeedAParent = React.createClass({
6 - render: function() {
7 - return <div />;
8 - }
9 -});
10 -
11 -var ButIDo = React.createClass({
12 - foo: function() {
13 - this.setState({banana: '?'});
14 - },
15 -
16 - render: function() {
17 - return <div />;
18 - }
19 -});
20 -
21 -var IAccessProps = React.createClass({
22 -
23 - getInitialState: function() {
24 - return {
25 - relayReleaseDate: this.props.soon,
26 - };
27 - },
28 -
29 - render: function() {
30 - return
31 - }
32 -
33 -});
packages/react-codemod/test/class-test2.output.js deleted
-31
@@ -1,31 +0,0 @@
1 -'use strict';
2 -
3 -var React = require('React');
4 -
5 -class IdontNeedAParent {
6 - render() {
7 - return <div />;
8 - }
9 -}
10 -
11 -class ButIDo extends React.Component {
12 - foo() {
13 - this.setState({banana: '?'});
14 - }
15 -
16 - render() {
17 - return <div />;
18 - }
19 -}
20 -
21 -class IAccessProps {
22 - constructor(props) {
23 - this.state = {
24 - relayReleaseDate: props.soon,
25 - };
26 - }
27 -
28 - render() {
29 - return
30 - }
31 -}
packages/react-codemod/test/class-test3.js deleted
-20
@@ -1,20 +0,0 @@
1 -'use strict';
2 -
3 -var React = require('React');
4 -
5 -// Comment
6 -module.exports = React.createClass({
7 - propTypes: {
8 - foo: React.PropTypes.bool,
9 - },
10 -
11 - getInitialState: function() {
12 - return {
13 - foo: 'bar',
14 - };
15 - },
16 -
17 - render: function() {
18 - return <div />;
19 - }
20 -});
packages/react-codemod/test/class-test3.output.js deleted
-22
@@ -1,22 +0,0 @@
1 -'use strict';
2 -
3 -var React = require('React');
4 -
5 -// Comment
6 -module.exports = class extends React.Component {
7 - constructor(props, context) {
8 - super(props, context);
9 -
10 - this.state = {
11 - foo: 'bar',
12 - };
13 - }
14 -
15 - render() {
16 - return <div />;
17 - }
18 -};
19 -
20 -module.exports.propTypes = {
21 - foo: React.PropTypes.bool,
22 -};
packages/react-codemod/test/export-default-class-test.js deleted
-19
@@ -1,19 +0,0 @@
1 -'use strict';
2 -
3 -import React from 'React';
4 -
5 -export default React.createClass({
6 - getInitialState: function() {
7 - return {
8 - foo: 'bar',
9 - };
10 - },
11 -
12 - propTypes: {
13 - foo: React.PropTypes.string,
14 - },
15 -
16 - render: function() {
17 - return <div />;
18 - }
19 -});
packages/react-codemod/test/export-default-class-test.output.js deleted
-21
@@ -1,21 +0,0 @@
1 -'use strict';
2 -
3 -import React from 'React';
4 -
5 -export default class extends React.Component {
6 - constructor(props, context) {
7 - super(props, context);
8 -
9 - this.state = {
10 - foo: 'bar',
11 - };
12 - }
13 -
14 - static propTypes = {
15 - foo: React.PropTypes.string,
16 - };
17 -
18 - render() {
19 - return <div />;
20 - }
21 -}
packages/react-codemod/test/findDOMNode-test.js deleted
-34
@@ -1,34 +0,0 @@
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 -});
packages/react-codemod/test/findDOMNode-test.output.js deleted
-34
@@ -1,34 +0,0 @@
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 -});
packages/react-codemod/test/pure-render-mixin-test.js deleted
-45
@@ -1,45 +0,0 @@
1 -var React = require('react/addons');
2 -
3 -var PureRenderMixin = React.addons.PureRenderMixin;
4 -
5 -var MyComponent = React.createClass({
6 - mixins: [PureRenderMixin],
7 -
8 - render: function() {
9 - return <div />;
10 - }
11 -});
12 -
13 -var MyMixedComponent = React.createClass({
14 - mixins: [PureRenderMixin, SomeOtherMixin],
15 -
16 - render: function() {
17 - return <div />;
18 - }
19 -});
20 -
21 -var MyFooComponent = React.createClass({
22 - mixins: [PureRenderMixin, SomeOtherMixin],
23 -
24 - render: function() {
25 - return <div />;
26 - },
27 -
28 - foo: function() {
29 -
30 - }
31 -});
32 -
33 -var MyStupidComponent = React.createClass({
34 - mixins: [PureRenderMixin],
35 -
36 - shouldComponentUpdate: function() {
37 - return !!'wtf is this doing here?';
38 - },
39 -
40 - render: function() {
41 - return <div />;
42 - }
43 -});
44 -
45 -module.exports = MyComponent;
packages/react-codemod/test/pure-render-mixin-test.output.js deleted
-55
@@ -1,55 +0,0 @@
1 -var React = require('react/addons');
2 -
3 -var PureRenderMixin = React.addons.PureRenderMixin;
4 -
5 -var MyComponent = React.createClass({
6 - shouldComponentUpdate: function(nextProps, nextState) {
7 - return React.addons.shallowCompare(this, nextProps, nextState);
8 - },
9 -
10 - render: function() {
11 - return <div />;
12 - }
13 -});
14 -
15 -var MyMixedComponent = React.createClass({
16 - mixins: [SomeOtherMixin],
17 -
18 - shouldComponentUpdate: function(nextProps, nextState) {
19 - return React.addons.shallowCompare(this, nextProps, nextState);
20 - },
21 -
22 - render: function() {
23 - return <div />;
24 - }
25 -});
26 -
27 -var MyFooComponent = React.createClass({
28 - mixins: [SomeOtherMixin],
29 -
30 - render: function() {
31 - return <div />;
32 - },
33 -
34 - foo: function() {
35 -
36 - },
37 -
38 - shouldComponentUpdate: function(nextProps, nextState) {
39 - return React.addons.shallowCompare(this, nextProps, nextState);
40 - }
41 -});
42 -
43 -var MyStupidComponent = React.createClass({
44 - mixins: [PureRenderMixin],
45 -
46 - shouldComponentUpdate: function() {
47 - return !!'wtf is this doing here?';
48 - },
49 -
50 - render: function() {
51 - return <div />;
52 - }
53 -});
54 -
55 -module.exports = MyComponent;
packages/react-codemod/test/pure-render-mixin-test2.js deleted
-13
@@ -1,13 +0,0 @@
1 -var React = require('react/addons');
2 -
3 -var PureRenderMixin = React.addons.PureRenderMixin;
4 -
5 -var MyComponent = React.createClass({
6 - mixins: [PureRenderMixin],
7 -
8 - render: function() {
9 - return <div />;
10 - }
11 -});
12 -
13 -module.exports = MyComponent;
packages/react-codemod/test/pure-render-mixin-test2.output.js deleted
-13
@@ -1,13 +0,0 @@
1 -var React = require('react/addons');
2 -
3 -var MyComponent = React.createClass({
4 - shouldComponentUpdate: function(nextProps, nextState) {
5 - return React.addons.shallowCompare(this, nextProps, nextState);
6 - },
7 -
8 - render: function() {
9 - return <div />;
10 - }
11 -});
12 -
13 -module.exports = MyComponent;
packages/react-codemod/test/pure-render-mixin-test3.js deleted
-14
@@ -1,14 +0,0 @@
1 -var React = require('react/addons');
2 -
3 -var Foo = 'Foo';
4 -var PureRenderMixin = React.addons.PureRenderMixin;
5 -
6 -var MyComponent = React.createClass({
7 - mixins: [PureRenderMixin],
8 -
9 - render: function() {
10 - return <div />;
11 - }
12 -});
13 -
14 -module.exports = MyComponent;
packages/react-codemod/test/pure-render-mixin-test3.output.js deleted
-15
@@ -1,15 +0,0 @@
1 -var React = require('react/addons');
2 -
3 -var Foo = 'Foo';
4 -
5 -var MyComponent = React.createClass({
6 - shouldComponentUpdate: function(nextProps, nextState) {
7 - return React.addons.shallowCompare(this, nextProps, nextState);
8 - },
9 -
10 - render: function() {
11 - return <div />;
12 - }
13 -});
14 -
15 -module.exports = MyComponent;
packages/react-codemod/test/pure-render-mixin-test4.js deleted
-12
@@ -1,12 +0,0 @@
1 -var React = require('React');
2 -var ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin');
3 -
4 -var MyComponent = React.createClass({
5 - mixins: [ReactComponentWithPureRenderMixin],
6 -
7 - render: function() {
8 - return <div />;
9 - }
10 -});
11 -
12 -module.exports = MyComponent;
packages/react-codemod/test/pure-render-mixin-test4.output.js deleted
-13
@@ -1,13 +0,0 @@
1 -var React = require('React');
2 -
3 -var MyComponent = React.createClass({
4 - shouldComponentUpdate: function(nextProps, nextState) {
5 - return React.addons.shallowCompare(this, nextProps, nextState);
6 - },
7 -
8 - render: function() {
9 - return <div />;
10 - }
11 -});
12 -
13 -module.exports = MyComponent;
packages/react-codemod/transforms/class.js deleted
-555
@@ -1,555 +0,0 @@
1 -/**
2 - * Copyright 2013-2015, Facebook, Inc.
3 - * All rights reserved.
4 - *
5 - * This source code is licensed under the BSD-style license found in the
6 - * LICENSE file in the root directory of this source tree. An additional grant
7 - * of patent rights can be found in the PATENTS file in the same directory.
8 - *
9 - */
10 -
11 -'use strict';
12 -
13 -module.exports = (file, api, options) => {
14 - const j = api.jscodeshift;
15 -
16 - require('./utils/array-polyfills');
17 - const ReactUtils = require('./utils/ReactUtils')(j);
18 -
19 - const printOptions =
20 - options.printOptions || {quote: 'single', trailingComma: true};
21 - const root = j(file.source);
22 -
23 - const AUTOBIND_IGNORE_KEYS = {
24 - componentDidMount: true,
25 - componentDidUpdate: true,
26 - componentWillReceiveProps: true,
27 - componentWillMount: true,
28 - componentWillUpdate: true,
29 - componentWillUnmount: true,
30 - getDefaultProps: true,
31 - getInitialState: true,
32 - render: true,
33 - shouldComponentUpdate: true,
34 - };
35 -
36 - const BASE_COMPONENT_METHODS = ['setState', 'forceUpdate'];
37 -
38 - const DEFAULT_PROPS_FIELD = 'getDefaultProps';
39 - const DEFAULT_PROPS_KEY = 'defaultProps';
40 - const GET_INITIAL_STATE_FIELD = 'getInitialState';
41 -
42 - const DEPRECATED_APIS = [
43 - 'getDOMNode',
44 - 'isMounted',
45 - 'replaceProps',
46 - 'replaceState',
47 - 'setProps',
48 - ];
49 -
50 - const STATIC_KEY = 'statics';
51 -
52 - const STATIC_KEYS = {
53 - childContextTypes: true,
54 - contextTypes: true,
55 - displayName: true,
56 - propTypes: true,
57 - };
58 -
59 - // ---------------------------------------------------------------------------
60 - // Checks if the module uses mixins or accesses deprecated APIs.
61 - const checkDeprecatedAPICalls = classPath =>
62 - DEPRECATED_APIS.reduce(
63 - (acc, name) =>
64 - acc + j(classPath)
65 - .find(j.Identifier, {name})
66 - .size(),
67 - 0
68 - ) > 0;
69 -
70 - const callsDeprecatedAPIs = classPath => {
71 - if (checkDeprecatedAPICalls(classPath)) {
72 - console.log(
73 - file.path + ': `' + ReactUtils.getComponentName(classPath) + '` ' +
74 - 'was skipped because of deprecated API calls. Remove calls to ' +
75 - DEPRECATED_APIS.join(', ') + ' in your React component and re-run ' +
76 - 'this script.'
77 - );
78 - return false;
79 - }
80 - return true;
81 - };
82 -
83 - const canConvertToClass = classPath => {
84 - const specPath = ReactUtils.getReactCreateClassSpec(classPath);
85 - const invalidProperties = specPath.properties.filter(prop => (
86 - !prop.key.name || (
87 - !STATIC_KEYS[prop.key.name] &&
88 - STATIC_KEY != prop.key.name &&
89 - !filterDefaultPropsField(prop) &&
90 - !filterGetInitialStateField(prop) &&
91 - !isFunctionExpression(prop)
92 - )
93 - ));
94 -
95 - if (invalidProperties.length) {
96 - const invalidText = invalidProperties
97 - .map(prop => prop.key.name ? prop.key.name : prop.key)
98 - .join(', ');
99 - console.log(
100 - file.path + ': `' + ReactUtils.getComponentName(classPath) + '` ' +
101 - 'was skipped because of invalid field(s) `' + invalidText + '` on ' +
102 - 'the React component. Remove any right-hand-side expressions that ' +
103 - 'are not simple, like: `componentWillUpdate: createWillUpdate()` or ' +
104 - '`render: foo ? renderA : renderB`.'
105 - );
106 - }
107 - return !invalidProperties.length;
108 - };
109 -
110 - const hasMixins = classPath => {
111 - if (ReactUtils.hasMixins(classPath)) {
112 - console.log(
113 - file.path + ': `' + ReactUtils.getComponentName(classPath) + '` ' +
114 - 'was skipped because of mixins.'
115 - );
116 - return false;
117 - }
118 - return true;
119 - };
120 -
121 - // ---------------------------------------------------------------------------
122 - // Helpers
123 - const createFindPropFn = prop => property => (
124 - property.key &&
125 - property.key.type === 'Identifier' &&
126 - property.key.name === prop
127 - );
128 -
129 - const filterDefaultPropsField = node =>
130 - createFindPropFn(DEFAULT_PROPS_FIELD)(node);
131 -
132 - const filterGetInitialStateField = node =>
133 - createFindPropFn(GET_INITIAL_STATE_FIELD)(node);
134 -
135 - const findGetDefaultProps = specPath =>
136 - specPath.properties.find(createFindPropFn(DEFAULT_PROPS_FIELD));
137 -
138 - const findGetInitialState = specPath =>
139 - specPath.properties.find(createFindPropFn(GET_INITIAL_STATE_FIELD));
140 -
141 - // This is conservative; only check for `setState` and `forceUpdate` literals
142 - // instead of also checking which objects they are called on.
143 - const shouldExtendReactComponent = classPath =>
144 - BASE_COMPONENT_METHODS.some(name => (
145 - j(classPath)
146 - .find(j.Identifier, {name})
147 - .size() > 0
148 - ));
149 -
150 - const withComments = (to, from) => {
151 - to.comments = from.comments;
152 - return to;
153 - };
154 -
155 - // ---------------------------------------------------------------------------
156 - // Collectors
157 - const isFunctionExpression = node => (
158 - node.key &&
159 - node.key.type === 'Identifier' &&
160 - node.value &&
161 - node.value.type === 'FunctionExpression'
162 - );
163 -
164 - const collectStatics = specPath => {
165 - const statics = specPath.properties.find(createFindPropFn('statics'));
166 - const staticsObject =
167 - (statics && statics.value && statics.value.properties) || [];
168 -
169 - const getDefaultProps = findGetDefaultProps(specPath);
170 - if (getDefaultProps) {
171 - staticsObject.push(createDefaultProps(getDefaultProps));
172 - }
173 -
174 - return (
175 - staticsObject.concat(specPath.properties.filter(property =>
176 - property.key && STATIC_KEYS[property.key.name]
177 - ))
178 - .sort((a, b) => a.key.name < b.key.name)
179 - );
180 - };
181 -
182 - const collectFunctions = specPath => specPath.properties
183 - .filter(prop =>
184 - !(filterDefaultPropsField(prop) || filterGetInitialStateField(prop))
185 - )
186 - .filter(isFunctionExpression);
187 -
188 - const findAutobindNamesFor = (subtree, fnNames, literalOrIdentifier) => {
189 - const node = literalOrIdentifier;
190 - const autobindNames = {};
191 -
192 - j(subtree)
193 - .find(j.MemberExpression, {
194 - object: node.name ? {
195 - type: node.type,
196 - name: node.name,
197 - } : {type: node.type},
198 - property: {
199 - type: 'Identifier',
200 - },
201 - })
202 - .filter(path => path.value.property && fnNames[path.value.property.name])
203 - .filter(path => {
204 - const call = path.parent.value;
205 - return !(
206 - call &&
207 - call.type === 'CallExpression' &&
208 - call.callee.type === 'MemberExpression' &&
209 - call.callee.object.type === node.type &&
210 - call.callee.object.name === node.name &&
211 - call.callee.property.type === 'Identifier' &&
212 - call.callee.property.name === path.value.property.name
213 - );
214 - })
215 - .forEach(path => autobindNames[path.value.property.name] = true);
216 -
217 - return Object.keys(autobindNames);
218 - };
219 -
220 - const collectAutoBindFunctions = (functions, classPath) => {
221 - const fnNames = {};
222 - functions
223 - .filter(fn => !AUTOBIND_IGNORE_KEYS[fn.key.name])
224 - .forEach(fn => fnNames[fn.key.name] = true);
225 -
226 - const autobindNames = {};
227 - const add = name => autobindNames[name] = true;
228 -
229 - // Find `this.<foo>`
230 - findAutobindNamesFor(classPath, fnNames, j.thisExpression()).forEach(add);
231 -
232 - // Find `self.<foo>` if `self = this`
233 - j(classPath)
234 - .findVariableDeclarators()
235 - .filter(path => (
236 - path.value.id.type === 'Identifier' &&
237 - path.value.init &&
238 - path.value.init.type === 'ThisExpression'
239 - ))
240 - .forEach(path =>
241 - findAutobindNamesFor(
242 - j(path).closest(j.FunctionExpression).get(),
243 - fnNames,
244 - path.value.id
245 - ).forEach(add)
246 - );
247 -
248 - return Object.keys(autobindNames).sort();
249 - };
250 -
251 - // ---------------------------------------------------------------------------
252 - // Boom!
253 - const createMethodDefinition = fn =>
254 - withComments(j.methodDefinition(
255 - 'method',
256 - fn.key,
257 - fn.value
258 - ), fn);
259 -
260 - const createBindAssignment = name =>
261 - j.expressionStatement(
262 - j.assignmentExpression(
263 - '=',
264 - j.memberExpression(
265 - j.thisExpression(),
266 - j.identifier(name),
267 - false
268 - ),
269 - j.callExpression(
270 - j.memberExpression(
271 - j.memberExpression(
272 - j.thisExpression(),
273 - j.identifier(name),
274 - false
275 - ),
276 - j.identifier('bind'),
277 - false
278 - ),
279 - [j.thisExpression()]
280 - )
281 - )
282 - );
283 -
284 - const createSuperCall = shouldAddSuperCall =>
285 - !shouldAddSuperCall ?
286 - [] :
287 - [
288 - j.expressionStatement(
289 - j.callExpression(
290 - j.identifier('super'),
291 - [j.identifier('props'), j.identifier('context')]
292 - )
293 - ),
294 - ];
295 -
296 - const updatePropsAccess = getInitialState =>
297 - getInitialState ?
298 - j(getInitialState)
299 - .find(j.MemberExpression, {
300 - object: {
301 - type: 'ThisExpression',
302 - },
303 - property: {
304 - type: 'Identifier',
305 - name: 'props',
306 - },
307 - })
308 - .forEach(path => j(path).replaceWith(j.identifier('props')))
309 - .size() > 0 :
310 - false;
311 -
312 - const inlineGetInitialState = getInitialState => {
313 - if (!getInitialState) {
314 - return [];
315 - }
316 -
317 - return getInitialState.value.body.body.map(statement => {
318 - if (statement.type === 'ReturnStatement') {
319 - return j.expressionStatement(
320 - j.assignmentExpression(
321 - '=',
322 - j.memberExpression(
323 - j.thisExpression(),
324 - j.identifier('state'),
325 - false
326 - ),
327 - statement.argument
328 - )
329 - );
330 - }
331 -
332 - return statement;
333 - });
334 - };
335 -
336 - const createConstructorArgs = (shouldAddSuperClass, hasPropsAccess) => {
337 - if (shouldAddSuperClass) {
338 - return [j.identifier('props'), j.identifier('context')];
339 - } else if (hasPropsAccess) {
340 - return [j.identifier('props')];
341 - } else {
342 - return [];
343 - }
344 - };
345 -
346 - const createConstructor = (
347 - getInitialState,
348 - autobindFunctions,
349 - shouldAddSuperClass
350 - ) => {
351 - if (!getInitialState && !autobindFunctions.length) {
352 - return [];
353 - }
354 -
355 - const hasPropsAccess = updatePropsAccess(getInitialState);
356 - return [
357 - createMethodDefinition({
358 - key: j.identifier('constructor'),
359 - value: j.functionExpression(
360 - null,
361 - createConstructorArgs(shouldAddSuperClass, hasPropsAccess),
362 - j.blockStatement(
363 - [].concat(
364 - createSuperCall(shouldAddSuperClass),
365 - autobindFunctions.map(createBindAssignment),
366 - inlineGetInitialState(getInitialState)
367 - )
368 - )
369 - ),
370 - }),
371 - ];
372 - };
373 -
374 - const createESClass = (
375 - name,
376 - properties,
377 - getInitialState,
378 - autobindFunctions,
379 - comments,
380 - shouldAddSuperClass
381 - ) =>
382 - withComments(j.classDeclaration(
383 - name ? j.identifier(name) : null,
384 - j.classBody(
385 - [].concat(
386 - createConstructor(
387 - getInitialState,
388 - autobindFunctions,
389 - shouldAddSuperClass
390 - ),
391 - properties
392 - )
393 - ),
394 - shouldAddSuperClass ? j.memberExpression(
395 - j.identifier('React'),
396 - j.identifier('Component'),
397 - false
398 - ) : null
399 - ), {comments});
400 -
401 - const createStaticAssignment = (name, staticProperty) =>
402 - withComments(j.expressionStatement(
403 - j.assignmentExpression(
404 - '=',
405 - j.memberExpression(
406 - name,
407 - j.identifier(staticProperty.key.name),
408 - false
409 - ),
410 - staticProperty.value
411 - )
412 - ), staticProperty);
413 -
414 - const createStaticAssignmentExpressions = (name, statics) =>
415 - statics.map(staticProperty => createStaticAssignment(name, staticProperty));
416 -
417 - const createStaticClassProperty = staticProperty =>
418 - withComments(j.classProperty(
419 - j.identifier(staticProperty.key.name),
420 - staticProperty.value,
421 - null,
422 - true
423 - ), staticProperty);
424 -
425 - const createStaticClassProperties = statics =>
426 - statics.map(createStaticClassProperty);
427 -
428 - const hasSingleReturnStatement = value => (
429 - value.type === 'FunctionExpression' &&
430 - value.body &&
431 - value.body.type === 'BlockStatement' &&
432 - value.body.body &&
433 - value.body.body.length === 1 &&
434 - value.body.body[0].type === 'ReturnStatement' &&
435 - value.body.body[0].argument &&
436 - value.body.body[0].argument.type === 'ObjectExpression'
437 - );
438 -
439 - const createDefaultPropsValue = value => {
440 - if (hasSingleReturnStatement(value)) {
441 - return value.body.body[0].argument;
442 - } else {
443 - return j.callExpression(
444 - value,
445 - []
446 - );
447 - }
448 - };
449 -
450 - const createDefaultProps = prop =>
451 - withComments(
452 - j.property(
453 - 'init',
454 - j.identifier(DEFAULT_PROPS_KEY),
455 - createDefaultPropsValue(prop.value)
456 - ),
457 - prop
458 - );
459 -
460 - const getComments = classPath => {
461 - if (classPath.value.comments) {
462 - return classPath.value.comments;
463 - }
464 - const declaration = j(classPath).closest(j.VariableDeclaration);
465 - if (declaration.size()) {
466 - return declaration.get().value.comments;
467 - }
468 - return null;
469 - };
470 -
471 - const createModuleExportsMemberExpression = () =>
472 - j.memberExpression(
473 - j.identifier('module'),
474 - j.identifier('exports'),
475 - false
476 - );
477 -
478 - const updateToClass = (classPath, shouldExtend, type) => {
479 - const specPath = ReactUtils.getReactCreateClassSpec(classPath);
480 - const name = ReactUtils.getComponentName(classPath);
481 - const statics = collectStatics(specPath);
482 - const functions = collectFunctions(specPath);
483 - const comments = getComments(classPath);
484 -
485 - const autobindFunctions = collectAutoBindFunctions(functions, classPath);
486 - const getInitialState = findGetInitialState(specPath);
487 -
488 - const staticName =
489 - name ? j.identifier(name) : createModuleExportsMemberExpression();
490 -
491 - var path;
492 - if (type == 'moduleExports' || type == 'exportDefault') {
493 - path = ReactUtils.findReactCreateClassCallExpression(classPath);
494 - } else {
495 - path = j(classPath).closest(j.VariableDeclaration);
496 - }
497 -
498 - const properties =
499 - (type == 'exportDefault') ? createStaticClassProperties(statics) : [];
500 -
501 - path.replaceWith(
502 - createESClass(
503 - name,
504 - properties.concat(functions.map(createMethodDefinition)),
505 - getInitialState,
506 - autobindFunctions,
507 - comments,
508 - shouldExtend || shouldExtendReactComponent(classPath)
509 - )
510 - );
511 -
512 - if (type == 'moduleExports' || type == 'var') {
513 - const staticAssignments = createStaticAssignmentExpressions(
514 - staticName,
515 - statics
516 - );
517 - if (type == 'moduleExports') {
518 - root.get().value.program.body.push(...staticAssignments);
519 - } else {
520 - path.insertAfter(staticAssignments.reverse());
521 - }
522 - }
523 - };
524 -
525 - if (
526 - !options['explicit-require'] || ReactUtils.hasReact(root)
527 - ) {
528 - const apply = (path, type) =>
529 - path
530 - .filter(hasMixins)
531 - .filter(callsDeprecatedAPIs)
532 - .filter(canConvertToClass)
533 - .forEach(classPath => updateToClass(
534 - classPath,
535 - !options['super-class'],
536 - type
537 - ));
538 -
539 - const didTransform = (
540 - apply(ReactUtils.findReactCreateClass(root), 'var')
541 - .size() +
542 - apply(ReactUtils.findReactCreateClassModuleExports(root), 'moduleExports')
543 - .size() +
544 - apply(ReactUtils.findReactCreateClassExportDefault(root), 'exportDefault')
545 - .size()
546 - ) > 0;
547 -
548 - if (didTransform) {
549 - return root.toSource(printOptions);
550 - }
551 -
552 - }
553 -
554 - return null;
555 -};
packages/react-codemod/transforms/findDOMNode.js deleted
-144
@@ -1,144 +0,0 @@
1 -/**
2 - * Copyright 2013-2015, Facebook, Inc.
3 - * All rights reserved.
4 - *
5 - * This source code is licensed under the BSD-style license found in the
6 - * LICENSE file in the root directory of this source tree. An additional grant
7 - * of patent rights can be found in the PATENTS file in the same directory.
8 - *
9 - */
10 -
11 -'use strict';
12 -
13 -function getDOMNodeToFindDOMNode(file, api, options) {
14 - const j = api.jscodeshift;
15 -
16 - require('./utils/array-polyfills');
17 - const ReactUtils = require('./utils/ReactUtils')(j);
18 -
19 - const printOptions =
20 - options.printOptions || {quote: 'single', trailingComma: true};
21 - const root = j(file.source);
22 -
23 - const createReactFindDOMNodeCall = arg => j.callExpression(
24 - j.memberExpression(
25 - j.identifier('React'),
26 - j.identifier('findDOMNode'),
27 - false
28 - ),
29 - [arg]
30 - );
31 -
32 - const updateRefCall = (path, refName) => {
33 - j(path)
34 - .find(j.CallExpression, {
35 - callee: {
36 - object: {
37 - type: 'Identifier',
38 - name: refName,
39 - },
40 - property: {
41 - type: 'Identifier',
42 - name: 'getDOMNode',
43 - },
44 - },
45 - })
46 - .forEach(callPath => j(callPath).replaceWith(
47 - createReactFindDOMNodeCall(j.identifier(refName))
48 - ));
49 - };
50 -
51 - const updateToFindDOMNode = classPath => {
52 - var sum = 0;
53 -
54 - // this.getDOMNode()
55 - sum += j(classPath)
56 - .find(j.CallExpression, {
57 - callee: {
58 - object: {
59 - type: 'ThisExpression',
60 - },
61 - property: {
62 - type: 'Identifier',
63 - name: 'getDOMNode',
64 - },
65 - },
66 - })
67 - .forEach(path => j(path).replaceWith(
68 - createReactFindDOMNodeCall(j.thisExpression())
69 - ))
70 - .size();
71 -
72 - // this.refs.xxx.getDOMNode() or this.refs.xxx.refs.yyy.getDOMNode()
73 - sum += j(classPath)
74 - .find(j.MemberExpression, {
75 - object: {
76 - type: 'MemberExpression',
77 - object: {
78 - type: 'MemberExpression',
79 - object: {
80 - type: 'ThisExpression',
81 - },
82 - property: {
83 - type: 'Identifier',
84 - name: 'refs',
85 - },
86 - },
87 - },
88 - })
89 - .closest(j.CallExpression)
90 - .filter(path => (
91 - path.value.callee.property &&
92 - path.value.callee.property.type === 'Identifier' &&
93 - path.value.callee.property.name === 'getDOMNode'
94 - ))
95 - .forEach(path => j(path).replaceWith(
96 - createReactFindDOMNodeCall(path.value.callee.object)
97 - ))
98 - .size();
99 -
100 - // someVariable.getDOMNode() wherre `someVariable = this.refs.xxx`
101 - sum += j(classPath)
102 - .findVariableDeclarators()
103 - .filter(path => {
104 - const init = path.value.init;
105 - const value = init && init.object;
106 - return (
107 - value &&
108 - value.type === 'MemberExpression' &&
109 - value.object &&
110 - value.object.type === 'ThisExpression' &&
111 - value.property &&
112 - value.property.type === 'Identifier' &&
113 - value.property.name === 'refs' &&
114 - init.property &&
115 - init.property.type === 'Identifier'
116 - );
117 - })
118 - .forEach(path => j(path)
119 - .closest(j.FunctionExpression)
120 - .forEach(fnPath => updateRefCall(fnPath, path.value.id.name))
121 - )
122 - .size();
123 -
124 - return sum > 0;
125 - };
126 -
127 - if (
128 - !options['explicit-require'] ||
129 - ReactUtils.hasReact(root)
130 - ) {
131 - const didTransform = ReactUtils
132 - .findReactCreateClass(root)
133 - .filter(updateToFindDOMNode)
134 - .size() > 0;
135 -
136 - if (didTransform) {
137 - return root.toSource(printOptions);
138 - }
139 - }
140 -
141 - return null;
142 -}
143 -
144 -module.exports = getDOMNodeToFindDOMNode;
packages/react-codemod/transforms/pure-render-mixin.js deleted
-188
@@ -1,188 +0,0 @@
1 -/**
2 - * Copyright 2013-2015, Facebook, Inc.
3 - * All rights reserved.
4 - *
5 - * This source code is licensed under the BSD-style license found in the
6 - * LICENSE file in the root directory of this source tree. An additional grant
7 - * of patent rights can be found in the PATENTS file in the same directory.
8 - *
9 - */
10 -
11 -'use strict';
12 -
13 -function removePureRenderMixin(file, api, options) {
14 - const j = api.jscodeshift;
15 -
16 - require('./utils/array-polyfills');
17 - const ReactUtils = require('./utils/ReactUtils')(j);
18 -
19 - const printOptions =
20 - options.printOptions || {quote: 'single', trailingComma: true};
21 - const root = j(file.source);
22 -
23 - const PURE_RENDER_MIXIN = options['mixin-name'] || 'PureRenderMixin';
24 - const SHOULD_COMPONENT_UPDATE = 'shouldComponentUpdate';
25 - const NEXT_PROPS = 'nextProps';
26 - const NEXT_STATE = 'nextState';
27 -
28 - // ---------------------------------------------------------------------------
29 - // shouldComponentUpdate
30 - const createShouldComponentUpdateFunction = () =>
31 - j.functionExpression(
32 - null,
33 - [j.identifier(NEXT_PROPS), j.identifier(NEXT_STATE)],
34 - j.blockStatement([
35 - j.returnStatement(
36 - j.callExpression(
37 - j.memberExpression(
38 - j.identifier('React'),
39 - j.memberExpression(
40 - j.identifier('addons'),
41 - j.identifier('shallowCompare'),
42 - false
43 - ),
44 - false
45 - ),
46 - [
47 - j.thisExpression(),
48 - j.identifier(NEXT_PROPS),
49 - j.identifier(NEXT_STATE),
50 - ]
51 - )
52 - ),
53 - ])
54 - );
55 -
56 - const createShouldComponentUpdateProperty = () =>
57 - j.property(
58 - 'init',
59 - j.identifier(SHOULD_COMPONENT_UPDATE),
60 - createShouldComponentUpdateFunction()
61 - );
62 -
63 - const hasShouldComponentUpdate = classPath =>
64 - ReactUtils.getReactCreateClassSpec(classPath)
65 - .properties.every(property =>
66 - property.key.name !== SHOULD_COMPONENT_UPDATE
67 - );
68 -
69 - // ---------------------------------------------------------------------------
70 - // Mixin related code
71 - const isPureRenderMixin = node => (
72 - node.type === 'Identifier' &&
73 - node.name === PURE_RENDER_MIXIN
74 - );
75 -
76 - const hasPureRenderMixin = classPath => {
77 - const spec = ReactUtils.getReactCreateClassSpec(classPath);
78 - const mixin = spec && spec.properties.find(ReactUtils.isMixinProperty);
79 - return mixin && mixin.value.elements.some(isPureRenderMixin);
80 - };
81 -
82 - const removeMixin = elements =>
83 - j.property(
84 - 'init',
85 - j.identifier('mixins'),
86 - j.arrayExpression(
87 - elements.filter(element => !isPureRenderMixin(element))
88 - )
89 - );
90 -
91 - // ---------------------------------------------------------------------------
92 - // Boom!
93 - const insertShouldComponentUpdate = properties => {
94 - const length = properties.length;
95 - const lastProp = properties[length - 1];
96 - // I wouldn't dare insert at the bottom if the last function is render
97 - if (
98 - lastProp.key.type === 'Identifier' &&
99 - lastProp.key.name === 'render'
100 - ) {
101 - properties.splice(
102 - length - 1,
103 - 1,
104 - createShouldComponentUpdateProperty(),
105 - lastProp
106 - );
107 - } else {
108 - properties.push(createShouldComponentUpdateProperty());
109 - }
110 - return properties;
111 - };
112 -
113 - const cleanupReactComponent = classPath => {
114 - const spec = ReactUtils.getReactCreateClassSpec(classPath);
115 - const properties = spec.properties
116 - .map(property => {
117 - if (ReactUtils.isMixinProperty(property)) {
118 - const elements = property.value.elements;
119 - return (elements.length !== 1) ? removeMixin(elements) : null;
120 - }
121 - return property;
122 - })
123 - .filter(property => !!property);
124 -
125 - ReactUtils.findReactCreateClassCallExpression(classPath).replaceWith(
126 - ReactUtils.createCreateReactClassCallExpression(
127 - insertShouldComponentUpdate(properties)
128 - )
129 - );
130 - };
131 -
132 - // Remove it if only two or fewer are left:
133 - // var PureRenderMixin = React.addons.PureRenderMixin;
134 - const hasPureRenderIdentifiers = path =>
135 - path.find(j.Identifier, {
136 - name: PURE_RENDER_MIXIN,
137 - }).size() > 2;
138 -
139 - const deletePureRenderMixin = path => {
140 - if (hasPureRenderIdentifiers(path)) {
141 - return;
142 - }
143 -
144 - const declaration = path
145 - .findVariableDeclarators(PURE_RENDER_MIXIN)
146 - .closest(j.VariableDeclaration);
147 -
148 - if (declaration.size > 1) {
149 - declaration.forEach(p =>
150 - j(p).replaceWith(
151 - j.variableDeclaration(
152 - 'var',
153 - p.value.declarations.filter(isPureRenderMixin)
154 - )
155 - )
156 - );
157 - } else {
158 - // Let's assume the variable declaration happens at the top level
159 - const program = declaration.closest(j.Program).get();
160 - const body = program.value.body;
161 - const index = body.indexOf(declaration.get().value);
162 - if (index !== -1) {
163 - body.splice(index, 1);
164 - }
165 - }
166 - };
167 -
168 - if (
169 - !options['explicit-require'] ||
170 - ReactUtils.hasReact(root)
171 - ) {
172 - const didTransform = ReactUtils
173 - .findReactCreateClass(root)
174 - .filter(hasPureRenderMixin)
175 - .filter(hasShouldComponentUpdate)
176 - .forEach(cleanupReactComponent)
177 - .size() > 0;
178 -
179 - if (didTransform) {
180 - deletePureRenderMixin(root);
181 - return root.toSource(printOptions);
182 - }
183 - }
184 -
185 - return null;
186 -}
187 -
188 -module.exports = removePureRenderMixin;
packages/react-codemod/transforms/react-to-react-dom.js deleted
-321
@@ -1,321 +0,0 @@
1 -/**
2 - * Copyright 2013-2015, Facebook, Inc.
3 - * All rights reserved.
4 - *
5 - * This source code is licensed under the BSD-style license found in the
6 - * LICENSE file in the root directory of this source tree. An additional grant
7 - * of patent rights can be found in the PATENTS file in the same directory.
8 - *
9 - */
10 -
11 -'use strict';
12 -
13 -var CORE_PROPERTIES = [
14 - 'Children',
15 - 'Component',
16 - 'createElement',
17 - 'cloneElement',
18 - 'isValidElement',
19 - 'PropTypes',
20 - 'createClass',
21 - 'createFactory',
22 - 'createMixin',
23 - 'DOM',
24 - '__spread',
25 -];
26 -
27 -var DOM_PROPERTIES = [
28 - 'findDOMNode',
29 - 'render',
30 - 'unmountComponentAtNode',
31 - 'unstable_batchedUpdates',
32 - 'unstable_renderSubtreeIntoContainer',
33 -];
34 -
35 -var DOM_SERVER_PROPERTIES = [
36 - 'renderToString',
37 - 'renderToStaticMarkup',
38 -];
39 -
40 -function reportError(node, error) {
41 - throw new Error(
42 - `At ${node.loc.start.line}:${node.loc.start.column}: ${error}`
43 - );
44 -}
45 -
46 -function isRequire(path, moduleName) {
47 - return (
48 - path.value.type === 'CallExpression' &&
49 - path.value.callee.type === 'Identifier' &&
50 - path.value.callee.name === 'require' &&
51 - path.value.arguments.length === 1 &&
52 - path.value.arguments[0].type === 'Literal' &&
53 - path.value.arguments[0].value === moduleName
54 - );
55 -}
56 -
57 -module.exports = function(file, api) {
58 - var j = api.jscodeshift;
59 - var root = j(file.source);
60 -
61 - [
62 - ['React', 'ReactDOM', 'ReactDOMServer'],
63 - ['react', 'react-dom', 'react-dom/server'],
64 - ].forEach(function(pair) {
65 - var coreModuleName = pair[0];
66 - var domModuleName = pair[1];
67 - var domServerModuleName = pair[2];
68 -
69 - var domAlreadyDeclared = false;
70 - var domServerAlreadyDeclared = false;
71 -
72 - var coreRequireDeclarator;
73 - root
74 - .find(j.CallExpression)
75 - .filter(p => isRequire(p, coreModuleName))
76 - .forEach(p => {
77 - var name, scope;
78 - if (p.parent.value.type === 'VariableDeclarator') {
79 - if (p.parent.value.id.type === 'ObjectPattern') {
80 - var pattern = p.parent.value.id;
81 - var all = pattern.properties.every(function(prop) {
82 - if (prop.key.type === 'Identifier') {
83 - name = prop.key.name;
84 - return CORE_PROPERTIES.indexOf(name) !== -1;
85 - }
86 - return false;
87 - });
88 - if (all) {
89 - // var {PropTypes} = require('React'); so leave alone
90 - return;
91 - }
92 - }
93 - if (coreRequireDeclarator) {
94 - reportError(
95 - p.value,
96 - 'Multiple declarations of React'
97 - );
98 - }
99 - if (p.parent.value.id.type !== 'Identifier') {
100 - reportError(
101 - p.value,
102 - 'Unexpected destructuring in require of ' + coreModuleName
103 - );
104 - }
105 - name = p.parent.value.id.name;
106 - scope = p.scope.lookup(name);
107 - if (scope.declares('ReactDOM')) {
108 - console.log('Using existing ReactDOM var in ' + file.path);
109 - domAlreadyDeclared = true;
110 - }
111 - if (scope.declares('ReactDOMServer')) {
112 - console.log('Using existing ReactDOMServer var in ' + file.path);
113 - domServerAlreadyDeclared = true;
114 - }
115 - coreRequireDeclarator = p.parent;
116 - } else if (p.parent.value.type === 'AssignmentExpression') {
117 - if (p.parent.value.left.type !== 'Identifier') {
118 - reportError(
119 - p.value,
120 - 'Unexpected destructuring in require of ' + coreModuleName
121 - );
122 - }
123 - name = p.parent.value.left.name;
124 - scope = p.scope.lookup(name);
125 - var reactBindings = scope.getBindings()[name];
126 - if (reactBindings.length !== 1) {
127 - throw new Error(
128 - 'Unexpected number of bindings: ' + reactBindings.length
129 - );
130 - }
131 - coreRequireDeclarator = reactBindings[0].parent;
132 - if (coreRequireDeclarator.value.init &&
133 - !isRequire(coreRequireDeclarator.get('init'), coreModuleName)) {
134 - reportError(
135 - coreRequireDeclarator.value,
136 - 'Unexpected initialization of ' + coreModuleName
137 - );
138 - }
139 - if (scope.declares('ReactDOM')) {
140 - console.log('Using existing ReactDOM var in ' + file.path);
141 - domAlreadyDeclared = true;
142 - }
143 - if (scope.declares('ReactDOMServer')) {
144 - console.log('Using existing ReactDOMServer var in ' + file.path);
145 - domServerAlreadyDeclared = true;
146 - }
147 - }
148 - });
149 - if (!coreRequireDeclarator) {
150 - return;
151 - }
152 -
153 - if (!domAlreadyDeclared &&
154 - root.find(j.Identifier, {name: 'ReactDOM'}).size() > 0) {
155 - throw new Error(
156 - 'ReactDOM is already defined in a different scope than React'
157 - );
158 - }
159 - if (!domServerAlreadyDeclared &&
160 - root.find(j.Identifier, {name: 'ReactDOMServer'}).size() > 0) {
161 - throw new Error(
162 - 'ReactDOMServer is already defined in a different scope than React'
163 - );
164 - }
165 -
166 - var coreName = coreRequireDeclarator.value.id.name;
167 -
168 - var processed = new Set();
169 - var requireAssignments = [];
170 - var coreUses = 0;
171 - var domUses = 0;
172 - var domServerUses = 0;
173 -
174 - root
175 - .find(j.Identifier, {name: coreName})
176 - .forEach(p => {
177 - if (processed.has(p.value)) {
178 - // https://github.com/facebook/jscodeshift/issues/36
179 - return;
180 - }
181 - processed.add(p.value);
182 - if (p.parent.value.type === 'MemberExpression' ||
183 - p.parent.value.type === 'QualifiedTypeIdentifier') {
184 - var left;
185 - var right;
186 - if (p.parent.value.type === 'MemberExpression') {
187 - left = p.parent.value.object;
188 - right = p.parent.value.property;
189 - } else {
190 - left = p.parent.value.qualification;
191 - right = p.parent.value.id;
192 - }
193 - if (left === p.value) {
194 - // React.foo (or React[foo])
195 - if (right.type === 'Identifier') {
196 - var name = right.name;
197 - if (CORE_PROPERTIES.indexOf(name) !== -1) {
198 - coreUses++;
199 - } else if (DOM_PROPERTIES.indexOf(name) !== -1) {
200 - domUses++;
201 - j(p).replaceWith(j.identifier('ReactDOM'));
202 - } else if (DOM_SERVER_PROPERTIES.indexOf(name) !== -1) {
203 - domServerUses++;
204 - j(p).replaceWith(j.identifier('ReactDOMServer'));
205 - } else {
206 - throw new Error('Unknown property React.' + name);
207 - }
208 - }
209 - } else if (right === p.value) {
210 - // foo.React, no need to transform
211 - } else {
212 - throw new Error('unimplemented');
213 - }
214 - } else if (p.parent.value.type === 'VariableDeclarator') {
215 - if (p.parent.value.id === p.value) {
216 - // var React = ...;
217 - } else if (p.parent.value.init === p.value) {
218 - // var ... = React;
219 - var pattern = p.parent.value.id;
220 - if (pattern.type === 'ObjectPattern') {
221 - // var {PropTypes} = React;
222 - // Most of these cases will just be looking at {PropTypes} so this
223 - // is usually a no-op.
224 - var coreProperties = [];
225 - var domProperties = [];
226 - pattern.properties.forEach(function(prop) {
227 - if (prop.key.type === 'Identifier') {
228 - var key = prop.key.name;
229 - if (CORE_PROPERTIES.indexOf(key) !== -1) {
230 - coreProperties.push(prop);
231 - } else if (DOM_PROPERTIES.indexOf(key) !== -1) {
232 - domProperties.push(prop);
233 - } else {
234 - throw new Error(
235 - 'Unknown property React.' + key + ' while destructuring'
236 - );
237 - }
238 - } else {
239 - throw new Error('unimplemented');
240 - }
241 - });
242 - var domDeclarator = j.variableDeclarator(
243 - j.objectPattern(domProperties),
244 - j.identifier('ReactDOM')
245 - );
246 - if (coreProperties.length && !domProperties.length) {
247 - // nothing to do
248 - coreUses++;
249 - } else if (domProperties.length && !coreProperties.length) {
250 - domUses++;
251 - j(p.parent).replaceWith(domDeclarator);
252 - } else {
253 - coreUses++;
254 - domUses++;
255 - var decl = j(p).closest(j.VariableDeclaration);
256 - decl.insertAfter(j.variableDeclaration(
257 - decl.get().value.kind,
258 - [domDeclarator]
259 - ));
260 - }
261 - } else {
262 - throw new Error('unimplemented');
263 - }
264 - } else {
265 - throw new Error('unimplemented');
266 - }
267 - } else if (p.parent.value.type === 'AssignmentExpression') {
268 - if (p.parent.value.left === p.value) {
269 - if (isRequire(p.parent.get('right'), coreModuleName)) {
270 - requireAssignments.push(p.parent);
271 - } else {
272 - reportError(
273 - p.parent.value,
274 - 'Unexpected assignment to ' + coreModuleName
275 - );
276 - }
277 - } else {
278 - throw new Error('unimplemented');
279 - }
280 - } else {
281 - reportError(p.value, 'unimplemented ' + p.parent.value.type);
282 - }
283 - });
284 -
285 - coreUses += root.find(j.JSXElement).size();
286 -
287 - function insertRequire(name, path) {
288 - var req = j.callExpression(
289 - j.identifier('require'),
290 - [j.literal(path)]
291 - );
292 - requireAssignments.forEach(function(requireAssignment) {
293 - requireAssignment.parent.insertAfter(
294 - j.expressionStatement(
295 - j.assignmentExpression('=', j.identifier(name), req)
296 - )
297 - );
298 - });
299 - coreRequireDeclarator.parent.insertAfter(j.variableDeclaration(
300 - coreRequireDeclarator.parent.value.kind,
301 - [j.variableDeclarator(
302 - j.identifier(name),
303 - coreRequireDeclarator.value.init ? req : null
304 - )]
305 - ));
306 - }
307 -
308 - if (domServerUses > 0 && !domServerAlreadyDeclared) {
309 - insertRequire('ReactDOMServer', domServerModuleName);
310 - }
311 - if (domUses > 0 && !domAlreadyDeclared) {
312 - insertRequire('ReactDOM', domModuleName);
313 - }
314 - if ((domUses > 0 || domServerUses > 0) && coreUses === 0) {
315 - j(coreRequireDeclarator).remove();
316 - requireAssignments.forEach(r => j(r).remove());
317 - }
318 - });
319 -
320 - return root.toSource({quote: 'single'});
321 -};
packages/react-codemod/transforms/utils/ReactUtils.js deleted
-160
@@ -1,160 +0,0 @@
1 -/**
2 - * Copyright 2013-2015, Facebook, Inc.
3 - * All rights reserved.
4 - *
5 - * This source code is licensed under the BSD-style license found in the
6 - * LICENSE file in the root directory of this source tree. An additional grant
7 - * of patent rights can be found in the PATENTS file in the same directory.
8 - *
9 - */
10 -
11 -'use strict';
12 -
13 -module.exports = function(j) {
14 - const REACT_CREATE_CLASS_MEMBER_EXPRESSION = {
15 - type: 'MemberExpression',
16 - object: {
17 - name: 'React',
18 - },
19 - property: {
20 - name: 'createClass',
21 - },
22 - };
23 -
24 - // ---------------------------------------------------------------------------
25 - // Checks if the file requires a certain module
26 - const hasModule = (path, module) =>
27 - path
28 - .findVariableDeclarators()
29 - .filter(j.filters.VariableDeclarator.requiresModule(module))
30 - .size() === 1 ||
31 - path
32 - .find(j.ImportDeclaration, {
33 - type: 'ImportDeclaration',
34 - source: {
35 - type: 'Literal',
36 - },
37 - })
38 - .filter(declarator => declarator.value.source.value === module)
39 - .size() === 1;
40 -
41 - const hasReact = path => (
42 - hasModule(path, 'React') ||
43 - hasModule(path, 'react') ||
44 - hasModule(path, 'react/addons')
45 - );
46 -
47 - // ---------------------------------------------------------------------------
48 - // Finds all variable declarations that call React.createClass
49 - const findReactCreateClassCallExpression = path =>
50 - j(path).find(j.CallExpression, {
51 - callee: REACT_CREATE_CLASS_MEMBER_EXPRESSION,
52 - });
53 -
54 - const findReactCreateClass = path =>
55 - path
56 - .findVariableDeclarators()
57 - .filter(decl => findReactCreateClassCallExpression(decl).size() > 0);
58 -
59 - const findReactCreateClassExportDefault = path =>
60 - path.find(j.ExportDefaultDeclaration, {
61 - declaration: {
62 - type: 'CallExpression',
63 - callee: REACT_CREATE_CLASS_MEMBER_EXPRESSION,
64 - },
65 - });
66 -
67 - const findReactCreateClassModuleExports = path =>
68 - path
69 - .find(j.AssignmentExpression, {
70 - left: {
71 - type: 'MemberExpression',
72 - object: {
73 - type: 'Identifier',
74 - name: 'module',
75 - },
76 - property: {
77 - type: 'Identifier',
78 - name: 'exports',
79 - },
80 - },
81 - right: {
82 - type: 'CallExpression',
83 - callee: REACT_CREATE_CLASS_MEMBER_EXPRESSION,
84 - },
85 - });
86 -
87 - // ---------------------------------------------------------------------------
88 - // Finds all classes that extend React.Component
89 - const findReactES6ClassDeclaration = path =>
90 - path
91 - .find(j.ClassDeclaration, {
92 - superClass: {
93 - type: 'MemberExpression',
94 - object: {
95 - type: 'Identifier',
96 - name: 'React',
97 - },
98 - property: {
99 - type: 'Identifier',
100 - name: 'Component',
101 - },
102 - },
103 - });
104 -
105 - // ---------------------------------------------------------------------------
106 - // Checks if the React class has mixins
107 - const isMixinProperty = property => {
108 - const key = property.key;
109 - const value = property.value;
110 - return (
111 - key.name === 'mixins' &&
112 - value.type === 'ArrayExpression' &&
113 - Array.isArray(value.elements) &&
114 - value.elements.length
115 - );
116 - };
117 -
118 - const hasMixins = classPath => {
119 - const spec = getReactCreateClassSpec(classPath);
120 - return spec && spec.properties.some(isMixinProperty);
121 - };
122 -
123 - // ---------------------------------------------------------------------------
124 - // Others
125 - const getReactCreateClassSpec = classPath => {
126 - var {value} = classPath;
127 - const spec = (value.init || value.right || value.declaration).arguments[0];
128 - if (spec.type === 'ObjectExpression' && Array.isArray(spec.properties)) {
129 - return spec;
130 - }
131 - };
132 -
133 - const createCreateReactClassCallExpression = properties =>
134 - j.callExpression(
135 - j.memberExpression(
136 - j.identifier('React'),
137 - j.identifier('createClass'),
138 - false
139 - ),
140 - [j.objectExpression(properties)]
141 - );
142 -
143 - const getComponentName =
144 - classPath => classPath.node.id && classPath.node.id.name;
145 -
146 - return {
147 - createCreateReactClassCallExpression,
148 - findReactES6ClassDeclaration,
149 - findReactCreateClass,
150 - findReactCreateClassCallExpression,
151 - findReactCreateClassModuleExports,
152 - findReactCreateClassExportDefault,
153 - getComponentName,
154 - getReactCreateClassSpec,
155 - hasMixins,
156 - hasModule,
157 - hasReact,
158 - isMixinProperty,
159 - };
160 -};
packages/react-codemod/transforms/utils/array-polyfills.js deleted
-46
@@ -1,46 +0,0 @@
1 -/**
2 - * Copyright 2013-2015, Facebook, Inc.
3 - * All rights reserved.
4 - *
5 - * This source code is licensed under the BSD-style license found in the
6 - * LICENSE file in the root directory of this source tree. An additional grant
7 - * of patent rights can be found in the PATENTS file in the same directory.
8 - *
9 - */
10 -
11 - /*eslint-disable no-extend-native*/
12 -
13 -'use strict';
14 -
15 -function findIndex(predicate, context) {
16 - if (this == null) {
17 - throw new TypeError(
18 - 'Array.prototype.findIndex called on null or undefined'
19 - );
20 - }
21 - if (typeof predicate !== 'function') {
22 - throw new TypeError('predicate must be a function');
23 - }
24 - var list = Object(this);
25 - var length = list.length >>> 0;
26 - for (var i = 0; i < length; i++) {
27 - if (predicate.call(context, list[i], i, list)) {
28 - return i;
29 - }
30 - }
31 - return -1;
32 -}
33 -
34 -if (!Array.prototype.findIndex) {
35 - Array.prototype.findIndex = findIndex;
36 -}
37 -
38 -if (!Array.prototype.find) {
39 - Array.prototype.find = function(predicate, context) {
40 - if (this == null) {
41 - throw new TypeError('Array.prototype.find called on null or undefined');
42 - }
43 - var index = findIndex.call(this, predicate, context);
44 - return index === -1 ? undefined : this[index];
45 - };
46 -}