Skip to content

Commit ae2b314

Browse files
authored
fix(check-template-names): checks class body for comments where template names used; fixes #1354 (#1407)
1 parent 26ae169 commit ae2b314

File tree

3 files changed

+88
-15
lines changed

3 files changed

+88
-15
lines changed

docs/rules/check-template-names.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,5 +372,28 @@ export function mapGroupBy(array, callbackFn) {
372372
* @function
373373
* @param {[D, V | undefined]} someParam
374374
*/
375+
376+
/**
377+
* @template {string} U
378+
*/
379+
export class User {
380+
/**
381+
* @type {U}
382+
*/
383+
name;
384+
}
385+
386+
/**
387+
* @template {string} U
388+
*/
389+
export class User {
390+
/**
391+
* @param {U} name
392+
*/
393+
constructor(name) {
394+
this.name = name;
395+
}
396+
methodToIgnore() {}
397+
}
375398
````
376399

src/rules/checkTemplateNames.js

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
1-
import iterateJsdoc from '../iterateJsdoc.js';
1+
import iterateJsdoc, {
2+
parseComment,
3+
} from '../iterateJsdoc.js';
24
import {
5+
getTags,
6+
} from '../jsdocUtils.js';
7+
import {
8+
getJSDocComment,
39
parse as parseType,
410
traverse,
511
tryParse as tryParseType,
612
} from '@es-joy/jsdoccomment';
713

814
export default iterateJsdoc(({
15+
jsdoc,
916
node,
1017
report,
1118
settings,
19+
sourceCode,
1220
utils,
1321
}) => {
1422
const {
@@ -42,19 +50,19 @@ export default iterateJsdoc(({
4250
});
4351
};
4452

45-
const checkParamsAndReturnsTags = () => {
53+
const checkParamsAndReturnsTags = (jsdc = jsdoc) => {
4654
const paramName = /** @type {string} */ (utils.getPreferredTagName({
4755
tagName: 'param',
4856
}));
49-
const paramTags = utils.getTags(paramName);
57+
const paramTags = getTags(jsdc, paramName);
5058
for (const paramTag of paramTags) {
5159
checkForUsedTypes(paramTag.type);
5260
}
5361

5462
const returnsName = /** @type {string} */ (utils.getPreferredTagName({
5563
tagName: 'returns',
5664
}));
57-
const returnsTags = utils.getTags(returnsName);
65+
const returnsTags = getTags(jsdc, returnsName);
5866
for (const returnsTag of returnsTags) {
5967
checkForUsedTypes(returnsTag.type);
6068
}
@@ -98,6 +106,26 @@ export default iterateJsdoc(({
98106

99107
if (checkParamsAndReturns) {
100108
checkParamsAndReturnsTags();
109+
} else if (aliasDeclaration.type === 'ClassDeclaration') {
110+
/* c8 ignore next -- TS */
111+
for (const nde of aliasDeclaration?.body?.body ?? []) {
112+
// @ts-expect-error Should be ok
113+
const commentNode = getJSDocComment(sourceCode, nde, settings);
114+
if (!commentNode) {
115+
continue;
116+
}
117+
118+
const innerJsdoc = parseComment(commentNode, '');
119+
checkParamsAndReturnsTags(innerJsdoc);
120+
121+
const typeName = /** @type {string} */ (utils.getPreferredTagName({
122+
tagName: 'type',
123+
}));
124+
const typeTags = getTags(innerJsdoc, typeName);
125+
for (const typeTag of typeTags) {
126+
checkForUsedTypes(typeTag.type);
127+
}
128+
}
101129
}
102130

103131
checkTemplateTags();
@@ -162,17 +190,7 @@ export default iterateJsdoc(({
162190
checkForUsedTypes(propertyTag.type);
163191
}
164192

165-
for (const tag of templateTags) {
166-
const {
167-
name,
168-
} = tag;
169-
const names = name.split(/,\s*/u);
170-
for (const nme of names) {
171-
if (!usedNames.has(nme)) {
172-
report(`@template ${nme} not in use`, null, tag);
173-
}
174-
}
175-
}
193+
checkTemplateTags();
176194
}, {
177195
iterateAllJsdocs: true,
178196
meta: {

test/rules/assertions/checkTemplateNames.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,5 +716,37 @@ export default /** @type {import('../index.js').TestCases} */ ({
716716
*/
717717
`,
718718
},
719+
{
720+
code: `
721+
/**
722+
* @template {string} U
723+
*/
724+
export class User {
725+
/**
726+
* @type {U}
727+
*/
728+
name;
729+
}
730+
`,
731+
languageOptions: {
732+
ecmaVersion: 2_022,
733+
},
734+
},
735+
{
736+
code: `
737+
/**
738+
* @template {string} U
739+
*/
740+
export class User {
741+
/**
742+
* @param {U} name
743+
*/
744+
constructor(name) {
745+
this.name = name;
746+
}
747+
methodToIgnore() {}
748+
}
749+
`,
750+
},
719751
],
720752
});

0 commit comments

Comments
 (0)