From caece8b4b7d301b7ff9d246f81e45d11945e1bb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20O=E2=80=99Shannessy?= Date: Mon, 19 Oct 2015 14:31:31 -0700 Subject: [PATCH] Remove react-codemod --- .eslintignore | 5 - packages/react-codemod/README.md | 111 ---- packages/react-codemod/package.json | 26 - .../test/__tests__/transform-tests.js | 68 --- packages/react-codemod/test/class-test.js | 133 ----- .../react-codemod/test/class-test.output.js | 144 ----- packages/react-codemod/test/class-test2.js | 33 -- .../react-codemod/test/class-test2.output.js | 31 - packages/react-codemod/test/class-test3.js | 20 - .../react-codemod/test/class-test3.output.js | 22 - .../test/export-default-class-test.js | 19 - .../test/export-default-class-test.output.js | 21 - .../react-codemod/test/findDOMNode-test.js | 34 -- .../test/findDOMNode-test.output.js | 34 -- .../test/pure-render-mixin-test.js | 45 -- .../test/pure-render-mixin-test.output.js | 55 -- .../test/pure-render-mixin-test2.js | 13 - .../test/pure-render-mixin-test2.output.js | 13 - .../test/pure-render-mixin-test3.js | 14 - .../test/pure-render-mixin-test3.output.js | 15 - .../test/pure-render-mixin-test4.js | 12 - .../test/pure-render-mixin-test4.output.js | 13 - packages/react-codemod/transforms/class.js | 555 ------------------ .../react-codemod/transforms/findDOMNode.js | 144 ----- .../transforms/pure-render-mixin.js | 188 ------ .../transforms/react-to-react-dom.js | 321 ---------- .../transforms/utils/ReactUtils.js | 160 ----- .../transforms/utils/array-polyfills.js | 46 -- 28 files changed, 2295 deletions(-) delete mode 100644 packages/react-codemod/README.md delete mode 100644 packages/react-codemod/package.json delete mode 100644 packages/react-codemod/test/__tests__/transform-tests.js delete mode 100644 packages/react-codemod/test/class-test.js delete mode 100644 packages/react-codemod/test/class-test.output.js delete mode 100644 packages/react-codemod/test/class-test2.js delete mode 100644 packages/react-codemod/test/class-test2.output.js delete mode 100644 packages/react-codemod/test/class-test3.js delete mode 100644 packages/react-codemod/test/class-test3.output.js delete mode 100644 packages/react-codemod/test/export-default-class-test.js delete mode 100644 packages/react-codemod/test/export-default-class-test.output.js delete mode 100644 packages/react-codemod/test/findDOMNode-test.js delete mode 100644 packages/react-codemod/test/findDOMNode-test.output.js delete mode 100644 packages/react-codemod/test/pure-render-mixin-test.js delete mode 100644 packages/react-codemod/test/pure-render-mixin-test.output.js delete mode 100644 packages/react-codemod/test/pure-render-mixin-test2.js delete mode 100644 packages/react-codemod/test/pure-render-mixin-test2.output.js delete mode 100644 packages/react-codemod/test/pure-render-mixin-test3.js delete mode 100644 packages/react-codemod/test/pure-render-mixin-test3.output.js delete mode 100644 packages/react-codemod/test/pure-render-mixin-test4.js delete mode 100644 packages/react-codemod/test/pure-render-mixin-test4.output.js delete mode 100644 packages/react-codemod/transforms/class.js delete mode 100644 packages/react-codemod/transforms/findDOMNode.js delete mode 100644 packages/react-codemod/transforms/pure-render-mixin.js delete mode 100644 packages/react-codemod/transforms/react-to-react-dom.js delete mode 100644 packages/react-codemod/transforms/utils/ReactUtils.js delete mode 100644 packages/react-codemod/transforms/utils/array-polyfills.js diff --git a/.eslintignore b/.eslintignore index c20a6aa20e..c8354bc782 100644 --- a/.eslintignore +++ b/.eslintignore @@ -11,9 +11,4 @@ docs/vendor/bundle/ examples/ # Ignore built files. build/ -# react-codemod -packages/react-codemod/test/ -packages/react-codemod/scripts/ -packages/react-codemod/build/ -packages/react-codemod/node_modules/ vendor/react-dom.js diff --git a/packages/react-codemod/README.md b/packages/react-codemod/README.md deleted file mode 100644 index 71cb97903f..0000000000 --- a/packages/react-codemod/README.md +++ /dev/null @@ -1,111 +0,0 @@ -## react-codemod - -This repository contains a collection of codemod scripts based for use with -[JSCodeshift](https://github.com/facebook/jscodeshift) that help update React -APIs. - -### Setup & Run - - * `npm install -g jscodeshift` - * `git clone https://github.com/facebook/react.git` or download a zip file - from `https://github.com/facebook/react/archive/master.zip` - * `jscodeshift -t ` - * Use the `-d` option for a dry-run and use `-p` to print the output - for comparison - -### Included Scripts - -`findDOMNode` updates `this.getDOMNode()` or `this.refs.foo.getDOMNode()` -calls inside of `React.createClass` components to `React.findDOMNode(foo)`. Note -that it will only look at code inside of `React.createClass` calls and only -update calls on the component instance or its refs. You can use this script to -update most calls to `getDOMNode` and then manually go through the remaining -calls. - - * `jscodeshift -t react/packages/react-codemod/transforms/findDOMNode.js ` - -`react-to-react-dom` updates code for the split of the `react` and `react-dom` -packages (e.g., `React.render` to `ReactDOM.render`). It looks for -`require('react')` and replaces the appropriate property accesses using -`require('react-dom')`. It does not support ES6 modules or other non-CommonJS -systems. We recommend performing the `findDOMNode` conversion first. - - * `jscodeshift -t react/packages/react-codemod/transforms/react-to-react-dom.js ` - * 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. - -`pure-render-mixin` removes `PureRenderMixin` and inlines -`shouldComponentUpdate` so that the ES2015 class transform can pick up the React -component and turn it into an ES2015 class. NOTE: This currently only works if you -are using the master version (>0.13.1) of React as it is using -`React.addons.shallowCompare` - - * `jscodeshift -t react/packages/react-codemod/transforms/pure-render-mixin.js ` - * If `--mixin-name=` is specified it will look for the specified name - instead of `PureRenderMixin`. Note that it is not possible to use a - namespaced name for the mixin. `mixins: [React.addons.PureRenderMixin]` will - not currently work. - -`class` transforms `React.createClass` calls into ES2015 classes. - - * `jscodeshift -t react/packages/react-codemod/transforms/class.js ` - * If `--no-super-class` is specified it will not extend - `React.Component` if `setState` and `forceUpdate` aren't being called in a - class. We do recommend always extending from `React.Component`, especially - if you are using or planning to use [Flow](http://flowtype.org/). Also make - sure you are not calling `setState` anywhere outside of your component. - -These three scripts take an option `--no-explicit-require` if you don't have a -`require('React')` statement in your code files and if you access React as a -global. - -### Explanation of the ES2015 class transform - - * Ignore components with calls to deprecated APIs. This is very defensive, if - the script finds any identifiers called `isMounted`, `getDOMNode`, - `replaceProps`, `replaceState` or `setProps` it will skip the component. - * Replaces `var A = React.createClass(spec)` with - `class A (extends React.Component) {spec}`. - * Pulls out all statics defined on `statics` plus the few special cased - statics like `propTypes`, `childContextTypes`, `contextTypes` and - `displayName` and assigns them after the class is created. - `class A {}; A.foo = bar;` - * Takes `getDefaultProps` and inlines it as a static `defaultProps`. - If `getDefaultProps` is defined as a function with a single statement that - returns an object, it optimizes and transforms - `getDefaultProps() { return {foo: 'bar'}; }` into - `A.defaultProps = {foo: 'bar'};`. If `getDefaultProps` contains more than - one statement it will transform into a self-invoking function like this: - `A.defaultProps = function() {…}();`. Note that this means that the function - will be executed only a single time per app-lifetime. In practice this - hasn't caused any issues – `getDefaultProps` should not contain any - side-effects. - * Binds class methods to the instance if methods are referenced without being - called directly. It checks for `this.foo` but also traces variable - assignments like `var self = this; self.foo`. It does not bind functions - from the React API and ignores functions that are being called directly - (unless it is both called directly and passed around to somewhere else) - * Creates a constructor if necessary. This is necessary if either - `getInitialState` exists in the `React.createClass` spec OR if functions - need to be bound to the instance. - * When `--no-super-class` is passed it only optionally extends - `React.Component` when `setState` or `forceUpdate` are used within the - class. - -The constructor logic is as follows: - * Call `super(props, context)` if the base class needs to be extended. - * Bind all functions that are passed around, - like `this.foo = this.foo.bind(this)` - * Inline `getInitialState` (and remove `getInitialState` from the spec). It - also updates access of `this.props.foo` to `props.foo` and adds `props` as - argument to the constructor. This is necessary in the case when the base - class does not need to be extended where `this.props` will only be set by - React after the constructor has been run. - * Changes `return StateObject` from `getInitialState` to assign `this.state` - directly. - -### Recast Options - -Options to [recast](https://github.com/benjamn/recast)'s printer can be provided -through the `printOptions` command line argument - - * `jscodeshift -t transform.js --printOptions='{"quote":"double"}'` diff --git a/packages/react-codemod/package.json b/packages/react-codemod/package.json deleted file mode 100644 index 069768edee..0000000000 --- a/packages/react-codemod/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "react-codemod", - "version": "3.0.0", - "description": "React codemod scripts", - "license": "BSD-3-Clause", - "repository": { - "type": "git", - "url": "https://github.com/facebook/react" - }, - "scripts": { - "test": "jest" - }, - "dependencies": { - "jscodeshift": "^0.3.7" - }, - "devDependencies": { - "babel-jest": "^5.3.0", - "jest-cli": "^0.5.1" - }, - "jest": { - "scriptPreprocessor": "./node_modules/babel-jest", - "testPathDirs": [ - "test" - ] - } -} diff --git a/packages/react-codemod/test/__tests__/transform-tests.js b/packages/react-codemod/test/__tests__/transform-tests.js deleted file mode 100644 index cc5c90753b..0000000000 --- a/packages/react-codemod/test/__tests__/transform-tests.js +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Copyright 2013-2015, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -"use strict"; - -jest.autoMockOff(); - -var fs = require('fs'); -var jscodeshift = require('jscodeshift'); - -function read(fileName) { - return fs.readFileSync(__dirname + '/../' + fileName, 'utf8'); -} - -function test(transformName, testFileName, options) { - var path = testFileName + '.js'; - var source = read(testFileName + '.js'); - var output = read(testFileName + '.output.js'); - - var transform = require('../../transforms/' + transformName); - expect( - (transform({path, source}, {jscodeshift}, options || {}) || '').trim() - ).toEqual( - output.trim() - ); -} - -describe('Transform Tests', () => { - - it('transforms the "findDOMNode" tests correctly', () => { - test('findDOMNode', 'findDOMNode-test'); - }); - - it('transforms the "pure-render-mixin" tests correctly', () => { - test('pure-render-mixin', 'pure-render-mixin-test'); - - test('pure-render-mixin', 'pure-render-mixin-test2'); - - test('pure-render-mixin', 'pure-render-mixin-test3'); - - test('pure-render-mixin', 'pure-render-mixin-test4', { - 'mixin-name': 'ReactComponentWithPureRenderMixin', - }); - }); - - it('transforms the "class" tests correctly', () => { - test('class', 'class-test'); - - test('class', 'class-test2', { - 'super-class': false - }); - - test('class', 'class-test3'); - - }); - - it('transforms exports class', () => { - test('class', 'export-default-class-test'); - }); - -}); diff --git a/packages/react-codemod/test/class-test.js b/packages/react-codemod/test/class-test.js deleted file mode 100644 index fd9533c15f..0000000000 --- a/packages/react-codemod/test/class-test.js +++ /dev/null @@ -1,133 +0,0 @@ -'use strict'; - -var React = require('React'); -var Relay = require('Relay'); - -var Image = require('Image.react'); - -/* - * Multiline - */ -var MyComponent = React.createClass({ - getInitialState: function() { - var x = this.props.foo; - return { - heyoo: 23, - }; - }, - - foo: function() { - this.setState({heyoo: 24}); - } -}); - -// Class comment -var MyComponent2 = React.createClass({ - getDefaultProps: function() { - return {a: 1}; - }, - foo: function() { - pass(this.foo); - this.forceUpdate(); - } -}); - -var MyComponent3 = React.createClass({ - statics: { - someThing: 10, - foo: function() {}, - }, - propTypes: { - highlightEntities: React.PropTypes.bool, - linkifyEntities: React.PropTypes.bool, - text: React.PropTypes.shape({ - text: React.PropTypes.string, - ranges: React.PropTypes.array - }).isRequired - }, - - getDefaultProps: function() { - foo(); - return { - linkifyEntities: true, - highlightEntities: false - }; - }, - - getInitialState: function() { - this.props.foo(); - return { - heyoo: 23, - }; - }, - - _renderText: function(text) { - return ; - }, - - _renderImageRange: function(text, range) { - var image = range.image; - if (image) { - return ( - - ); - } - }, - - autobindMe: function() {}, - dontAutobindMe: function() {}, - - // Function comment - _renderRange: function(text, range) { - var self = this; - - self.dontAutobindMe(); - call(self.autobindMe); - - var type = rage.type; - var {highlightEntities} = this.props; - - if (type === 'ImageAtRange') { - return this._renderImageRange(text, range); - } - - if (this.props.linkifyEntities) { - text = - - {text} - ; - } else { - text = {text}; - } - - return text; - }, - - /* This is a comment */ - render: function() { - var content = this.props.text; - return ( - - ); - } -}); - -var MyComponent4 = React.createClass({ - foo: callMeMaybe(), - render: function() {}, -}); - -module.exports = Relay.createContainer(MyComponent, { - queries: { - me: Relay.graphql`this is not graphql`, - } -}); diff --git a/packages/react-codemod/test/class-test.output.js b/packages/react-codemod/test/class-test.output.js deleted file mode 100644 index 5862308127..0000000000 --- a/packages/react-codemod/test/class-test.output.js +++ /dev/null @@ -1,144 +0,0 @@ -'use strict'; - -var React = require('React'); -var Relay = require('Relay'); - -var Image = require('Image.react'); - -/* - * Multiline - */ -class MyComponent extends React.Component { - constructor(props, context) { - super(props, context); - var x = props.foo; - - this.state = { - heyoo: 23, - }; - } - - foo() { - this.setState({heyoo: 24}); - } -} - -// Class comment -class MyComponent2 extends React.Component { - constructor(props, context) { - super(props, context); - this.foo = this.foo.bind(this); - } - - foo() { - pass(this.foo); - this.forceUpdate(); - } -} - -MyComponent2.defaultProps = {a: 1}; - -class MyComponent3 extends React.Component { - constructor(props, context) { - super(props, context); - this._renderRange = this._renderRange.bind(this); - this._renderText = this._renderText.bind(this); - this.autobindMe = this.autobindMe.bind(this); - props.foo(); - - this.state = { - heyoo: 23, - }; - } - - _renderText(text) { - return ; - } - - _renderImageRange(text, range) { - var image = range.image; - if (image) { - return ( - - ); - } - } - - autobindMe() {} - dontAutobindMe() {} - - // Function comment - _renderRange(text, range) { - var self = this; - - self.dontAutobindMe(); - call(self.autobindMe); - - var type = rage.type; - var {highlightEntities} = this.props; - - if (type === 'ImageAtRange') { - return this._renderImageRange(text, range); - } - - if (this.props.linkifyEntities) { - text = - - {text} - ; - } else { - text = {text}; - } - - return text; - } - - /* This is a comment */ - render() { - var content = this.props.text; - return ( - - ); - } -} - -MyComponent3.defaultProps = function() { - foo(); - return { - linkifyEntities: true, - highlightEntities: false - }; -}(); - -MyComponent3.foo = function() {}; - -MyComponent3.propTypes = { - highlightEntities: React.PropTypes.bool, - linkifyEntities: React.PropTypes.bool, - text: React.PropTypes.shape({ - text: React.PropTypes.string, - ranges: React.PropTypes.array - }).isRequired -}; - -MyComponent3.someThing = 10; - -var MyComponent4 = React.createClass({ - foo: callMeMaybe(), - render: function() {}, -}); - -module.exports = Relay.createContainer(MyComponent, { - queries: { - me: Relay.graphql`this is not graphql`, - } -}); diff --git a/packages/react-codemod/test/class-test2.js b/packages/react-codemod/test/class-test2.js deleted file mode 100644 index 7773f3cd29..0000000000 --- a/packages/react-codemod/test/class-test2.js +++ /dev/null @@ -1,33 +0,0 @@ -'use strict'; - -var React = require('React'); - -var IdontNeedAParent = React.createClass({ - render: function() { - return
; - } -}); - -var ButIDo = React.createClass({ - foo: function() { - this.setState({banana: '?'}); - }, - - render: function() { - return
; - } -}); - -var IAccessProps = React.createClass({ - - getInitialState: function() { - return { - relayReleaseDate: this.props.soon, - }; - }, - - render: function() { - return - } - -}); diff --git a/packages/react-codemod/test/class-test2.output.js b/packages/react-codemod/test/class-test2.output.js deleted file mode 100644 index 9021d6ffa7..0000000000 --- a/packages/react-codemod/test/class-test2.output.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict'; - -var React = require('React'); - -class IdontNeedAParent { - render() { - return
; - } -} - -class ButIDo extends React.Component { - foo() { - this.setState({banana: '?'}); - } - - render() { - return
; - } -} - -class IAccessProps { - constructor(props) { - this.state = { - relayReleaseDate: props.soon, - }; - } - - render() { - return - } -} diff --git a/packages/react-codemod/test/class-test3.js b/packages/react-codemod/test/class-test3.js deleted file mode 100644 index ba03cf8dbd..0000000000 --- a/packages/react-codemod/test/class-test3.js +++ /dev/null @@ -1,20 +0,0 @@ -'use strict'; - -var React = require('React'); - -// Comment -module.exports = React.createClass({ - propTypes: { - foo: React.PropTypes.bool, - }, - - getInitialState: function() { - return { - foo: 'bar', - }; - }, - - render: function() { - return
; - } -}); diff --git a/packages/react-codemod/test/class-test3.output.js b/packages/react-codemod/test/class-test3.output.js deleted file mode 100644 index 68803e4196..0000000000 --- a/packages/react-codemod/test/class-test3.output.js +++ /dev/null @@ -1,22 +0,0 @@ -'use strict'; - -var React = require('React'); - -// Comment -module.exports = class extends React.Component { - constructor(props, context) { - super(props, context); - - this.state = { - foo: 'bar', - }; - } - - render() { - return
; - } -}; - -module.exports.propTypes = { - foo: React.PropTypes.bool, -}; diff --git a/packages/react-codemod/test/export-default-class-test.js b/packages/react-codemod/test/export-default-class-test.js deleted file mode 100644 index 676bfc51c7..0000000000 --- a/packages/react-codemod/test/export-default-class-test.js +++ /dev/null @@ -1,19 +0,0 @@ -'use strict'; - -import React from 'React'; - -export default React.createClass({ - getInitialState: function() { - return { - foo: 'bar', - }; - }, - - propTypes: { - foo: React.PropTypes.string, - }, - - render: function() { - return
; - } -}); diff --git a/packages/react-codemod/test/export-default-class-test.output.js b/packages/react-codemod/test/export-default-class-test.output.js deleted file mode 100644 index 26e4b8107a..0000000000 --- a/packages/react-codemod/test/export-default-class-test.output.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict'; - -import React from 'React'; - -export default class extends React.Component { - constructor(props, context) { - super(props, context); - - this.state = { - foo: 'bar', - }; - } - - static propTypes = { - foo: React.PropTypes.string, - }; - - render() { - return
; - } -} diff --git a/packages/react-codemod/test/findDOMNode-test.js b/packages/react-codemod/test/findDOMNode-test.js deleted file mode 100644 index fbdb0a95f6..0000000000 --- a/packages/react-codemod/test/findDOMNode-test.js +++ /dev/null @@ -1,34 +0,0 @@ -'use strict'; - -var React = require('React'); - -var Composer = React.createClass({ - componentWillReceiveProps: function(nextProps) { - this.getDOMNode(); - return foo(this.refs.input.getDOMNode()); - }, - - foo: function() { - var ref = 'foo'; - var element = this.refs[ref]; - var domNode = element.getDOMNode(); - }, - - bar: function() { - var thing = this.refs.foo; - thing.getDOMNode(); - }, - - foobar: function() { - passThisOn(this.refs.main.refs.list.getDOMNode()); - } -}); - -var SomeDialog = React.createClass({ - render: function() { - call(this.refs.SomeThing); - return ( -
- ); - } -}); diff --git a/packages/react-codemod/test/findDOMNode-test.output.js b/packages/react-codemod/test/findDOMNode-test.output.js deleted file mode 100644 index 45bfca5bbb..0000000000 --- a/packages/react-codemod/test/findDOMNode-test.output.js +++ /dev/null @@ -1,34 +0,0 @@ -'use strict'; - -var React = require('React'); - -var Composer = React.createClass({ - componentWillReceiveProps: function(nextProps) { - React.findDOMNode(this); - return foo(React.findDOMNode(this.refs.input)); - }, - - foo: function() { - var ref = 'foo'; - var element = this.refs[ref]; - var domNode = React.findDOMNode(element); - }, - - bar: function() { - var thing = this.refs.foo; - React.findDOMNode(thing); - }, - - foobar: function() { - passThisOn(React.findDOMNode(this.refs.main.refs.list)); - } -}); - -var SomeDialog = React.createClass({ - render: function() { - call(this.refs.SomeThing); - return ( -
- ); - } -}); diff --git a/packages/react-codemod/test/pure-render-mixin-test.js b/packages/react-codemod/test/pure-render-mixin-test.js deleted file mode 100644 index dcb374328f..0000000000 --- a/packages/react-codemod/test/pure-render-mixin-test.js +++ /dev/null @@ -1,45 +0,0 @@ -var React = require('react/addons'); - -var PureRenderMixin = React.addons.PureRenderMixin; - -var MyComponent = React.createClass({ - mixins: [PureRenderMixin], - - render: function() { - return
; - } -}); - -var MyMixedComponent = React.createClass({ - mixins: [PureRenderMixin, SomeOtherMixin], - - render: function() { - return
; - } -}); - -var MyFooComponent = React.createClass({ - mixins: [PureRenderMixin, SomeOtherMixin], - - render: function() { - return
; - }, - - foo: function() { - - } -}); - -var MyStupidComponent = React.createClass({ - mixins: [PureRenderMixin], - - shouldComponentUpdate: function() { - return !!'wtf is this doing here?'; - }, - - render: function() { - return
; - } -}); - -module.exports = MyComponent; diff --git a/packages/react-codemod/test/pure-render-mixin-test.output.js b/packages/react-codemod/test/pure-render-mixin-test.output.js deleted file mode 100644 index 31fdec6c87..0000000000 --- a/packages/react-codemod/test/pure-render-mixin-test.output.js +++ /dev/null @@ -1,55 +0,0 @@ -var React = require('react/addons'); - -var PureRenderMixin = React.addons.PureRenderMixin; - -var MyComponent = React.createClass({ - shouldComponentUpdate: function(nextProps, nextState) { - return React.addons.shallowCompare(this, nextProps, nextState); - }, - - render: function() { - return
; - } -}); - -var MyMixedComponent = React.createClass({ - mixins: [SomeOtherMixin], - - shouldComponentUpdate: function(nextProps, nextState) { - return React.addons.shallowCompare(this, nextProps, nextState); - }, - - render: function() { - return
; - } -}); - -var MyFooComponent = React.createClass({ - mixins: [SomeOtherMixin], - - render: function() { - return
; - }, - - foo: function() { - - }, - - shouldComponentUpdate: function(nextProps, nextState) { - return React.addons.shallowCompare(this, nextProps, nextState); - } -}); - -var MyStupidComponent = React.createClass({ - mixins: [PureRenderMixin], - - shouldComponentUpdate: function() { - return !!'wtf is this doing here?'; - }, - - render: function() { - return
; - } -}); - -module.exports = MyComponent; diff --git a/packages/react-codemod/test/pure-render-mixin-test2.js b/packages/react-codemod/test/pure-render-mixin-test2.js deleted file mode 100644 index e5acfdabe5..0000000000 --- a/packages/react-codemod/test/pure-render-mixin-test2.js +++ /dev/null @@ -1,13 +0,0 @@ -var React = require('react/addons'); - -var PureRenderMixin = React.addons.PureRenderMixin; - -var MyComponent = React.createClass({ - mixins: [PureRenderMixin], - - render: function() { - return
; - } -}); - -module.exports = MyComponent; diff --git a/packages/react-codemod/test/pure-render-mixin-test2.output.js b/packages/react-codemod/test/pure-render-mixin-test2.output.js deleted file mode 100644 index 90d0a78208..0000000000 --- a/packages/react-codemod/test/pure-render-mixin-test2.output.js +++ /dev/null @@ -1,13 +0,0 @@ -var React = require('react/addons'); - -var MyComponent = React.createClass({ - shouldComponentUpdate: function(nextProps, nextState) { - return React.addons.shallowCompare(this, nextProps, nextState); - }, - - render: function() { - return
; - } -}); - -module.exports = MyComponent; diff --git a/packages/react-codemod/test/pure-render-mixin-test3.js b/packages/react-codemod/test/pure-render-mixin-test3.js deleted file mode 100644 index 4044f4779c..0000000000 --- a/packages/react-codemod/test/pure-render-mixin-test3.js +++ /dev/null @@ -1,14 +0,0 @@ -var React = require('react/addons'); - -var Foo = 'Foo'; -var PureRenderMixin = React.addons.PureRenderMixin; - -var MyComponent = React.createClass({ - mixins: [PureRenderMixin], - - render: function() { - return
; - } -}); - -module.exports = MyComponent; diff --git a/packages/react-codemod/test/pure-render-mixin-test3.output.js b/packages/react-codemod/test/pure-render-mixin-test3.output.js deleted file mode 100644 index 37cc2fe1d3..0000000000 --- a/packages/react-codemod/test/pure-render-mixin-test3.output.js +++ /dev/null @@ -1,15 +0,0 @@ -var React = require('react/addons'); - -var Foo = 'Foo'; - -var MyComponent = React.createClass({ - shouldComponentUpdate: function(nextProps, nextState) { - return React.addons.shallowCompare(this, nextProps, nextState); - }, - - render: function() { - return
; - } -}); - -module.exports = MyComponent; diff --git a/packages/react-codemod/test/pure-render-mixin-test4.js b/packages/react-codemod/test/pure-render-mixin-test4.js deleted file mode 100644 index cbf384e0f4..0000000000 --- a/packages/react-codemod/test/pure-render-mixin-test4.js +++ /dev/null @@ -1,12 +0,0 @@ -var React = require('React'); -var ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin'); - -var MyComponent = React.createClass({ - mixins: [ReactComponentWithPureRenderMixin], - - render: function() { - return
; - } -}); - -module.exports = MyComponent; diff --git a/packages/react-codemod/test/pure-render-mixin-test4.output.js b/packages/react-codemod/test/pure-render-mixin-test4.output.js deleted file mode 100644 index 14c9cf2f94..0000000000 --- a/packages/react-codemod/test/pure-render-mixin-test4.output.js +++ /dev/null @@ -1,13 +0,0 @@ -var React = require('React'); - -var MyComponent = React.createClass({ - shouldComponentUpdate: function(nextProps, nextState) { - return React.addons.shallowCompare(this, nextProps, nextState); - }, - - render: function() { - return
; - } -}); - -module.exports = MyComponent; diff --git a/packages/react-codemod/transforms/class.js b/packages/react-codemod/transforms/class.js deleted file mode 100644 index 782fff5cac..0000000000 --- a/packages/react-codemod/transforms/class.js +++ /dev/null @@ -1,555 +0,0 @@ -/** - * Copyright 2013-2015, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -'use strict'; - -module.exports = (file, api, options) => { - const j = api.jscodeshift; - - require('./utils/array-polyfills'); - const ReactUtils = require('./utils/ReactUtils')(j); - - const printOptions = - options.printOptions || {quote: 'single', trailingComma: true}; - const root = j(file.source); - - const AUTOBIND_IGNORE_KEYS = { - componentDidMount: true, - componentDidUpdate: true, - componentWillReceiveProps: true, - componentWillMount: true, - componentWillUpdate: true, - componentWillUnmount: true, - getDefaultProps: true, - getInitialState: true, - render: true, - shouldComponentUpdate: true, - }; - - const BASE_COMPONENT_METHODS = ['setState', 'forceUpdate']; - - const DEFAULT_PROPS_FIELD = 'getDefaultProps'; - const DEFAULT_PROPS_KEY = 'defaultProps'; - const GET_INITIAL_STATE_FIELD = 'getInitialState'; - - const DEPRECATED_APIS = [ - 'getDOMNode', - 'isMounted', - 'replaceProps', - 'replaceState', - 'setProps', - ]; - - const STATIC_KEY = 'statics'; - - const STATIC_KEYS = { - childContextTypes: true, - contextTypes: true, - displayName: true, - propTypes: true, - }; - - // --------------------------------------------------------------------------- - // Checks if the module uses mixins or accesses deprecated APIs. - const checkDeprecatedAPICalls = classPath => - DEPRECATED_APIS.reduce( - (acc, name) => - acc + j(classPath) - .find(j.Identifier, {name}) - .size(), - 0 - ) > 0; - - const callsDeprecatedAPIs = classPath => { - if (checkDeprecatedAPICalls(classPath)) { - console.log( - file.path + ': `' + ReactUtils.getComponentName(classPath) + '` ' + - 'was skipped because of deprecated API calls. Remove calls to ' + - DEPRECATED_APIS.join(', ') + ' in your React component and re-run ' + - 'this script.' - ); - return false; - } - return true; - }; - - const canConvertToClass = classPath => { - const specPath = ReactUtils.getReactCreateClassSpec(classPath); - const invalidProperties = specPath.properties.filter(prop => ( - !prop.key.name || ( - !STATIC_KEYS[prop.key.name] && - STATIC_KEY != prop.key.name && - !filterDefaultPropsField(prop) && - !filterGetInitialStateField(prop) && - !isFunctionExpression(prop) - ) - )); - - if (invalidProperties.length) { - const invalidText = invalidProperties - .map(prop => prop.key.name ? prop.key.name : prop.key) - .join(', '); - console.log( - file.path + ': `' + ReactUtils.getComponentName(classPath) + '` ' + - 'was skipped because of invalid field(s) `' + invalidText + '` on ' + - 'the React component. Remove any right-hand-side expressions that ' + - 'are not simple, like: `componentWillUpdate: createWillUpdate()` or ' + - '`render: foo ? renderA : renderB`.' - ); - } - return !invalidProperties.length; - }; - - const hasMixins = classPath => { - if (ReactUtils.hasMixins(classPath)) { - console.log( - file.path + ': `' + ReactUtils.getComponentName(classPath) + '` ' + - 'was skipped because of mixins.' - ); - return false; - } - return true; - }; - - // --------------------------------------------------------------------------- - // Helpers - const createFindPropFn = prop => property => ( - property.key && - property.key.type === 'Identifier' && - property.key.name === prop - ); - - const filterDefaultPropsField = node => - createFindPropFn(DEFAULT_PROPS_FIELD)(node); - - const filterGetInitialStateField = node => - createFindPropFn(GET_INITIAL_STATE_FIELD)(node); - - const findGetDefaultProps = specPath => - specPath.properties.find(createFindPropFn(DEFAULT_PROPS_FIELD)); - - const findGetInitialState = specPath => - specPath.properties.find(createFindPropFn(GET_INITIAL_STATE_FIELD)); - - // This is conservative; only check for `setState` and `forceUpdate` literals - // instead of also checking which objects they are called on. - const shouldExtendReactComponent = classPath => - BASE_COMPONENT_METHODS.some(name => ( - j(classPath) - .find(j.Identifier, {name}) - .size() > 0 - )); - - const withComments = (to, from) => { - to.comments = from.comments; - return to; - }; - - // --------------------------------------------------------------------------- - // Collectors - const isFunctionExpression = node => ( - node.key && - node.key.type === 'Identifier' && - node.value && - node.value.type === 'FunctionExpression' - ); - - const collectStatics = specPath => { - const statics = specPath.properties.find(createFindPropFn('statics')); - const staticsObject = - (statics && statics.value && statics.value.properties) || []; - - const getDefaultProps = findGetDefaultProps(specPath); - if (getDefaultProps) { - staticsObject.push(createDefaultProps(getDefaultProps)); - } - - return ( - staticsObject.concat(specPath.properties.filter(property => - property.key && STATIC_KEYS[property.key.name] - )) - .sort((a, b) => a.key.name < b.key.name) - ); - }; - - const collectFunctions = specPath => specPath.properties - .filter(prop => - !(filterDefaultPropsField(prop) || filterGetInitialStateField(prop)) - ) - .filter(isFunctionExpression); - - const findAutobindNamesFor = (subtree, fnNames, literalOrIdentifier) => { - const node = literalOrIdentifier; - const autobindNames = {}; - - j(subtree) - .find(j.MemberExpression, { - object: node.name ? { - type: node.type, - name: node.name, - } : {type: node.type}, - property: { - type: 'Identifier', - }, - }) - .filter(path => path.value.property && fnNames[path.value.property.name]) - .filter(path => { - const call = path.parent.value; - return !( - call && - call.type === 'CallExpression' && - call.callee.type === 'MemberExpression' && - call.callee.object.type === node.type && - call.callee.object.name === node.name && - call.callee.property.type === 'Identifier' && - call.callee.property.name === path.value.property.name - ); - }) - .forEach(path => autobindNames[path.value.property.name] = true); - - return Object.keys(autobindNames); - }; - - const collectAutoBindFunctions = (functions, classPath) => { - const fnNames = {}; - functions - .filter(fn => !AUTOBIND_IGNORE_KEYS[fn.key.name]) - .forEach(fn => fnNames[fn.key.name] = true); - - const autobindNames = {}; - const add = name => autobindNames[name] = true; - - // Find `this.` - findAutobindNamesFor(classPath, fnNames, j.thisExpression()).forEach(add); - - // Find `self.` if `self = this` - j(classPath) - .findVariableDeclarators() - .filter(path => ( - path.value.id.type === 'Identifier' && - path.value.init && - path.value.init.type === 'ThisExpression' - )) - .forEach(path => - findAutobindNamesFor( - j(path).closest(j.FunctionExpression).get(), - fnNames, - path.value.id - ).forEach(add) - ); - - return Object.keys(autobindNames).sort(); - }; - - // --------------------------------------------------------------------------- - // Boom! - const createMethodDefinition = fn => - withComments(j.methodDefinition( - 'method', - fn.key, - fn.value - ), fn); - - const createBindAssignment = name => - j.expressionStatement( - j.assignmentExpression( - '=', - j.memberExpression( - j.thisExpression(), - j.identifier(name), - false - ), - j.callExpression( - j.memberExpression( - j.memberExpression( - j.thisExpression(), - j.identifier(name), - false - ), - j.identifier('bind'), - false - ), - [j.thisExpression()] - ) - ) - ); - - const createSuperCall = shouldAddSuperCall => - !shouldAddSuperCall ? - [] : - [ - j.expressionStatement( - j.callExpression( - j.identifier('super'), - [j.identifier('props'), j.identifier('context')] - ) - ), - ]; - - const updatePropsAccess = getInitialState => - getInitialState ? - j(getInitialState) - .find(j.MemberExpression, { - object: { - type: 'ThisExpression', - }, - property: { - type: 'Identifier', - name: 'props', - }, - }) - .forEach(path => j(path).replaceWith(j.identifier('props'))) - .size() > 0 : - false; - - const inlineGetInitialState = getInitialState => { - if (!getInitialState) { - return []; - } - - return getInitialState.value.body.body.map(statement => { - if (statement.type === 'ReturnStatement') { - return j.expressionStatement( - j.assignmentExpression( - '=', - j.memberExpression( - j.thisExpression(), - j.identifier('state'), - false - ), - statement.argument - ) - ); - } - - return statement; - }); - }; - - const createConstructorArgs = (shouldAddSuperClass, hasPropsAccess) => { - if (shouldAddSuperClass) { - return [j.identifier('props'), j.identifier('context')]; - } else if (hasPropsAccess) { - return [j.identifier('props')]; - } else { - return []; - } - }; - - const createConstructor = ( - getInitialState, - autobindFunctions, - shouldAddSuperClass - ) => { - if (!getInitialState && !autobindFunctions.length) { - return []; - } - - const hasPropsAccess = updatePropsAccess(getInitialState); - return [ - createMethodDefinition({ - key: j.identifier('constructor'), - value: j.functionExpression( - null, - createConstructorArgs(shouldAddSuperClass, hasPropsAccess), - j.blockStatement( - [].concat( - createSuperCall(shouldAddSuperClass), - autobindFunctions.map(createBindAssignment), - inlineGetInitialState(getInitialState) - ) - ) - ), - }), - ]; - }; - - const createESClass = ( - name, - properties, - getInitialState, - autobindFunctions, - comments, - shouldAddSuperClass - ) => - withComments(j.classDeclaration( - name ? j.identifier(name) : null, - j.classBody( - [].concat( - createConstructor( - getInitialState, - autobindFunctions, - shouldAddSuperClass - ), - properties - ) - ), - shouldAddSuperClass ? j.memberExpression( - j.identifier('React'), - j.identifier('Component'), - false - ) : null - ), {comments}); - - const createStaticAssignment = (name, staticProperty) => - withComments(j.expressionStatement( - j.assignmentExpression( - '=', - j.memberExpression( - name, - j.identifier(staticProperty.key.name), - false - ), - staticProperty.value - ) - ), staticProperty); - - const createStaticAssignmentExpressions = (name, statics) => - statics.map(staticProperty => createStaticAssignment(name, staticProperty)); - - const createStaticClassProperty = staticProperty => - withComments(j.classProperty( - j.identifier(staticProperty.key.name), - staticProperty.value, - null, - true - ), staticProperty); - - const createStaticClassProperties = statics => - statics.map(createStaticClassProperty); - - const hasSingleReturnStatement = value => ( - value.type === 'FunctionExpression' && - value.body && - value.body.type === 'BlockStatement' && - value.body.body && - value.body.body.length === 1 && - value.body.body[0].type === 'ReturnStatement' && - value.body.body[0].argument && - value.body.body[0].argument.type === 'ObjectExpression' - ); - - const createDefaultPropsValue = value => { - if (hasSingleReturnStatement(value)) { - return value.body.body[0].argument; - } else { - return j.callExpression( - value, - [] - ); - } - }; - - const createDefaultProps = prop => - withComments( - j.property( - 'init', - j.identifier(DEFAULT_PROPS_KEY), - createDefaultPropsValue(prop.value) - ), - prop - ); - - const getComments = classPath => { - if (classPath.value.comments) { - return classPath.value.comments; - } - const declaration = j(classPath).closest(j.VariableDeclaration); - if (declaration.size()) { - return declaration.get().value.comments; - } - return null; - }; - - const createModuleExportsMemberExpression = () => - j.memberExpression( - j.identifier('module'), - j.identifier('exports'), - false - ); - - const updateToClass = (classPath, shouldExtend, type) => { - const specPath = ReactUtils.getReactCreateClassSpec(classPath); - const name = ReactUtils.getComponentName(classPath); - const statics = collectStatics(specPath); - const functions = collectFunctions(specPath); - const comments = getComments(classPath); - - const autobindFunctions = collectAutoBindFunctions(functions, classPath); - const getInitialState = findGetInitialState(specPath); - - const staticName = - name ? j.identifier(name) : createModuleExportsMemberExpression(); - - var path; - if (type == 'moduleExports' || type == 'exportDefault') { - path = ReactUtils.findReactCreateClassCallExpression(classPath); - } else { - path = j(classPath).closest(j.VariableDeclaration); - } - - const properties = - (type == 'exportDefault') ? createStaticClassProperties(statics) : []; - - path.replaceWith( - createESClass( - name, - properties.concat(functions.map(createMethodDefinition)), - getInitialState, - autobindFunctions, - comments, - shouldExtend || shouldExtendReactComponent(classPath) - ) - ); - - if (type == 'moduleExports' || type == 'var') { - const staticAssignments = createStaticAssignmentExpressions( - staticName, - statics - ); - if (type == 'moduleExports') { - root.get().value.program.body.push(...staticAssignments); - } else { - path.insertAfter(staticAssignments.reverse()); - } - } - }; - - if ( - !options['explicit-require'] || ReactUtils.hasReact(root) - ) { - const apply = (path, type) => - path - .filter(hasMixins) - .filter(callsDeprecatedAPIs) - .filter(canConvertToClass) - .forEach(classPath => updateToClass( - classPath, - !options['super-class'], - type - )); - - const didTransform = ( - apply(ReactUtils.findReactCreateClass(root), 'var') - .size() + - apply(ReactUtils.findReactCreateClassModuleExports(root), 'moduleExports') - .size() + - apply(ReactUtils.findReactCreateClassExportDefault(root), 'exportDefault') - .size() - ) > 0; - - if (didTransform) { - return root.toSource(printOptions); - } - - } - - return null; -}; diff --git a/packages/react-codemod/transforms/findDOMNode.js b/packages/react-codemod/transforms/findDOMNode.js deleted file mode 100644 index 3c925b226c..0000000000 --- a/packages/react-codemod/transforms/findDOMNode.js +++ /dev/null @@ -1,144 +0,0 @@ -/** - * Copyright 2013-2015, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -'use strict'; - -function getDOMNodeToFindDOMNode(file, api, options) { - const j = api.jscodeshift; - - require('./utils/array-polyfills'); - const ReactUtils = require('./utils/ReactUtils')(j); - - const printOptions = - options.printOptions || {quote: 'single', trailingComma: true}; - const root = j(file.source); - - const createReactFindDOMNodeCall = arg => j.callExpression( - j.memberExpression( - j.identifier('React'), - j.identifier('findDOMNode'), - false - ), - [arg] - ); - - const updateRefCall = (path, refName) => { - j(path) - .find(j.CallExpression, { - callee: { - object: { - type: 'Identifier', - name: refName, - }, - property: { - type: 'Identifier', - name: 'getDOMNode', - }, - }, - }) - .forEach(callPath => j(callPath).replaceWith( - createReactFindDOMNodeCall(j.identifier(refName)) - )); - }; - - const updateToFindDOMNode = classPath => { - var sum = 0; - - // this.getDOMNode() - sum += j(classPath) - .find(j.CallExpression, { - callee: { - object: { - type: 'ThisExpression', - }, - property: { - type: 'Identifier', - name: 'getDOMNode', - }, - }, - }) - .forEach(path => j(path).replaceWith( - createReactFindDOMNodeCall(j.thisExpression()) - )) - .size(); - - // this.refs.xxx.getDOMNode() or this.refs.xxx.refs.yyy.getDOMNode() - sum += j(classPath) - .find(j.MemberExpression, { - object: { - type: 'MemberExpression', - object: { - type: 'MemberExpression', - object: { - type: 'ThisExpression', - }, - property: { - type: 'Identifier', - name: 'refs', - }, - }, - }, - }) - .closest(j.CallExpression) - .filter(path => ( - path.value.callee.property && - path.value.callee.property.type === 'Identifier' && - path.value.callee.property.name === 'getDOMNode' - )) - .forEach(path => j(path).replaceWith( - createReactFindDOMNodeCall(path.value.callee.object) - )) - .size(); - - // someVariable.getDOMNode() wherre `someVariable = this.refs.xxx` - sum += j(classPath) - .findVariableDeclarators() - .filter(path => { - const init = path.value.init; - const value = init && init.object; - return ( - value && - value.type === 'MemberExpression' && - value.object && - value.object.type === 'ThisExpression' && - value.property && - value.property.type === 'Identifier' && - value.property.name === 'refs' && - init.property && - init.property.type === 'Identifier' - ); - }) - .forEach(path => j(path) - .closest(j.FunctionExpression) - .forEach(fnPath => updateRefCall(fnPath, path.value.id.name)) - ) - .size(); - - return sum > 0; - }; - - if ( - !options['explicit-require'] || - ReactUtils.hasReact(root) - ) { - const didTransform = ReactUtils - .findReactCreateClass(root) - .filter(updateToFindDOMNode) - .size() > 0; - - if (didTransform) { - return root.toSource(printOptions); - } - } - - return null; -} - -module.exports = getDOMNodeToFindDOMNode; diff --git a/packages/react-codemod/transforms/pure-render-mixin.js b/packages/react-codemod/transforms/pure-render-mixin.js deleted file mode 100644 index f5bc29d214..0000000000 --- a/packages/react-codemod/transforms/pure-render-mixin.js +++ /dev/null @@ -1,188 +0,0 @@ -/** - * Copyright 2013-2015, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -'use strict'; - -function removePureRenderMixin(file, api, options) { - const j = api.jscodeshift; - - require('./utils/array-polyfills'); - const ReactUtils = require('./utils/ReactUtils')(j); - - const printOptions = - options.printOptions || {quote: 'single', trailingComma: true}; - const root = j(file.source); - - const PURE_RENDER_MIXIN = options['mixin-name'] || 'PureRenderMixin'; - const SHOULD_COMPONENT_UPDATE = 'shouldComponentUpdate'; - const NEXT_PROPS = 'nextProps'; - const NEXT_STATE = 'nextState'; - - // --------------------------------------------------------------------------- - // shouldComponentUpdate - const createShouldComponentUpdateFunction = () => - j.functionExpression( - null, - [j.identifier(NEXT_PROPS), j.identifier(NEXT_STATE)], - j.blockStatement([ - j.returnStatement( - j.callExpression( - j.memberExpression( - j.identifier('React'), - j.memberExpression( - j.identifier('addons'), - j.identifier('shallowCompare'), - false - ), - false - ), - [ - j.thisExpression(), - j.identifier(NEXT_PROPS), - j.identifier(NEXT_STATE), - ] - ) - ), - ]) - ); - - const createShouldComponentUpdateProperty = () => - j.property( - 'init', - j.identifier(SHOULD_COMPONENT_UPDATE), - createShouldComponentUpdateFunction() - ); - - const hasShouldComponentUpdate = classPath => - ReactUtils.getReactCreateClassSpec(classPath) - .properties.every(property => - property.key.name !== SHOULD_COMPONENT_UPDATE - ); - - // --------------------------------------------------------------------------- - // Mixin related code - const isPureRenderMixin = node => ( - node.type === 'Identifier' && - node.name === PURE_RENDER_MIXIN - ); - - const hasPureRenderMixin = classPath => { - const spec = ReactUtils.getReactCreateClassSpec(classPath); - const mixin = spec && spec.properties.find(ReactUtils.isMixinProperty); - return mixin && mixin.value.elements.some(isPureRenderMixin); - }; - - const removeMixin = elements => - j.property( - 'init', - j.identifier('mixins'), - j.arrayExpression( - elements.filter(element => !isPureRenderMixin(element)) - ) - ); - - // --------------------------------------------------------------------------- - // Boom! - const insertShouldComponentUpdate = properties => { - const length = properties.length; - const lastProp = properties[length - 1]; - // I wouldn't dare insert at the bottom if the last function is render - if ( - lastProp.key.type === 'Identifier' && - lastProp.key.name === 'render' - ) { - properties.splice( - length - 1, - 1, - createShouldComponentUpdateProperty(), - lastProp - ); - } else { - properties.push(createShouldComponentUpdateProperty()); - } - return properties; - }; - - const cleanupReactComponent = classPath => { - const spec = ReactUtils.getReactCreateClassSpec(classPath); - const properties = spec.properties - .map(property => { - if (ReactUtils.isMixinProperty(property)) { - const elements = property.value.elements; - return (elements.length !== 1) ? removeMixin(elements) : null; - } - return property; - }) - .filter(property => !!property); - - ReactUtils.findReactCreateClassCallExpression(classPath).replaceWith( - ReactUtils.createCreateReactClassCallExpression( - insertShouldComponentUpdate(properties) - ) - ); - }; - - // Remove it if only two or fewer are left: - // var PureRenderMixin = React.addons.PureRenderMixin; - const hasPureRenderIdentifiers = path => - path.find(j.Identifier, { - name: PURE_RENDER_MIXIN, - }).size() > 2; - - const deletePureRenderMixin = path => { - if (hasPureRenderIdentifiers(path)) { - return; - } - - const declaration = path - .findVariableDeclarators(PURE_RENDER_MIXIN) - .closest(j.VariableDeclaration); - - if (declaration.size > 1) { - declaration.forEach(p => - j(p).replaceWith( - j.variableDeclaration( - 'var', - p.value.declarations.filter(isPureRenderMixin) - ) - ) - ); - } else { - // Let's assume the variable declaration happens at the top level - const program = declaration.closest(j.Program).get(); - const body = program.value.body; - const index = body.indexOf(declaration.get().value); - if (index !== -1) { - body.splice(index, 1); - } - } - }; - - if ( - !options['explicit-require'] || - ReactUtils.hasReact(root) - ) { - const didTransform = ReactUtils - .findReactCreateClass(root) - .filter(hasPureRenderMixin) - .filter(hasShouldComponentUpdate) - .forEach(cleanupReactComponent) - .size() > 0; - - if (didTransform) { - deletePureRenderMixin(root); - return root.toSource(printOptions); - } - } - - return null; -} - -module.exports = removePureRenderMixin; diff --git a/packages/react-codemod/transforms/react-to-react-dom.js b/packages/react-codemod/transforms/react-to-react-dom.js deleted file mode 100644 index 0c9ce96c03..0000000000 --- a/packages/react-codemod/transforms/react-to-react-dom.js +++ /dev/null @@ -1,321 +0,0 @@ -/** - * Copyright 2013-2015, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -'use strict'; - -var CORE_PROPERTIES = [ - 'Children', - 'Component', - 'createElement', - 'cloneElement', - 'isValidElement', - 'PropTypes', - 'createClass', - 'createFactory', - 'createMixin', - 'DOM', - '__spread', -]; - -var DOM_PROPERTIES = [ - 'findDOMNode', - 'render', - 'unmountComponentAtNode', - 'unstable_batchedUpdates', - 'unstable_renderSubtreeIntoContainer', -]; - -var DOM_SERVER_PROPERTIES = [ - 'renderToString', - 'renderToStaticMarkup', -]; - -function reportError(node, error) { - throw new Error( - `At ${node.loc.start.line}:${node.loc.start.column}: ${error}` - ); -} - -function isRequire(path, moduleName) { - return ( - path.value.type === 'CallExpression' && - path.value.callee.type === 'Identifier' && - path.value.callee.name === 'require' && - path.value.arguments.length === 1 && - path.value.arguments[0].type === 'Literal' && - path.value.arguments[0].value === moduleName - ); -} - -module.exports = function(file, api) { - var j = api.jscodeshift; - var root = j(file.source); - - [ - ['React', 'ReactDOM', 'ReactDOMServer'], - ['react', 'react-dom', 'react-dom/server'], - ].forEach(function(pair) { - var coreModuleName = pair[0]; - var domModuleName = pair[1]; - var domServerModuleName = pair[2]; - - var domAlreadyDeclared = false; - var domServerAlreadyDeclared = false; - - var coreRequireDeclarator; - root - .find(j.CallExpression) - .filter(p => isRequire(p, coreModuleName)) - .forEach(p => { - var name, scope; - if (p.parent.value.type === 'VariableDeclarator') { - if (p.parent.value.id.type === 'ObjectPattern') { - var pattern = p.parent.value.id; - var all = pattern.properties.every(function(prop) { - if (prop.key.type === 'Identifier') { - name = prop.key.name; - return CORE_PROPERTIES.indexOf(name) !== -1; - } - return false; - }); - if (all) { - // var {PropTypes} = require('React'); so leave alone - return; - } - } - if (coreRequireDeclarator) { - reportError( - p.value, - 'Multiple declarations of React' - ); - } - if (p.parent.value.id.type !== 'Identifier') { - reportError( - p.value, - 'Unexpected destructuring in require of ' + coreModuleName - ); - } - name = p.parent.value.id.name; - scope = p.scope.lookup(name); - if (scope.declares('ReactDOM')) { - console.log('Using existing ReactDOM var in ' + file.path); - domAlreadyDeclared = true; - } - if (scope.declares('ReactDOMServer')) { - console.log('Using existing ReactDOMServer var in ' + file.path); - domServerAlreadyDeclared = true; - } - coreRequireDeclarator = p.parent; - } else if (p.parent.value.type === 'AssignmentExpression') { - if (p.parent.value.left.type !== 'Identifier') { - reportError( - p.value, - 'Unexpected destructuring in require of ' + coreModuleName - ); - } - name = p.parent.value.left.name; - scope = p.scope.lookup(name); - var reactBindings = scope.getBindings()[name]; - if (reactBindings.length !== 1) { - throw new Error( - 'Unexpected number of bindings: ' + reactBindings.length - ); - } - coreRequireDeclarator = reactBindings[0].parent; - if (coreRequireDeclarator.value.init && - !isRequire(coreRequireDeclarator.get('init'), coreModuleName)) { - reportError( - coreRequireDeclarator.value, - 'Unexpected initialization of ' + coreModuleName - ); - } - if (scope.declares('ReactDOM')) { - console.log('Using existing ReactDOM var in ' + file.path); - domAlreadyDeclared = true; - } - if (scope.declares('ReactDOMServer')) { - console.log('Using existing ReactDOMServer var in ' + file.path); - domServerAlreadyDeclared = true; - } - } - }); - if (!coreRequireDeclarator) { - return; - } - - if (!domAlreadyDeclared && - root.find(j.Identifier, {name: 'ReactDOM'}).size() > 0) { - throw new Error( - 'ReactDOM is already defined in a different scope than React' - ); - } - if (!domServerAlreadyDeclared && - root.find(j.Identifier, {name: 'ReactDOMServer'}).size() > 0) { - throw new Error( - 'ReactDOMServer is already defined in a different scope than React' - ); - } - - var coreName = coreRequireDeclarator.value.id.name; - - var processed = new Set(); - var requireAssignments = []; - var coreUses = 0; - var domUses = 0; - var domServerUses = 0; - - root - .find(j.Identifier, {name: coreName}) - .forEach(p => { - if (processed.has(p.value)) { - // https://github.com/facebook/jscodeshift/issues/36 - return; - } - processed.add(p.value); - if (p.parent.value.type === 'MemberExpression' || - p.parent.value.type === 'QualifiedTypeIdentifier') { - var left; - var right; - if (p.parent.value.type === 'MemberExpression') { - left = p.parent.value.object; - right = p.parent.value.property; - } else { - left = p.parent.value.qualification; - right = p.parent.value.id; - } - if (left === p.value) { - // React.foo (or React[foo]) - if (right.type === 'Identifier') { - var name = right.name; - if (CORE_PROPERTIES.indexOf(name) !== -1) { - coreUses++; - } else if (DOM_PROPERTIES.indexOf(name) !== -1) { - domUses++; - j(p).replaceWith(j.identifier('ReactDOM')); - } else if (DOM_SERVER_PROPERTIES.indexOf(name) !== -1) { - domServerUses++; - j(p).replaceWith(j.identifier('ReactDOMServer')); - } else { - throw new Error('Unknown property React.' + name); - } - } - } else if (right === p.value) { - // foo.React, no need to transform - } else { - throw new Error('unimplemented'); - } - } else if (p.parent.value.type === 'VariableDeclarator') { - if (p.parent.value.id === p.value) { - // var React = ...; - } else if (p.parent.value.init === p.value) { - // var ... = React; - var pattern = p.parent.value.id; - if (pattern.type === 'ObjectPattern') { - // var {PropTypes} = React; - // Most of these cases will just be looking at {PropTypes} so this - // is usually a no-op. - var coreProperties = []; - var domProperties = []; - pattern.properties.forEach(function(prop) { - if (prop.key.type === 'Identifier') { - var key = prop.key.name; - if (CORE_PROPERTIES.indexOf(key) !== -1) { - coreProperties.push(prop); - } else if (DOM_PROPERTIES.indexOf(key) !== -1) { - domProperties.push(prop); - } else { - throw new Error( - 'Unknown property React.' + key + ' while destructuring' - ); - } - } else { - throw new Error('unimplemented'); - } - }); - var domDeclarator = j.variableDeclarator( - j.objectPattern(domProperties), - j.identifier('ReactDOM') - ); - if (coreProperties.length && !domProperties.length) { - // nothing to do - coreUses++; - } else if (domProperties.length && !coreProperties.length) { - domUses++; - j(p.parent).replaceWith(domDeclarator); - } else { - coreUses++; - domUses++; - var decl = j(p).closest(j.VariableDeclaration); - decl.insertAfter(j.variableDeclaration( - decl.get().value.kind, - [domDeclarator] - )); - } - } else { - throw new Error('unimplemented'); - } - } else { - throw new Error('unimplemented'); - } - } else if (p.parent.value.type === 'AssignmentExpression') { - if (p.parent.value.left === p.value) { - if (isRequire(p.parent.get('right'), coreModuleName)) { - requireAssignments.push(p.parent); - } else { - reportError( - p.parent.value, - 'Unexpected assignment to ' + coreModuleName - ); - } - } else { - throw new Error('unimplemented'); - } - } else { - reportError(p.value, 'unimplemented ' + p.parent.value.type); - } - }); - - coreUses += root.find(j.JSXElement).size(); - - function insertRequire(name, path) { - var req = j.callExpression( - j.identifier('require'), - [j.literal(path)] - ); - requireAssignments.forEach(function(requireAssignment) { - requireAssignment.parent.insertAfter( - j.expressionStatement( - j.assignmentExpression('=', j.identifier(name), req) - ) - ); - }); - coreRequireDeclarator.parent.insertAfter(j.variableDeclaration( - coreRequireDeclarator.parent.value.kind, - [j.variableDeclarator( - j.identifier(name), - coreRequireDeclarator.value.init ? req : null - )] - )); - } - - if (domServerUses > 0 && !domServerAlreadyDeclared) { - insertRequire('ReactDOMServer', domServerModuleName); - } - if (domUses > 0 && !domAlreadyDeclared) { - insertRequire('ReactDOM', domModuleName); - } - if ((domUses > 0 || domServerUses > 0) && coreUses === 0) { - j(coreRequireDeclarator).remove(); - requireAssignments.forEach(r => j(r).remove()); - } - }); - - return root.toSource({quote: 'single'}); -}; diff --git a/packages/react-codemod/transforms/utils/ReactUtils.js b/packages/react-codemod/transforms/utils/ReactUtils.js deleted file mode 100644 index 7dab7ca4e7..0000000000 --- a/packages/react-codemod/transforms/utils/ReactUtils.js +++ /dev/null @@ -1,160 +0,0 @@ -/** - * Copyright 2013-2015, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -'use strict'; - -module.exports = function(j) { - const REACT_CREATE_CLASS_MEMBER_EXPRESSION = { - type: 'MemberExpression', - object: { - name: 'React', - }, - property: { - name: 'createClass', - }, - }; - - // --------------------------------------------------------------------------- - // Checks if the file requires a certain module - const hasModule = (path, module) => - path - .findVariableDeclarators() - .filter(j.filters.VariableDeclarator.requiresModule(module)) - .size() === 1 || - path - .find(j.ImportDeclaration, { - type: 'ImportDeclaration', - source: { - type: 'Literal', - }, - }) - .filter(declarator => declarator.value.source.value === module) - .size() === 1; - - const hasReact = path => ( - hasModule(path, 'React') || - hasModule(path, 'react') || - hasModule(path, 'react/addons') - ); - - // --------------------------------------------------------------------------- - // Finds all variable declarations that call React.createClass - const findReactCreateClassCallExpression = path => - j(path).find(j.CallExpression, { - callee: REACT_CREATE_CLASS_MEMBER_EXPRESSION, - }); - - const findReactCreateClass = path => - path - .findVariableDeclarators() - .filter(decl => findReactCreateClassCallExpression(decl).size() > 0); - - const findReactCreateClassExportDefault = path => - path.find(j.ExportDefaultDeclaration, { - declaration: { - type: 'CallExpression', - callee: REACT_CREATE_CLASS_MEMBER_EXPRESSION, - }, - }); - - const findReactCreateClassModuleExports = path => - path - .find(j.AssignmentExpression, { - left: { - type: 'MemberExpression', - object: { - type: 'Identifier', - name: 'module', - }, - property: { - type: 'Identifier', - name: 'exports', - }, - }, - right: { - type: 'CallExpression', - callee: REACT_CREATE_CLASS_MEMBER_EXPRESSION, - }, - }); - - // --------------------------------------------------------------------------- - // Finds all classes that extend React.Component - const findReactES6ClassDeclaration = path => - path - .find(j.ClassDeclaration, { - superClass: { - type: 'MemberExpression', - object: { - type: 'Identifier', - name: 'React', - }, - property: { - type: 'Identifier', - name: 'Component', - }, - }, - }); - - // --------------------------------------------------------------------------- - // Checks if the React class has mixins - const isMixinProperty = property => { - const key = property.key; - const value = property.value; - return ( - key.name === 'mixins' && - value.type === 'ArrayExpression' && - Array.isArray(value.elements) && - value.elements.length - ); - }; - - const hasMixins = classPath => { - const spec = getReactCreateClassSpec(classPath); - return spec && spec.properties.some(isMixinProperty); - }; - - // --------------------------------------------------------------------------- - // Others - const getReactCreateClassSpec = classPath => { - var {value} = classPath; - const spec = (value.init || value.right || value.declaration).arguments[0]; - if (spec.type === 'ObjectExpression' && Array.isArray(spec.properties)) { - return spec; - } - }; - - const createCreateReactClassCallExpression = properties => - j.callExpression( - j.memberExpression( - j.identifier('React'), - j.identifier('createClass'), - false - ), - [j.objectExpression(properties)] - ); - - const getComponentName = - classPath => classPath.node.id && classPath.node.id.name; - - return { - createCreateReactClassCallExpression, - findReactES6ClassDeclaration, - findReactCreateClass, - findReactCreateClassCallExpression, - findReactCreateClassModuleExports, - findReactCreateClassExportDefault, - getComponentName, - getReactCreateClassSpec, - hasMixins, - hasModule, - hasReact, - isMixinProperty, - }; -}; diff --git a/packages/react-codemod/transforms/utils/array-polyfills.js b/packages/react-codemod/transforms/utils/array-polyfills.js deleted file mode 100644 index 377de52d6c..0000000000 --- a/packages/react-codemod/transforms/utils/array-polyfills.js +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright 2013-2015, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - - /*eslint-disable no-extend-native*/ - -'use strict'; - -function findIndex(predicate, context) { - if (this == null) { - throw new TypeError( - 'Array.prototype.findIndex called on null or undefined' - ); - } - if (typeof predicate !== 'function') { - throw new TypeError('predicate must be a function'); - } - var list = Object(this); - var length = list.length >>> 0; - for (var i = 0; i < length; i++) { - if (predicate.call(context, list[i], i, list)) { - return i; - } - } - return -1; -} - -if (!Array.prototype.findIndex) { - Array.prototype.findIndex = findIndex; -} - -if (!Array.prototype.find) { - Array.prototype.find = function(predicate, context) { - if (this == null) { - throw new TypeError('Array.prototype.find called on null or undefined'); - } - var index = findIndex.call(this, predicate, context); - return index === -1 ? undefined : this[index]; - }; -}