Skip to content

Commit f4d69ab

Browse files
committed
fix(no-undefined-types): consider template type as defined when on functions within its scope; fixes part of gajus#559
1 parent a764861 commit f4d69ab

File tree

3 files changed

+55
-3
lines changed

3 files changed

+55
-3
lines changed

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6212,6 +6212,18 @@ class SomeType {}
62126212
*/
62136213
function quux () {}
62146214
// Settings: {"jsdoc":{"mode":"closure"}}
6215+
6216+
/**
6217+
* @template T
6218+
* @param {T} arg
6219+
*/
6220+
function example(arg) {
6221+
6222+
/** @param {T} */
6223+
function inner(x) {
6224+
}
6225+
}
6226+
// Settings: {"jsdoc":{"mode":"closure"}}
62156227
````
62166228
62176229

src/rules/noUndefinedTypes.js

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import _ from 'lodash';
22
import {parse as parseType, traverse} from 'jsdoctypeparser';
33
import iterateJsdoc, {parseComment} from '../iterateJsdoc';
44
import jsdocUtils from '../jsdocUtils';
5+
import {getJSDocComment} from '../eslint/getJSDocComment';
56

67
const extraTypes = [
78
'null', 'undefined', 'void', 'string', 'boolean', 'object',
@@ -17,11 +18,13 @@ const stripPseudoTypes = (str) => {
1718

1819
export default iterateJsdoc(({
1920
context,
21+
node,
2022
report,
2123
settings,
22-
sourceCode: {scopeManager},
24+
sourceCode,
2325
utils,
2426
}) => {
27+
const {scopeManager} = sourceCode;
2528
const {globalScope} = scopeManager;
2629

2730
const {definedTypes = []} = context.options[0] || {};
@@ -54,7 +57,9 @@ export default iterateJsdoc(({
5457
.filter((comment) => {
5558
return comment.value.startsWith('*');
5659
})
57-
.map(parseComment)
60+
.map((commentNode) => {
61+
return parseComment(commentNode, '');
62+
})
5863
.flatMap((doc) => {
5964
return (doc.tags || []).filter(({tag}) => {
6065
return utils.isNamepathDefiningTag(tag);
@@ -65,7 +70,23 @@ export default iterateJsdoc(({
6570
})
6671
.value();
6772

68-
let templateTags = utils.getPresentTags('template');
73+
const ancestorNodes = [];
74+
let currentScope = scopeManager.acquire(node);
75+
while (currentScope && currentScope.block.type !== 'Program') {
76+
ancestorNodes.push(currentScope.block);
77+
currentScope = currentScope.upper;
78+
}
79+
80+
let templateTags = ancestorNodes.flatMap((ancestorNode) => {
81+
const commentNode = getJSDocComment(sourceCode, ancestorNode, settings);
82+
83+
const jsdoc = parseComment(commentNode, '');
84+
85+
return jsdocUtils.filterTags(jsdoc.tags, (tag) => {
86+
return 'template' === tag.tag;
87+
});
88+
});
89+
6990
const classJsdoc = utils.getClassJsdoc();
7091
if (classJsdoc?.tags) {
7192
templateTags = templateTags.concat(

test/rules/assertions/noUndefinedTypes.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,5 +705,24 @@ export default {
705705
},
706706
},
707707
},
708+
{
709+
code: `
710+
/**
711+
* @template T
712+
* @param {T} arg
713+
*/
714+
function example(arg) {
715+
716+
/** @param {T} */
717+
function inner(x) {
718+
}
719+
}
720+
`,
721+
settings: {
722+
jsdoc: {
723+
mode: 'closure',
724+
},
725+
},
726+
},
708727
],
709728
};

0 commit comments

Comments
 (0)