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

Do not codemod classes with invalid fields, fixes #4628

cpojer committed Sep 3, 2015 at 17:04 UTC cfe0351b8f95cc212570c9d158ad7cde155258d0
4 files changed +47 -7
packages/react-codemod/package.json
+3 -3
@@ -11,11 +11,11 @@
11 "test": "jest"
12 },
13 "dependencies": {
14 - "jscodeshift": "^0.3.2"
14 + "jscodeshift": "^0.3.7"
15 },
16 "devDependencies": {
17 - "babel-jest": "^4.0.0",
18 - "jest-cli": "^0.4.0"
17 + "babel-jest": "^5.3.0",
18 + "jest-cli": "^0.5.1"
19 },
20 "jest": {
21 "scriptPreprocessor": "./node_modules/babel-jest",
packages/react-codemod/test/class-test.js
+5
@@ -121,6 +121,11 @@ var MyComponent3 = React.createClass({
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`,
packages/react-codemod/test/class-test.output.js
+5
@@ -132,6 +132,11 @@ MyComponent3.propTypes = {
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`,
packages/react-codemod/transforms/class.js
+34 -4
@@ -46,6 +46,8 @@ module.exports = (file, api, options) => {
46 'setProps',
47 ];
48
49 + const STATIC_KEY = 'statics';
50 +
51 const STATIC_KEYS = {
52 childContextTypes: true,
53 contextTypes: true,
@@ -67,8 +69,8 @@ module.exports = (file, api, options) => {
69 const callsDeprecatedAPIs = classPath => {
70 if (checkDeprecatedAPICalls(classPath)) {
71 console.log(
70 - file.path + ': "' + ReactUtils.getComponentName(classPath) + '" ' +
71 - 'skipped because of deprecated API calls. Remove calls to ' +
72 + file.path + ': `' + ReactUtils.getComponentName(classPath) + '` ' +
73 + 'was skipped because of deprecated API calls. Remove calls to ' +
74 DEPRECATED_APIS.join(', ') + ' in your React component and re-run ' +
75 'this script.'
76 );
@@ -77,11 +79,38 @@ module.exports = (file, api, options) => {
79 return true;
80 };
81
82 + const canConvertToClass = classPath => {
83 + const specPath = ReactUtils.getReactCreateClassSpec(classPath);
84 + const invalidProperties = specPath.properties.filter(prop => (
85 + !prop.key.name || (
86 + !STATIC_KEYS[prop.key.name] &&
87 + STATIC_KEY != prop.key.name &&
88 + !filterDefaultPropsField(prop) &&
89 + !filterGetInitialStateField(prop) &&
90 + !isFunctionExpression(prop)
91 + )
92 + ));
93 +
94 + if (invalidProperties.length) {
95 + const invalidText = invalidProperties
96 + .map(prop => prop.key.name ? prop.key.name : prop.key)
97 + .join(', ');
98 + console.log(
99 + file.path + ': `' + ReactUtils.getComponentName(classPath) + '` ' +
100 + 'was skipped because of invalid field(s) `' + invalidText + '` on ' +
101 + 'the React component. Remove any right-hand-side expressions that ' +
102 + 'are not simple, like: `componentWillUpdate: createWillUpdate()` or ' +
103 + '`render: foo ? renderA : renderB`.'
104 + );
105 + }
106 + return !invalidProperties.length;
107 + }
108 +
109 const hasMixins = classPath => {
110 if (ReactUtils.hasMixins(classPath)) {
111 console.log(
83 - file.path + ': "' + ReactUtils.getComponentName(classPath) + '" ' +
84 - ' skipped because of mixins.'
112 + file.path + ': `' + ReactUtils.getComponentName(classPath) + '` ' +
113 + 'was skipped because of mixins.'
114 );
115 return false;
116 }
@@ -499,6 +528,7 @@ module.exports = (file, api, options) => {
528 path
529 .filter(hasMixins)
530 .filter(callsDeprecatedAPIs)
531 + .filter(canConvertToClass)
532 .forEach(classPath => updateToClass(
533 classPath,
534 !options['no-super-class'],