@@ -47,13 +47,15 @@ function mergeUsedPropTypes(propsList, newPropsList) {
47
47
}
48
48
49
49
const Lists = new WeakMap ( ) ;
50
+ const ReactImports = new WeakMap ( ) ;
50
51
51
52
/**
52
53
* Components
53
54
*/
54
55
class Components {
55
56
constructor ( ) {
56
57
Lists . set ( this , { } ) ;
58
+ ReactImports . set ( this , { } ) ;
57
59
}
58
60
59
61
/**
@@ -179,6 +181,52 @@ class Components {
179
181
const list = Lists . get ( this ) ;
180
182
return Object . keys ( list ) . filter ( ( i ) => list [ i ] . confidence >= 2 ) . length ;
181
183
}
184
+
185
+ /**
186
+ * Return the node naming the default React import
187
+ * It can be used to determine the local name of import, even if it's imported
188
+ * with an unusual name.
189
+ *
190
+ * @returns {ASTNode } React default import node
191
+ */
192
+ getDefaultReactImports ( ) {
193
+ return ReactImports . get ( this ) . defaultReactImports ;
194
+ }
195
+
196
+ /**
197
+ * Return the nodes of all React named imports
198
+ *
199
+ * @returns {Object } The list of React named imports
200
+ */
201
+ getNamedReactImports ( ) {
202
+ return ReactImports . get ( this ) . namedReactImports ;
203
+ }
204
+
205
+ /**
206
+ * Add the default React import specifier to the scope
207
+ *
208
+ * @param {ASTNode } specifier The AST Node of the default React import
209
+ * @returns {void }
210
+ */
211
+ addDefaultReactImport ( specifier ) {
212
+ const info = ReactImports . get ( this ) ;
213
+ ReactImports . set ( this , Object . assign ( { } , info , {
214
+ defaultReactImports : ( info . defaultReactImports || [ ] ) . concat ( specifier ) ,
215
+ } ) ) ;
216
+ }
217
+
218
+ /**
219
+ * Add a named React import specifier to the scope
220
+ *
221
+ * @param {ASTNode } specifier The AST Node of a named React import
222
+ * @returns {void }
223
+ */
224
+ addNamedReactImport ( specifier ) {
225
+ const info = ReactImports . get ( this ) ;
226
+ ReactImports . set ( this , Object . assign ( { } , info , {
227
+ namedReactImports : ( info . namedReactImports || [ ] ) . concat ( specifier ) ,
228
+ } ) ) ;
229
+ }
182
230
}
183
231
184
232
function getWrapperFunctions ( context , pragma ) {
@@ -857,6 +905,25 @@ function componentRule(rule, context) {
857
905
} ,
858
906
} ;
859
907
908
+ // Detect React import specifiers
909
+ const reactImportInstructions = {
910
+ ImportDeclaration ( node ) {
911
+ const isReactImported = node . source . type === 'Literal' && node . source . value === 'react' ;
912
+ if ( ! isReactImported ) {
913
+ return ;
914
+ }
915
+
916
+ node . specifiers . forEach ( ( specifier ) => {
917
+ if ( specifier . type === 'ImportDefaultSpecifier' ) {
918
+ components . addDefaultReactImport ( specifier ) ;
919
+ }
920
+ if ( specifier . type === 'ImportSpecifier' ) {
921
+ components . addNamedReactImport ( specifier ) ;
922
+ }
923
+ } ) ;
924
+ } ,
925
+ } ;
926
+
860
927
// Update the provided rule instructions to add the component detection
861
928
const ruleInstructions = rule ( context , components , utils ) ;
862
929
const updatedRuleInstructions = Object . assign ( { } , ruleInstructions ) ;
@@ -866,7 +933,8 @@ function componentRule(rule, context) {
866
933
const allKeys = new Set ( Object . keys ( detectionInstructions ) . concat (
867
934
Object . keys ( propTypesInstructions ) ,
868
935
Object . keys ( usedPropTypesInstructions ) ,
869
- Object . keys ( defaultPropsInstructions )
936
+ Object . keys ( defaultPropsInstructions ) ,
937
+ Object . keys ( reactImportInstructions )
870
938
) ) ;
871
939
872
940
allKeys . forEach ( ( instruction ) => {
@@ -883,6 +951,9 @@ function componentRule(rule, context) {
883
951
if ( instruction in defaultPropsInstructions ) {
884
952
defaultPropsInstructions [ instruction ] ( node ) ;
885
953
}
954
+ if ( instruction in reactImportInstructions ) {
955
+ reactImportInstructions [ instruction ] ( node ) ;
956
+ }
886
957
if ( ruleInstructions [ instruction ] ) {
887
958
return ruleInstructions [ instruction ] ( node ) ;
888
959
}
0 commit comments