@@ -269,237 +269,63 @@ const isTagWithMandatoryNamepathOrType = (tagName) => {
269
269
return tagsWithMandatoryNamepathOrType . includes ( tagName ) ;
270
270
} ;
271
271
272
- const LOOP_STATEMENTS = [ 'WhileStatement' , 'DoWhileStatement' , 'ForStatement' , 'ForInStatement' , 'ForOfStatement' ] ;
273
-
274
- const STATEMENTS_WITH_CHILDREN = [
275
- '@loop' ,
276
- 'SwitchStatement' ,
277
- 'IfStatement' ,
278
- 'BlockStatement' ,
279
- 'TryStatement' ,
280
- 'WithStatement'
281
- ] ;
282
-
283
- const RETURNFREE_STATEMENTS = [
284
- 'VariableDeclaration' ,
285
- 'ThrowStatement' ,
286
- 'FunctionDeclaration' ,
287
- 'BreakStatement' ,
288
- 'ContinueStatement' ,
289
- 'LabeledStatement' ,
290
- 'DebuggerStatement' ,
291
- 'EmptyStatement' ,
292
- 'ThrowStatement' ,
293
- 'ExpressionStatement'
294
- ] ;
295
-
296
- const ENTRY_POINTS = [ 'FunctionDeclaration' , 'ArrowFunctionExpression' , 'FunctionExpression' ] ;
297
-
298
- /* eslint-disable sort-keys */
299
- const lookupTable = {
300
- ReturnStatement : {
301
- is ( node ) {
302
- return node . type === 'ReturnStatement' ;
303
- } ,
304
- check ( node ) {
305
- /* istanbul ignore next */
306
- if ( ! lookupTable . ReturnStatement . is ( node ) ) {
307
- return false ;
308
- }
309
-
310
- // A return without any arguments just exits the function
311
- // and is typically not documented at all in jsdoc.
312
- if ( node . argument === null ) {
313
- return false ;
314
- }
315
-
316
- return true ;
317
- }
318
- } ,
319
- WithStatement : {
320
- is ( node ) {
321
- return node . type === 'WithStatement' ;
322
- } ,
323
- check ( node , context ) {
324
- return lookupTable . BlockStatement . check ( node . body , context ) ;
325
- }
326
- } ,
327
- IfStatement : {
328
- is ( node ) {
329
- return node . type === 'IfStatement' ;
330
- } ,
331
- check ( node ) {
332
- /* istanbul ignore next */
333
- if ( ! lookupTable . IfStatement . is ( node ) ) {
334
- return false ;
335
- }
336
-
337
- if ( lookupTable [ '@default' ] . check ( node . consequent ) ) {
338
- return true ;
339
- }
340
-
341
- if ( node . alternate && lookupTable [ '@default' ] . check ( node . alternate ) ) {
342
- return true ;
343
- }
344
-
345
- return false ;
346
- }
347
- } ,
348
- '@loop' : {
349
- is ( node ) {
350
- return LOOP_STATEMENTS . includes ( node . type ) ;
351
- } ,
352
- check ( node ) {
353
- return lookupTable [ '@default' ] . check ( node . body ) ;
354
- }
355
- } ,
356
- SwitchStatement : {
357
- is ( node ) {
358
- return node . type === 'SwitchStatement' ;
359
- } ,
360
- check ( node ) {
361
- for ( const item of node . cases ) {
362
- for ( const statement of item . consequent ) {
363
- if ( lookupTable [ '@default' ] . check ( statement ) ) {
364
- return true ;
365
- }
366
- }
367
- }
368
-
369
- return false ;
370
- }
371
- } ,
372
- TryStatement : {
373
- is ( node ) {
374
- return node . type === 'TryStatement' ;
375
- } ,
376
- check ( node ) {
377
- /* istanbul ignore next */
378
- if ( ! lookupTable . TryStatement . is ( node ) ) {
379
- return false ;
380
- }
381
-
382
- if ( lookupTable . BlockStatement . check ( node . block ) ) {
383
- return true ;
384
- }
385
-
386
- if ( node . handler && node . handler . body ) {
387
- if ( lookupTable [ '@default' ] . check ( node . handler . body ) ) {
388
- return true ;
389
- }
390
- }
391
- if ( lookupTable . BlockStatement . check ( node . finalizer ) ) {
392
- return true ;
393
- }
394
-
395
- return false ;
396
- }
397
- } ,
398
- BlockStatement : {
399
- is ( node ) {
400
- return node . type === 'BlockStatement' ;
401
- } ,
402
- check ( node , context ) {
403
- // E.g. the catch block statement is optional.
404
- /* istanbul ignore next */
405
- if ( typeof node === 'undefined' || node === null ) {
406
- return false ;
407
- }
408
-
409
- /* istanbul ignore next */
410
- if ( ! lookupTable . BlockStatement . is ( node ) ) {
411
- return false ;
412
- }
413
-
414
- for ( const item of node . body ) {
415
- if ( lookupTable [ '@default' ] . check ( item , context ) ) {
416
- return true ;
417
- }
418
- }
419
-
420
- return false ;
421
- }
422
- } ,
423
- FunctionExpression : {
424
- is ( node ) {
425
- return node . type === 'FunctionExpression' ;
426
- } ,
427
- check ( node , context , ignoreAsync ) {
428
- return ! ignoreAsync && node . async || lookupTable . BlockStatement . check ( node . body , context ) ;
429
- }
430
- } ,
431
- ArrowFunctionExpression : {
432
- is ( node ) {
433
- return node . type === 'ArrowFunctionExpression' ;
434
- } ,
435
- check ( node , context , ignoreAsync ) {
436
- // An expression always has a return value.
437
- return node . expression ||
438
- ! ignoreAsync && node . async ||
439
- lookupTable . BlockStatement . check ( node . body , context ) ;
440
- }
441
- } ,
442
- FunctionDeclaration : {
443
- is ( node ) {
444
- return node . type === 'FunctionDeclaration' ;
445
- } ,
446
- check ( node , context , ignoreAsync ) {
447
- return ! ignoreAsync && node . async || lookupTable . BlockStatement . check ( node . body , context ) ;
448
- }
449
- } ,
450
- '@default' : {
451
- check ( node , context ) {
452
- // In case it is a `ReturnStatement`, we found what we were looking for
453
- if ( lookupTable . ReturnStatement . is ( node ) ) {
454
- return lookupTable . ReturnStatement . check ( node , context ) ;
455
- }
456
-
457
- // In case the element has children, we need to traverse them.
458
- // Examples are BlockStatement, Choices, TryStatement, Loops, ...
459
- for ( const item of STATEMENTS_WITH_CHILDREN ) {
460
- if ( lookupTable [ item ] . is ( node ) ) {
461
- return lookupTable [ item ] . check ( node , context ) ;
462
- }
463
- }
464
-
465
- // Everything else cannot return anything.
466
- /* istanbul ignore next */
467
- if ( RETURNFREE_STATEMENTS . includes ( node . type ) ) {
468
- return false ;
469
- }
470
-
471
- /* istanbul ignore next */
472
- // If we end up here, we stumbled upon an unknown element.
473
- // Most likely it is enough to add it to the blacklist.
474
- //
475
- // throw new Error('Unknown node type: ' + node.type);
476
- return false ;
477
- }
478
- }
479
- } ;
480
-
481
272
/**
482
- * Checks if the source code returns a return value.
483
- * It traverses the parsed source code and returns as
484
- * soon as it stumbles upon the first return statement.
273
+ * Checks if a node has a return statement. Void return does not count.
485
274
*
486
275
* @param {object } node
487
- * the node which should be checked.
488
- * @param {object } context
489
- * @param {boolean } ignoreAsync
490
- * ignore implicit async return.
491
276
* @returns {boolean }
492
- * true in case the code returns a return value
493
277
*/
494
- const hasReturnValue = ( node , context , ignoreAsync ) => {
495
- // Loop through all of our entry points
496
- for ( const item of ENTRY_POINTS ) {
497
- if ( lookupTable [ item ] . is ( node ) ) {
498
- return lookupTable [ item ] . check ( node , context , ignoreAsync ) ;
278
+ // eslint-disable-next-line complexity
279
+ const hasReturnValue = ( node ) => {
280
+ if ( ! node ) {
281
+ return false ;
282
+ }
283
+ switch ( node . type ) {
284
+ case 'FunctionExpression' :
285
+ case 'FunctionDeclaration' :
286
+ case 'ArrowFunctionExpression' : {
287
+ return node . expression || hasReturnValue ( node . body ) ;
288
+ }
289
+ case 'BlockStatement' : {
290
+ return node . body . some ( ( bodyNode ) => {
291
+ return bodyNode . type !== 'FunctionDeclaration' && hasReturnValue ( bodyNode ) ;
292
+ } ) ;
293
+ }
294
+ case 'WhileStatement' :
295
+ case 'DoWhileStatement' :
296
+ case 'ForStatement' :
297
+ case 'ForInStatement' :
298
+ case 'ForOfStatement' :
299
+ case 'WithStatement' : {
300
+ return hasReturnValue ( node . body ) ;
301
+ }
302
+ case 'IfStatement' : {
303
+ return hasReturnValue ( node . consequent ) || hasReturnValue ( node . alternate ) ;
304
+ }
305
+ case 'TryStatement' : {
306
+ return hasReturnValue ( node . block ) ||
307
+ hasReturnValue ( node . handler && node . handler . body ) ||
308
+ hasReturnValue ( node . finalizer ) ;
309
+ }
310
+ case 'SwitchStatement' : {
311
+ return node . cases . some (
312
+ ( someCase ) => {
313
+ return someCase . consequent . some ( hasReturnValue ) ;
314
+ }
315
+ ) ;
316
+ }
317
+ case 'ReturnStatement' : {
318
+ // void return does not count.
319
+ if ( node . argument === null ) {
320
+ return false ;
499
321
}
322
+
323
+ return true ;
324
+ }
325
+ default : {
326
+ return false ;
327
+ }
500
328
}
501
- /* istanbul ignore next */
502
- throw new Error ( `Unknown element ${ node . type } ` ) ;
503
329
} ;
504
330
505
331
/** @param {string } tag */
@@ -584,8 +410,8 @@ const getTagsByType = (tags, tagPreference) => {
584
410
} ) ;
585
411
586
412
return {
587
- tagsWithoutNames ,
588
- tagsWithNames
413
+ tagsWithNames ,
414
+ tagsWithoutNames
589
415
} ;
590
416
} ;
591
417
0 commit comments