@@ -11,6 +11,7 @@ const values = require('object.values');
11
11
const docsUrl = require ( '../util/docsUrl' ) ;
12
12
const pragmaUtil = require ( '../util/pragma' ) ;
13
13
const report = require ( '../util/report' ) ;
14
+ const astUtil = require ( '../util/ast' ) ;
14
15
15
16
// ------------------------------------------------------------------------------
16
17
// Rule Definition
@@ -124,6 +125,36 @@ module.exports = {
124
125
} ) ;
125
126
}
126
127
128
+ /**
129
+ * Checks if the given node is a function expression or arrow function,
130
+ * and checks if there is a missing key prop in return statement's arguments
131
+ * @param {ASTNode } node
132
+ */
133
+ function checkFunctionsBlockStatement ( node ) {
134
+ if ( astUtil . isFunctionLikeExpression ( node ) ) {
135
+ if ( node . body . type === 'BlockStatement' ) {
136
+ getReturnStatements ( node . body )
137
+ . filter ( ( returnStatement ) => returnStatement && returnStatement . argument )
138
+ . forEach ( ( returnStatement ) => {
139
+ checkIteratorElement ( returnStatement . argument ) ;
140
+ } ) ;
141
+ }
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Checks if the given node is an arrow function that has an JSX Element or JSX Fragment in its body,
147
+ * and the JSX is missing a key prop
148
+ * @param {ASTNode } node
149
+ */
150
+ function checkArrowFunctionWithJSX ( node ) {
151
+ const isArrFn = node && node . type === 'ArrowFunctionExpression' ;
152
+
153
+ if ( isArrFn && ( node . body . type === 'JSXElement' || node . body . type === 'JSXFragment' ) ) {
154
+ checkIteratorElement ( node . body ) ;
155
+ }
156
+ }
157
+
127
158
const seen = new WeakSet ( ) ;
128
159
129
160
return {
@@ -196,26 +227,26 @@ module.exports = {
196
227
OptionalCallExpression[callee.type="MemberExpression"][callee.property.name="map"],\
197
228
OptionalCallExpression[callee.type="OptionalMemberExpression"][callee.property.name="map"]' ( node ) {
198
229
const fn = node . arguments [ 0 ] ;
199
- const isFn = fn && fn . type === 'FunctionExpression' ;
200
- const isArrFn = fn && fn . type === 'ArrowFunctionExpression' ;
201
-
202
- if ( ! fn && ! isFn && ! isArrFn ) {
230
+ if ( ! astUtil . isFunctionLikeExpression ( fn ) ) {
203
231
return ;
204
232
}
205
233
206
- if ( isArrFn && ( fn . body . type === 'JSXElement' || fn . body . type === 'JSXFragment' ) ) {
207
- checkIteratorElement ( fn . body ) ;
208
- }
234
+ checkArrowFunctionWithJSX ( fn ) ;
209
235
210
- if ( isFn || isArrFn ) {
211
- if ( fn . body . type === 'BlockStatement' ) {
212
- getReturnStatements ( fn . body )
213
- . filter ( ( returnStatement ) => returnStatement && returnStatement . argument )
214
- . forEach ( ( returnStatement ) => {
215
- checkIteratorElement ( returnStatement . argument ) ;
216
- } ) ;
217
- }
236
+ checkFunctionsBlockStatement ( fn ) ;
237
+ } ,
238
+
239
+ // Array.from
240
+ 'CallExpression[callee.type="MemberExpression"][callee.property.name="from"]' ( node ) {
241
+ const fn = node . arguments . length > 1 && node . arguments [ 1 ] ;
242
+
243
+ if ( ! astUtil . isFunctionLikeExpression ( fn ) ) {
244
+ return ;
218
245
}
246
+
247
+ checkArrowFunctionWithJSX ( fn ) ;
248
+
249
+ checkFunctionsBlockStatement ( fn ) ;
219
250
} ,
220
251
} ;
221
252
} ,
0 commit comments