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
-}