Skip to content

Commit 3cd7cbd

Browse files
committed
feat(check-tag-names, require-template, check-template-names): make typeParam a non-preferred alias for template
1 parent 44b2631 commit 3cd7cbd

File tree

9 files changed

+136
-8
lines changed

9 files changed

+136
-8
lines changed

docs/rules/check-tag-names.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,5 +1157,10 @@ interface WebTwain {
11571157
* @param {AnotherType} anotherName And yet {@another}
11581158
*/
11591159
// "jsdoc/check-tag-names": ["error"|"warn", {"inlineTags":["inline","another","inlineTag","link"]}]
1160+
1161+
/**
1162+
* @typeParam T
1163+
*/
1164+
// Settings: {"jsdoc":{"tagNamePreference":{"template":"typeParam"}}}
11601165
````
11611166

docs/rules/check-template-names.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,12 @@ export default class <NumType> {
214214
* @param {[X, Y | undefined]} someParam
215215
*/
216216
// Message: @template D not in use
217+
218+
/**
219+
* @template
220+
*/
221+
// Settings: {"jsdoc":{"tagNamePreference":{"template":false}}}
222+
// Message: Unexpected tag `@template`
217223
````
218224

219225

docs/rules/require-template.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,12 @@ function foo<T>(bar: T, baz: number | boolean): T {
236236
return bar;
237237
}
238238
// Message: Missing @template T
239+
240+
/**
241+
* @template
242+
*/
243+
// Settings: {"jsdoc":{"tagNamePreference":{"template":false}}}
244+
// Message: Unexpected tag `@template`
239245
````
240246

241247

@@ -399,5 +405,18 @@ type Pairs<D, V> = [D, V | undefined];
399405
* @typedef {[D, V | undefined]} Pairs
400406
*/
401407
// "jsdoc/require-template": ["error"|"warn", {"exemptedBy":["inheritdoc"]}]
408+
409+
/**
410+
* Test interface for type definitions.
411+
*
412+
* @typeParam Foo - dummy type param
413+
*/
414+
export interface Test<Foo extends string> {
415+
/**
416+
*
417+
*/
418+
bar: Foo;
419+
}
420+
// Settings: {"jsdoc":{"tagNamePreference":{"template":"typeParam"}}}
402421
````
403422

src/rules/checkTemplateNames.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,14 @@ export default iterateJsdoc(({
2323
mode,
2424
} = settings;
2525

26-
const templateTags = utils.getTags('template');
26+
const tgName = /** @type {string} */ (utils.getPreferredTagName({
27+
tagName: 'template',
28+
}));
29+
if (!tgName) {
30+
return;
31+
}
32+
33+
const templateTags = utils.getTags(tgName);
2734

2835
const usedNames = new Set();
2936
/**
@@ -73,7 +80,7 @@ export default iterateJsdoc(({
7380
const names = utils.parseClosureTemplateTag(tag);
7481
for (const nme of names) {
7582
if (!usedNames.has(nme)) {
76-
report(`@template ${nme} not in use`, null, tag);
83+
report(`@${tgName} ${nme} not in use`, null, tag);
7784
}
7885
}
7986
}

src/rules/requireTemplate.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,16 @@ export default iterateJsdoc(({
2525
} = settings;
2626

2727
const usedNames = new Set();
28-
const templateTags = utils.getTags('template');
28+
29+
const tgName = /** @type {string} */ (utils.getPreferredTagName({
30+
tagName: 'template',
31+
}));
32+
if (!tgName) {
33+
return;
34+
}
35+
36+
const templateTags = utils.getTags(tgName);
37+
2938
const templateNames = templateTags.flatMap((tag) => {
3039
return utils.parseClosureTemplateTag(tag);
3140
});
@@ -34,7 +43,7 @@ export default iterateJsdoc(({
3443
for (const tag of templateTags) {
3544
const names = utils.parseClosureTemplateTag(tag);
3645
if (names.length > 1) {
37-
report(`Missing separate @template for ${names[1]}`, null, tag);
46+
report(`Missing separate @${tgName} for ${names[1]}`, null, tag);
3847
}
3948
}
4049
}
@@ -64,7 +73,7 @@ export default iterateJsdoc(({
6473

6574
for (const usedName of usedNames) {
6675
if (!templateNames.includes(usedName)) {
67-
report(`Missing @template ${usedName}`);
76+
report(`Missing @${tgName} ${usedName}`);
6877
}
6978
}
7079
};
@@ -156,7 +165,7 @@ export default iterateJsdoc(({
156165
// Could check against whitelist/blacklist
157166
for (const usedName of usedNames) {
158167
if (!templateNames.includes(usedName)) {
159-
report(`Missing @template ${usedName}`, null, usedNameToTag.get(usedName));
168+
report(`Missing @${tgName} ${usedName}`, null, usedNameToTag.get(usedName));
160169
}
161170
}
162171
};

src/tagNames.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,11 @@ const typeScriptTags = {
150150
satisfies: [],
151151

152152
// `@template` is also in TypeScript per:
153-
// https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html#supported-jsdoc
154-
template: [],
153+
// https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#template
154+
template: [
155+
// Alias as per https://typedoc.org/documents/Tags._typeParam.html
156+
'typeParam',
157+
],
155158
};
156159

157160
/**

test/rules/assertions/checkTagNames.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1499,5 +1499,19 @@ export default /** @type {import('../index.js').TestCases} */ ({
14991499
},
15001500
],
15011501
},
1502+
{
1503+
code: `
1504+
/**
1505+
* @typeParam T
1506+
*/
1507+
`,
1508+
settings: {
1509+
jsdoc: {
1510+
tagNamePreference: {
1511+
template: 'typeParam',
1512+
},
1513+
},
1514+
},
1515+
},
15021516
],
15031517
});

test/rules/assertions/checkTemplateNames.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,26 @@ export default /** @type {import('../index.js').TestCases} */ ({
464464
},
465465
],
466466
},
467+
{
468+
code: `
469+
/**
470+
* @template
471+
*/
472+
`,
473+
errors: [
474+
{
475+
line: 3,
476+
message: 'Unexpected tag `@template`',
477+
},
478+
],
479+
settings: {
480+
jsdoc: {
481+
tagNamePreference: {
482+
template: false,
483+
},
484+
},
485+
},
486+
},
467487
],
468488
valid: [
469489
{

test/rules/assertions/requireTemplate.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,26 @@ export default /** @type {import('../index.js').TestCases} */ ({
426426
parser: typescriptEslintParser,
427427
},
428428
},
429+
{
430+
code: `
431+
/**
432+
* @template
433+
*/
434+
`,
435+
errors: [
436+
{
437+
line: 3,
438+
message: 'Unexpected tag `@template`',
439+
},
440+
],
441+
settings: {
442+
jsdoc: {
443+
tagNamePreference: {
444+
template: false,
445+
},
446+
},
447+
},
448+
},
429449
],
430450
valid: [
431451
{
@@ -701,5 +721,30 @@ export default /** @type {import('../index.js').TestCases} */ ({
701721
},
702722
],
703723
},
724+
{
725+
code: `
726+
/**
727+
* Test interface for type definitions.
728+
*
729+
* @typeParam Foo - dummy type param
730+
*/
731+
export interface Test<Foo extends string> {
732+
/**
733+
*
734+
*/
735+
bar: Foo;
736+
}
737+
`,
738+
languageOptions: {
739+
parser: typescriptEslintParser,
740+
},
741+
settings: {
742+
jsdoc: {
743+
tagNamePreference: {
744+
template: 'typeParam',
745+
},
746+
},
747+
},
748+
},
704749
],
705750
});

0 commit comments

Comments
 (0)