@@ -130,6 +130,68 @@ module.exports = (file, api, options) => {
130
130
return true ;
131
131
} ;
132
132
133
+ const isGetInitialStateConstructorSafe = getInitialState => {
134
+ if ( ! getInitialState ) {
135
+ return true ;
136
+ }
137
+
138
+ const collection = j ( getInitialState ) ;
139
+ let result = true ;
140
+
141
+ const propsVarDeclarationCount = collection . find ( j . VariableDeclarator , {
142
+ id : { name : 'props' } ,
143
+ } ) . size ( ) ;
144
+
145
+ const contextVarDeclarationCount = collection . find ( j . VariableDeclarator , {
146
+ id : { name : 'context' } ,
147
+ } ) . size ( ) ;
148
+
149
+ if (
150
+ propsVarDeclarationCount &&
151
+ propsVarDeclarationCount !== collection . find ( j . VariableDeclarator , {
152
+ id : { name : 'props' } ,
153
+ init : {
154
+ type : 'MemberExpression' ,
155
+ object : { type : 'ThisExpression' } ,
156
+ property : { name : 'props' } ,
157
+ }
158
+ } ) . size ( )
159
+ ) {
160
+ result = false ;
161
+ }
162
+
163
+ if (
164
+ contextVarDeclarationCount &&
165
+ contextVarDeclarationCount !== collection . find ( j . VariableDeclarator , {
166
+ id : { name : 'context' } ,
167
+ init : {
168
+ type : 'MemberExpression' ,
169
+ object : { type : 'ThisExpression' } ,
170
+ property : { name : 'context' } ,
171
+ }
172
+ } ) . size ( )
173
+ ) {
174
+ result = false ;
175
+ }
176
+
177
+ return result ;
178
+ } ;
179
+
180
+ const isInitialStateConvertible = classPath => {
181
+ const result = isGetInitialStateConstructorSafe (
182
+ ReactUtils . getReactCreateClassSpec ( classPath )
183
+ ) ;
184
+ if ( ! result ) {
185
+ console . warn (
186
+ file . path + ': `' + ReactUtils . getComponentName ( classPath ) + '` ' +
187
+ 'was skipped because of potential shadowing issues were found in ' +
188
+ 'the React component. Rename variable declarations of `props` and/or `context` ' +
189
+ 'in your `getInitialState` and re-run this script.'
190
+ ) ;
191
+ }
192
+ return result ;
193
+ } ;
194
+
133
195
const canConvertToClass = classPath => {
134
196
const specPath = ReactUtils . getReactCreateClassSpec ( classPath ) ;
135
197
const invalidProperties = specPath . properties . filter ( prop => (
@@ -323,6 +385,15 @@ module.exports = (file, api, options) => {
323
385
const inlineGetInitialState = getInitialState => {
324
386
const functionExpressionAST = j ( getInitialState . value ) ;
325
387
388
+ // at this point if there exists bindings like `const props = ...`, we
389
+ // already know the RHS must be `this.props` (see `isGetInitialStateConstructorSafe`)
390
+ // so it's safe to just remove them
391
+ functionExpressionAST . find ( j . VariableDeclarator , { id : { name : 'props' } } )
392
+ . forEach ( path => j ( path ) . remove ( ) ) ;
393
+
394
+ functionExpressionAST . find ( j . VariableDeclarator , { id : { name : 'context' } } )
395
+ . forEach ( path => j ( path ) . remove ( ) ) ;
396
+
326
397
return functionExpressionAST
327
398
. find ( j . ReturnStatement )
328
399
. forEach ( path => {
@@ -880,6 +951,7 @@ module.exports = (file, api, options) => {
880
951
. filter ( hasNoCallsToDeprecatedAPIs )
881
952
. filter ( hasNoCallsToAPIsThatWillBeRemoved )
882
953
. filter ( doesNotUseArguments )
954
+ . filter ( isInitialStateConvertible )
883
955
. filter ( canConvertToClass )
884
956
. forEach ( classPath => updateToClass ( classPath , type ) ) ;
885
957
0 commit comments