Skip to content

Commit 320a1eb

Browse files
committed
feat(require-template, check-template-names): add support TSInterfaceDeclaration
1 parent 87a1270 commit 320a1eb

File tree

8 files changed

+332
-14
lines changed

8 files changed

+332
-14
lines changed

.README/rules/check-template-names.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
Checks that any `@template` names are actually used in the connected
44
`@typedef` or type alias.
55

6-
Currently checks `TSTypeAliasDeclaration` such as:
6+
Currently checks `TSInterfaceDeclaration` or `TSTypeAliasDeclaration` such as:
77

88
```ts
99
/**

.README/rules/require-template.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
Checks to see that `@template` tags are present for any detected type
44
parameters.
55

6-
Currently checks `TSTypeAliasDeclaration` such as:
6+
Currently checks `TSInterfaceDeclaration` or `TSTypeAliasDeclaration` such as:
77

88
```ts
99
export type Pairs<D, V> = [D, V | undefined];

docs/rules/check-template-names.md

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
Checks that any `@template` names are actually used in the connected
66
`@typedef` or type alias.
77

8-
Currently checks `TSTypeAliasDeclaration` such as:
8+
Currently checks `TSInterfaceDeclaration` or `TSTypeAliasDeclaration` such as:
99

1010
```ts
1111
/**
@@ -95,6 +95,33 @@ export type Extras<D, U> = [D, U | undefined];
9595
* @property {V} foo
9696
*/
9797
// Message: @template D not in use
98+
99+
/**
100+
* @template D
101+
* @template V
102+
*/
103+
interface GenericIdentityFn<Type> {
104+
(arg: Type): Type;
105+
}
106+
// Message: @template D not in use
107+
108+
/**
109+
* @template D
110+
* @template V
111+
*/
112+
export interface GenericIdentityFn<Type> {
113+
(arg: Type): Type;
114+
}
115+
// Message: @template D not in use
116+
117+
/**
118+
* @template D
119+
* @template V
120+
*/
121+
export default interface GenericIdentityFn<Type> {
122+
(arg: Type): Type;
123+
}
124+
// Message: @template D not in use
98125
````
99126

100127

@@ -146,5 +173,26 @@ export type Extras<D, U, V> = [D, U, V | undefined];
146173
* @property {D} foo
147174
* @property {V} bar
148175
*/
176+
177+
/**
178+
* @template Type
179+
*/
180+
interface GenericIdentityFn<Type> {
181+
(arg: Type): Type;
182+
}
183+
184+
/**
185+
* @template Type
186+
*/
187+
export interface GenericIdentityFn<Type> {
188+
(arg: Type): Type;
189+
}
190+
191+
/**
192+
* @template Type
193+
*/
194+
export default interface GenericIdentityFn<Type> {
195+
(arg: Type): Type;
196+
}
149197
````
150198

docs/rules/require-template.md

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
Checks to see that `@template` tags are present for any detected type
66
parameters.
77

8-
Currently checks `TSTypeAliasDeclaration` such as:
8+
Currently checks `TSInterfaceDeclaration` or `TSTypeAliasDeclaration` such as:
99

1010
```ts
1111
export type Pairs<D, V> = [D, V | undefined];
@@ -114,6 +114,30 @@ export type Pairs<D, V> = [D, V | undefined];
114114
* @property {X} bar
115115
*/
116116
// Message: Missing @template D
117+
118+
/**
119+
*
120+
*/
121+
interface GenericIdentityFn<Type> {
122+
(arg: Type): Type;
123+
}
124+
// Message: Missing @template Type
125+
126+
/**
127+
*
128+
*/
129+
export interface GenericIdentityFn<Type> {
130+
(arg: Type): Type;
131+
}
132+
// Message: Missing @template Type
133+
134+
/**
135+
*
136+
*/
137+
export default interface GenericIdentityFn<Type> {
138+
(arg: Type): Type;
139+
}
140+
// Message: Missing @template Type
117141
````
118142

119143

@@ -164,5 +188,26 @@ export type Extras<D, U, V> = [D, U, V | undefined];
164188
* @property {D} foo
165189
* @property {V} bar
166190
*/
191+
192+
/**
193+
* @template Type
194+
*/
195+
interface GenericIdentityFn<Type> {
196+
(arg: Type): Type;
197+
}
198+
199+
/**
200+
* @template Type
201+
*/
202+
export interface GenericIdentityFn<Type> {
203+
(arg: Type): Type;
204+
}
205+
206+
/**
207+
* @template Type
208+
*/
209+
export default interface GenericIdentityFn<Type> {
210+
(arg: Type): Type;
211+
}
167212
````
168213

src/rules/checkTemplateNames.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ export default iterateJsdoc(({
2020

2121
const usedNames = new Set();
2222
/**
23-
* @param {import('@typescript-eslint/types').TSESTree.TSTypeAliasDeclaration} aliasDeclaration
23+
* @param {import('@typescript-eslint/types').TSESTree.TSInterfaceDeclaration|
24+
* import('@typescript-eslint/types').TSESTree.TSTypeAliasDeclaration} aliasDeclaration
2425
*/
2526
const checkParameters = (aliasDeclaration) => {
2627
/* c8 ignore next -- Guard */
@@ -47,12 +48,17 @@ export default iterateJsdoc(({
4748
return;
4849
}
4950
switch (nde.type) {
51+
case 'ExportDefaultDeclaration':
5052
case 'ExportNamedDeclaration':
51-
if (nde.declaration?.type === 'TSTypeAliasDeclaration') {
52-
checkParameters(nde.declaration);
53+
switch (nde.declaration?.type) {
54+
case 'TSTypeAliasDeclaration':
55+
case 'TSInterfaceDeclaration':
56+
checkParameters(nde.declaration);
57+
break;
5358
}
5459
break;
5560
case 'TSTypeAliasDeclaration':
61+
case 'TSInterfaceDeclaration':
5662
checkParameters(nde);
5763
break;
5864
}

src/rules/requireTemplate.js

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,10 @@ export default iterateJsdoc(({
3535
}
3636

3737
/**
38-
* @param {import('@typescript-eslint/types').TSESTree.TSTypeAliasDeclaration} aliasDeclaration
38+
* @param {import('@typescript-eslint/types').TSESTree.TSInterfaceDeclaration|
39+
* import('@typescript-eslint/types').TSESTree.TSTypeAliasDeclaration} aliasDeclaration
3940
*/
40-
const checkParameters = (aliasDeclaration) => {
41+
const checkTypeParams = (aliasDeclaration) => {
4142
/* c8 ignore next -- Guard */
4243
const {params} = aliasDeclaration.typeParameters ?? {params: []};
4344
for (const {name: {name}} of params) {
@@ -50,28 +51,39 @@ export default iterateJsdoc(({
5051
}
5152
};
5253

53-
const handleTypeAliases = () => {
54+
const handleTypes = () => {
5455
const nde = /** @type {import('@typescript-eslint/types').TSESTree.Node} */ (
5556
node
5657
);
5758
if (!nde) {
5859
return;
5960
}
6061
switch (nde.type) {
62+
case 'ExportDefaultDeclaration':
63+
switch (nde.declaration?.type) {
64+
case 'TSInterfaceDeclaration':
65+
checkTypeParams(nde.declaration);
66+
break;
67+
}
68+
break;
6169
case 'ExportNamedDeclaration':
62-
if (nde.declaration?.type === 'TSTypeAliasDeclaration') {
63-
checkParameters(nde.declaration);
70+
switch (nde.declaration?.type) {
71+
case 'TSTypeAliasDeclaration':
72+
case 'TSInterfaceDeclaration':
73+
checkTypeParams(nde.declaration);
74+
break;
6475
}
6576
break;
6677
case 'TSTypeAliasDeclaration':
67-
checkParameters(nde);
78+
case 'TSInterfaceDeclaration':
79+
checkTypeParams(nde);
6880
break;
6981
}
7082
};
7183

7284
const typedefTags = utils.getTags('typedef');
7385
if (!typedefTags.length || typedefTags.length >= 2) {
74-
handleTypeAliases();
86+
handleTypes();
7587
return;
7688
}
7789

test/rules/assertions/checkTemplateNames.js

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,78 @@ export default {
158158
},
159159
],
160160
},
161+
{
162+
code: `
163+
/**
164+
* @template D
165+
* @template V
166+
*/
167+
interface GenericIdentityFn<Type> {
168+
(arg: Type): Type;
169+
}
170+
`,
171+
errors: [
172+
{
173+
line: 3,
174+
message: '@template D not in use',
175+
},
176+
{
177+
line: 4,
178+
message: '@template V not in use',
179+
},
180+
],
181+
languageOptions: {
182+
parser: typescriptEslintParser
183+
},
184+
},
185+
{
186+
code: `
187+
/**
188+
* @template D
189+
* @template V
190+
*/
191+
export interface GenericIdentityFn<Type> {
192+
(arg: Type): Type;
193+
}
194+
`,
195+
errors: [
196+
{
197+
line: 3,
198+
message: '@template D not in use',
199+
},
200+
{
201+
line: 4,
202+
message: '@template V not in use',
203+
},
204+
],
205+
languageOptions: {
206+
parser: typescriptEslintParser
207+
},
208+
},
209+
{
210+
code: `
211+
/**
212+
* @template D
213+
* @template V
214+
*/
215+
export default interface GenericIdentityFn<Type> {
216+
(arg: Type): Type;
217+
}
218+
`,
219+
errors: [
220+
{
221+
line: 3,
222+
message: '@template D not in use',
223+
},
224+
{
225+
line: 4,
226+
message: '@template V not in use',
227+
},
228+
],
229+
languageOptions: {
230+
parser: typescriptEslintParser
231+
},
232+
},
161233
],
162234
valid: [
163235
{
@@ -228,5 +300,44 @@ export default {
228300
*/
229301
`,
230302
},
303+
{
304+
code: `
305+
/**
306+
* @template Type
307+
*/
308+
interface GenericIdentityFn<Type> {
309+
(arg: Type): Type;
310+
}
311+
`,
312+
languageOptions: {
313+
parser: typescriptEslintParser
314+
},
315+
},
316+
{
317+
code: `
318+
/**
319+
* @template Type
320+
*/
321+
export interface GenericIdentityFn<Type> {
322+
(arg: Type): Type;
323+
}
324+
`,
325+
languageOptions: {
326+
parser: typescriptEslintParser
327+
},
328+
},
329+
{
330+
code: `
331+
/**
332+
* @template Type
333+
*/
334+
export default interface GenericIdentityFn<Type> {
335+
(arg: Type): Type;
336+
}
337+
`,
338+
languageOptions: {
339+
parser: typescriptEslintParser
340+
},
341+
},
231342
],
232343
};

0 commit comments

Comments
 (0)