Skip to content

Commit cfbdf8b

Browse files
committedOct 24, 2022
fix(require-returns-check, require-yields-check): check for undefined/void within union; fixes #925
1 parent 12da503 commit cfbdf8b

File tree

4 files changed

+73
-2
lines changed

4 files changed

+73
-2
lines changed
 

‎README.md

+10
Original file line numberDiff line numberDiff line change
@@ -18141,6 +18141,16 @@ function getTrue() {
1814118141
console.log('returning...');
1814218142
}
1814318143
}
18144+
18145+
/**
18146+
* Maybe return a boolean.
18147+
* @returns {boolean|void} true, or undefined.
18148+
*/
18149+
function maybeTrue() {
18150+
if (Math.random() > 0.5) {
18151+
return true;
18152+
}
18153+
}
1814418154
````
1814518155

1814618156

‎src/iterateJsdoc.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,7 @@ const getUtils = (
676676
};
677677

678678
utils.hasDefinedTypeTag = (tag) => {
679-
return jsdocUtils.hasDefinedTypeTag(tag);
679+
return jsdocUtils.hasDefinedTypeTag(tag, settings.mode);
680680
};
681681

682682
utils.hasValueOrExecutorHasNonEmptyResolveValue = (anyPromiseAsReturn, allBranches) => {

‎src/jsdocUtils.js

+30-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
/* eslint-disable jsdoc/no-undefined-types */
22

3+
import {
4+
tryParse,
5+
} from '@es-joy/jsdoccomment';
36
import WarnSettings from './WarnSettings';
47
import getDefaultTagStructureForMode from './getDefaultTagStructureForMode';
58
import {
@@ -465,21 +468,47 @@ const hasATag = (jsdoc, targetTagNames) => {
465468
*
466469
* @param {JsDocTag} tag
467470
* the tag which should be checked.
471+
* @param {"jsdoc"|"closure"|"typescript"} mode
468472
* @returns {boolean}
469473
* true in case a defined type is declared; otherwise false.
470474
*/
471-
const hasDefinedTypeTag = (tag) => {
475+
const hasDefinedTypeTag = (tag, mode) => {
472476
// The function should not continue in the event the type is not defined...
473477
if (typeof tag === 'undefined' || tag === null) {
474478
return false;
475479
}
476480

477481
// .. same applies if it declares an `{undefined}` or `{void}` type
478482
const tagType = tag.type.trim();
483+
484+
// Exit early if matching
479485
if (tagType === 'undefined' || tagType === 'void') {
480486
return false;
481487
}
482488

489+
let parsedTypes;
490+
try {
491+
parsedTypes = tryParse(
492+
tagType,
493+
mode === 'permissive' ? undefined : [
494+
mode,
495+
],
496+
);
497+
} catch {
498+
// Ignore
499+
}
500+
501+
if (
502+
// We do not traverse deeply as it could be, e.g., `Promise<void>`
503+
parsedTypes &&
504+
parsedTypes.type === 'JsdocTypeUnion' &&
505+
parsedTypes.elements.find((elem) => {
506+
return elem.type === 'JsdocTypeUndefined' ||
507+
elem.type === 'JsdocTypeName' && elem.value === 'void';
508+
})) {
509+
return false;
510+
}
511+
483512
// In any other case, a type is present
484513
return true;
485514
};

‎test/rules/assertions/requireReturnsCheck.js

+32
Original file line numberDiff line numberDiff line change
@@ -1426,5 +1426,37 @@ export default {
14261426
}
14271427
`,
14281428
},
1429+
{
1430+
code: `
1431+
/**
1432+
* Maybe return a boolean.
1433+
* @returns {boolean|void} true, or undefined.
1434+
*/
1435+
function maybeTrue() {
1436+
if (Math.random() > 0.5) {
1437+
return true;
1438+
}
1439+
}
1440+
`,
1441+
},
1442+
{
1443+
code: `
1444+
/**
1445+
* Maybe return a boolean.
1446+
* @return {boolean|void} true, or undefined.
1447+
*/
1448+
function maybeTrue() {
1449+
if (Math.random() > 0.5) {
1450+
return true;
1451+
}
1452+
}
1453+
`,
1454+
ignoreReadme: true,
1455+
settings: {
1456+
jsdoc: {
1457+
mode: 'permissive',
1458+
},
1459+
},
1460+
},
14291461
],
14301462
};

0 commit comments

Comments
 (0)
Please sign in to comment.