Skip to content

Commit d46be35

Browse files
committed
feat(require-template): add rule; fixes part of #1120
1 parent 1bb8aa5 commit d46be35

13 files changed

+692
-71
lines changed

.README/README.md

+2
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ non-default-recommended fixer).
236236
|:heavy_check_mark:|:wrench:|[check-tag-names](./docs/rules/check-tag-names.md#readme)|Reports invalid jsdoc (block) tag names|
237237
|:heavy_check_mark:|:wrench:|[check-types](./docs/rules/check-types.md#readme)|Reports types deemed invalid (customizable and with defaults, for preventing and/or recommending replacements)|
238238
|:heavy_check_mark:||[check-values](./docs/rules/check-values.md#readme)|Checks for expected content within some miscellaneous tags (`@version`, `@since`, `@license`, `@author`)|
239+
| || [convert-to-jsdoc-comments](./docs/rules/convert-to-jsdoc-comments.md#readme) | Converts line and block comments preceding or following specified nodes into JSDoc comments|
239240
|:heavy_check_mark:|:wrench:|[empty-tags](./docs/rules/empty-tags.md#readme)|Checks tags that are expected to be empty (e.g., `@abstract` or `@async`), reporting if they have content|
240241
|:heavy_check_mark:||[implements-on-classes](./docs/rules/implements-on-classes.md#readme)|Prohibits use of `@implements` on non-constructor functions (to enforce the tag only being used on classes/constructors)|
241242
|||[informative-docs](./docs/rules/informative-docs.md#readme)|Reports on JSDoc texts that serve only to restate their attached name.|
@@ -270,6 +271,7 @@ non-default-recommended fixer).
270271
|:heavy_check_mark:||[require-returns-check](./docs/rules/require-returns-check.md#readme)|Requires a return statement be present in a function body if a `@returns` tag is specified in the jsdoc comment block (and reports if multiple `@returns` tags are present).|
271272
|:heavy_check_mark:||[require-returns-description](./docs/rules/require-returns-description.md#readme)|Requires that the `@returns` tag has a `description` value (not including `void`/`undefined` type returns).|
272273
|:heavy_check_mark: (off in TS)||[require-returns-type](./docs/rules/require-returns-type.md#readme)|Requires that `@returns` tag has a type value (in curly brackets).|
274+
| || [require-template](./docs/rules/require-template.md#readme) | Requires `@template` tags be present when type parameters are used.|
273275
|||[require-throws](./docs/rules/require-throws.md#readme)|Requires that throw statements are documented|
274276
|:heavy_check_mark:||[require-yields](./docs/rules/require-yields.md#readme)|Requires that yields are documented|
275277
|:heavy_check_mark:||[require-yields-check](./docs/rules/require-yields-check.md#readme)|Ensures that if a `@yields` is present that a `yield` (or `yield` with a value) is present in the function body (or that if a `@next` is present that there is a `yield` with a return value present)|

.README/rules/require-template.md

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# `require-template`
2+
3+
Checks to see that `@template` tags are present for any detected type
4+
parameters.
5+
6+
Currently checks `TSTypeAliasDeclaration` such as:
7+
8+
```ts
9+
export type Pairs<D, V> = [D, V | undefined];
10+
```
11+
12+
or
13+
14+
```js
15+
/**
16+
* @typedef {[D, V | undefined]} Pairs
17+
*/
18+
```
19+
20+
Note that in the latter TypeScript-flavor JavaScript example, there is no way
21+
for us to firmly distinguish between `D` and `V` as type parameters or as some
22+
other identifiers, so we use an algorithm that any single capital letters
23+
are assumed to be templates.
24+
25+
## Options
26+
27+
### `requireSeparateTemplates`
28+
29+
Requires that each template have its own separate line, i.e., preventing
30+
templates of this format:
31+
32+
```js
33+
/**
34+
* @template T, U, V
35+
*/
36+
```
37+
38+
Defaults to `false`.
39+
40+
|||
41+
|---|---|
42+
|Context|everywhere|
43+
|Tags|`template`|
44+
|Recommended|true|
45+
|Settings||
46+
|Options|`requireSeparateTemplates`|
47+
48+
## Failing examples
49+
50+
<!-- assertions-failing requireTemplate -->
51+
52+
## Passing examples
53+
54+
<!-- assertions-passing requireTemplate -->

.github/workflows/feature.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ jobs:
4242
node_js_version:
4343
- '18'
4444
- '20'
45+
- '22'
4546
build:
4647
runs-on: ubuntu-latest
4748
name: Build

.ncurc.cjs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
module.exports = {
44
reject: [
5-
// Todo: When package converted to ESM only
5+
// Todo: When our package converted to ESM only
66
'escape-string-regexp',
77

88
// todo[engine:node@>=20]: Can reenable

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ non-default-recommended fixer).
263263
|:heavy_check_mark:|:wrench:|[check-tag-names](./docs/rules/check-tag-names.md#readme)|Reports invalid jsdoc (block) tag names|
264264
|:heavy_check_mark:|:wrench:|[check-types](./docs/rules/check-types.md#readme)|Reports types deemed invalid (customizable and with defaults, for preventing and/or recommending replacements)|
265265
|:heavy_check_mark:||[check-values](./docs/rules/check-values.md#readme)|Checks for expected content within some miscellaneous tags (`@version`, `@since`, `@license`, `@author`)|
266+
| || [convert-to-jsdoc-comments](./docs/rules/convert-to-jsdoc-comments.md#readme) | Converts line and block comments preceding or following specified nodes into JSDoc comments|
266267
|:heavy_check_mark:|:wrench:|[empty-tags](./docs/rules/empty-tags.md#readme)|Checks tags that are expected to be empty (e.g., `@abstract` or `@async`), reporting if they have content|
267268
|:heavy_check_mark:||[implements-on-classes](./docs/rules/implements-on-classes.md#readme)|Prohibits use of `@implements` on non-constructor functions (to enforce the tag only being used on classes/constructors)|
268269
|||[informative-docs](./docs/rules/informative-docs.md#readme)|Reports on JSDoc texts that serve only to restate their attached name.|
@@ -297,6 +298,7 @@ non-default-recommended fixer).
297298
|:heavy_check_mark:||[require-returns-check](./docs/rules/require-returns-check.md#readme)|Requires a return statement be present in a function body if a `@returns` tag is specified in the jsdoc comment block (and reports if multiple `@returns` tags are present).|
298299
|:heavy_check_mark:||[require-returns-description](./docs/rules/require-returns-description.md#readme)|Requires that the `@returns` tag has a `description` value (not including `void`/`undefined` type returns).|
299300
|:heavy_check_mark: (off in TS)||[require-returns-type](./docs/rules/require-returns-type.md#readme)|Requires that `@returns` tag has a type value (in curly brackets).|
301+
| || [require-template](./docs/rules/require-template.md#readme) | Requires `@template` tags be present when type parameters are used.|
300302
|||[require-throws](./docs/rules/require-throws.md#readme)|Requires that throw statements are documented|
301303
|:heavy_check_mark:||[require-yields](./docs/rules/require-yields.md#readme)|Requires that yields are documented|
302304
|:heavy_check_mark:||[require-yields-check](./docs/rules/require-yields-check.md#readme)|Ensures that if a `@yields` is present that a `yield` (or `yield` with a value) is present in the function body (or that if a `@next` is present that there is a `yield` with a return value present)|

docs/rules/require-template.md

+147
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
<a name="user-content-require-template"></a>
2+
<a name="require-template"></a>
3+
# <code>require-template</code>
4+
5+
Checks to see that `@template` tags are present for any detected type
6+
parameters.
7+
8+
Currently checks `TSTypeAliasDeclaration` such as:
9+
10+
```ts
11+
export type Pairs<D, V> = [D, V | undefined];
12+
```
13+
14+
or
15+
16+
```js
17+
/**
18+
* @typedef {[D, V | undefined]} Pairs
19+
*/
20+
```
21+
22+
Note that in the latter TypeScript-flavor JavaScript example, there is no way
23+
for us to firmly distinguish between `D` and `V` as type parameters or as some
24+
other identifiers, so we use an algorithm that any single capital letters
25+
are assumed to be templates.
26+
27+
<a name="user-content-require-template-options"></a>
28+
<a name="require-template-options"></a>
29+
## Options
30+
31+
<a name="user-content-require-template-options-requireseparatetemplates"></a>
32+
<a name="require-template-options-requireseparatetemplates"></a>
33+
### <code>requireSeparateTemplates</code>
34+
35+
Requires that each template have its own separate line, i.e., preventing
36+
templates of this format:
37+
38+
```js
39+
/**
40+
* @template T, U, V
41+
*/
42+
```
43+
44+
Defaults to `false`.
45+
46+
|||
47+
|---|---|
48+
|Context|everywhere|
49+
|Tags|`template`|
50+
|Recommended|true|
51+
|Settings||
52+
|Options|`requireSeparateTemplates`|
53+
54+
<a name="user-content-require-template-failing-examples"></a>
55+
<a name="require-template-failing-examples"></a>
56+
## Failing examples
57+
58+
The following patterns are considered problems:
59+
60+
````js
61+
/**
62+
*
63+
*/
64+
type Pairs<D, V> = [D, V | undefined];
65+
// Message: Missing @template D
66+
67+
/**
68+
*
69+
*/
70+
export type Pairs<D, V> = [D, V | undefined];
71+
// Message: Missing @template D
72+
73+
/**
74+
* @typedef {[D, V | undefined]} Pairs
75+
*/
76+
// Message: Missing @template D
77+
78+
/**
79+
* @typedef {[D, V | undefined]} Pairs
80+
*/
81+
// Settings: {"jsdoc":{"mode":"permissive"}}
82+
// Message: Missing @template D
83+
84+
/**
85+
* @template D, U
86+
*/
87+
export type Extras<D, U, V> = [D, U, V | undefined];
88+
// Message: Missing @template V
89+
90+
/**
91+
* @template D, U
92+
* @typedef {[D, U, V | undefined]} Extras
93+
*/
94+
// Message: Missing @template V
95+
96+
/**
97+
* @template D, V
98+
*/
99+
export type Pairs<D, V> = [D, V | undefined];
100+
// "jsdoc/require-template": ["error"|"warn", {"requireSeparateTemplates":true}]
101+
// Message: Missing separate @template for V
102+
103+
/**
104+
* @template D, V
105+
* @typedef {[D, V | undefined]} Pairs
106+
*/
107+
// "jsdoc/require-template": ["error"|"warn", {"requireSeparateTemplates":true}]
108+
// Message: Missing separate @template for V
109+
````
110+
111+
112+
113+
<a name="user-content-require-template-passing-examples"></a>
114+
<a name="require-template-passing-examples"></a>
115+
## Passing examples
116+
117+
The following patterns are not considered problems:
118+
119+
````js
120+
/**
121+
* @template D
122+
* @template V
123+
*/
124+
export type Pairs<D, V> = [D, V | undefined];
125+
126+
/**
127+
* @template D
128+
* @template V
129+
* @typedef {[D, V | undefined]} Pairs
130+
*/
131+
132+
/**
133+
* @template D, U, V
134+
*/
135+
export type Extras<D, U, V> = [D, U, V | undefined];
136+
137+
/**
138+
* @template D, U, V
139+
* @typedef {[D, U, V | undefined]} Extras
140+
*/
141+
142+
/**
143+
* @typedef {[D, U, V | undefined]} Extras
144+
* @typedef {[D, U, V | undefined]} Extras
145+
*/
146+
````
147+

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"url": "http://gajus.com"
66
},
77
"dependencies": {
8-
"@es-joy/jsdoccomment": "~0.45.0",
8+
"@es-joy/jsdoccomment": "~0.46.0",
99
"are-docs-informative": "^0.0.2",
1010
"comment-parser": "1.4.1",
1111
"debug": "^4.3.5",
@@ -54,7 +54,7 @@
5454
"eslint": "9.6.0",
5555
"eslint-config-canonical": "~43.0.13",
5656
"espree": "^10.1.0",
57-
"gitdown": "^3.1.5",
57+
"gitdown": "^4.0.0",
5858
"glob": "^10.4.2",
5959
"globals": "^15.8.0",
6060
"husky": "^9.0.11",

0 commit comments

Comments
 (0)