@depup/eslint-plugin-jsdoc 64.0.2-depup.1 → 64.2.0-depup.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -9
- package/changes.json +3 -8
- package/dist/iterateJsdoc.d.ts +6 -2
- package/dist/rules.d.ts +21 -2
- package/package.json +9 -14
- package/src/iterateJsdoc.js +66 -34
- package/src/rules/checkParamNames.js +249 -19
- package/src/rules.d.ts +21 -2
package/README.md
CHANGED
|
@@ -13,16 +13,10 @@ npm install @depup/eslint-plugin-jsdoc
|
|
|
13
13
|
|
|
14
14
|
| Field | Value |
|
|
15
15
|
|-------|-------|
|
|
16
|
-
| Original | [eslint-plugin-jsdoc](https://www.npmjs.com/package/eslint-plugin-jsdoc) @ 64.0
|
|
17
|
-
| Processed | 2026-08-
|
|
16
|
+
| Original | [eslint-plugin-jsdoc](https://www.npmjs.com/package/eslint-plugin-jsdoc) @ 64.2.0 |
|
|
17
|
+
| Processed | 2026-08-15 |
|
|
18
18
|
| Smoke test | passed |
|
|
19
|
-
| Deps updated |
|
|
20
|
-
|
|
21
|
-
## Dependency Changes
|
|
22
|
-
|
|
23
|
-
| Dependency | From | To |
|
|
24
|
-
|------------|------|-----|
|
|
25
|
-
| @es-joy/jsdoccomment | ~0.93.2 | ^0.94.0 |
|
|
19
|
+
| Deps updated | 0 |
|
|
26
20
|
|
|
27
21
|
---
|
|
28
22
|
|
package/changes.json
CHANGED
package/dist/iterateJsdoc.d.ts
CHANGED
|
@@ -52,12 +52,16 @@ export type BasicUtils = {
|
|
|
52
52
|
export type IsIteratingFunction = () => boolean;
|
|
53
53
|
export type IsVirtualFunction = () => boolean;
|
|
54
54
|
export type Stringify = (tagBlock: import("comment-parser").Block, specRewire?: boolean | undefined) => string;
|
|
55
|
+
export type JsdocSuggestions = {
|
|
56
|
+
desc: string;
|
|
57
|
+
handler: (fixer: import("eslint").Rule.RuleFixer) => import("eslint").Rule.Fix | void;
|
|
58
|
+
}[];
|
|
55
59
|
export type ReportJSDoc = (msg: string, tag?: import("comment-parser").Spec | {
|
|
56
60
|
line: Integer;
|
|
57
61
|
column?: Integer;
|
|
58
62
|
} | null | undefined, handler?: ((fixer: import("eslint").Rule.RuleFixer) => import("eslint").Rule.Fix | void) | null | undefined, specRewire?: boolean | undefined, data?: undefined | {
|
|
59
63
|
[key: string]: string;
|
|
60
|
-
}) => any;
|
|
64
|
+
}, suggestions?: JsdocSuggestions | undefined) => any;
|
|
61
65
|
export type GetRegexFromString = (str: string, requiredFlags?: string | undefined) => RegExp;
|
|
62
66
|
export type GetTagDescription = (tg: import("comment-parser").Spec, returnArray?: boolean | undefined) => string[] | string;
|
|
63
67
|
export type SetTagDescription = (tg: import("comment-parser").Spec, matcher: RegExp, setter: (description: string) => string) => Integer;
|
|
@@ -256,7 +260,7 @@ export type Report = (message: string, fix?: import("@eslint/core").RuleFixer |
|
|
|
256
260
|
line?: Integer;
|
|
257
261
|
}) | null | undefined, data?: undefined | {
|
|
258
262
|
[key: string]: string;
|
|
259
|
-
}) => void;
|
|
263
|
+
}, suggest?: import("eslint").Rule.SuggestionReportDescriptor[] | undefined) => void;
|
|
260
264
|
export type PreferredTypes = {
|
|
261
265
|
[key: string]: false | string | {
|
|
262
266
|
message: string;
|
package/dist/rules.d.ts
CHANGED
|
@@ -143,6 +143,16 @@ export interface Rules {
|
|
|
143
143
|
* `@param`'s and present function parameters will still be reported.
|
|
144
144
|
*/
|
|
145
145
|
allowExtraTrailingParamDocs?: boolean;
|
|
146
|
+
/**
|
|
147
|
+
* Whether to offer a suggestion to rename a mismatched `@param` to the
|
|
148
|
+
* corresponding function parameter name. Defaults to `false`.
|
|
149
|
+
*/
|
|
150
|
+
badParamNames?: boolean;
|
|
151
|
+
/**
|
|
152
|
+
* Whether to report `@param` definitions whose names match the function
|
|
153
|
+
* parameters but appear in a different order. Defaults to `true`.
|
|
154
|
+
*/
|
|
155
|
+
badParamOrder?: boolean;
|
|
146
156
|
/**
|
|
147
157
|
* Whether to check destructured properties. Defaults to `true`.
|
|
148
158
|
*/
|
|
@@ -206,14 +216,23 @@ export interface Rules {
|
|
|
206
216
|
*/
|
|
207
217
|
disableMissingParamChecks?: boolean;
|
|
208
218
|
/**
|
|
209
|
-
*
|
|
210
|
-
|
|
219
|
+
* Whether to report duplicate `@param` definitions. Defaults to `true`.
|
|
220
|
+
*/
|
|
221
|
+
duplicateParams?: boolean;
|
|
222
|
+
/**
|
|
223
|
+
* Set to `true` to reorder non-nested `@param` definitions to match the
|
|
224
|
+
* function signature and to auto-remove duplicates (based on identical names).
|
|
211
225
|
*
|
|
212
226
|
* Note that this option will remove duplicates of the same name even if
|
|
213
227
|
* the definitions do not match in other ways (e.g., the second param will
|
|
214
228
|
* be removed even if it has a different type or description).
|
|
215
229
|
*/
|
|
216
230
|
enableFixer?: boolean;
|
|
231
|
+
/**
|
|
232
|
+
* Whether to offer a suggestion to remove an `@param` that has no
|
|
233
|
+
* corresponding function parameter. Defaults to `false`.
|
|
234
|
+
*/
|
|
235
|
+
extraParams?: boolean;
|
|
217
236
|
/**
|
|
218
237
|
* Set to `true` if you wish to avoid reporting of child property documentation
|
|
219
238
|
* where instead of destructuring, a whole plain object is supplied as default
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"url": "http://gajus.com"
|
|
6
6
|
},
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@es-joy/jsdoccomment": "
|
|
8
|
+
"@es-joy/jsdoccomment": "~0.95.0",
|
|
9
9
|
"@es-joy/resolve.exports": "1.2.0",
|
|
10
10
|
"are-docs-informative": "^0.1.1",
|
|
11
11
|
"comment-parser": "1.4.8",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"@types/node": "^26.2.0",
|
|
44
44
|
"@types/semver": "^7.8.0",
|
|
45
45
|
"@types/spdx-expression-parse": "^4.0.0",
|
|
46
|
-
"@typescript-eslint/types": "8.
|
|
46
|
+
"@typescript-eslint/types": "8.67.0",
|
|
47
47
|
"babel-plugin-add-module-exports": "^1.0.4",
|
|
48
48
|
"babel-plugin-transform-import-meta": "^3.0.0",
|
|
49
49
|
"c8": "^12.0.0",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"glob": "^13.0.6",
|
|
57
57
|
"globals": "^17.9.0",
|
|
58
58
|
"husky": "^9.1.7",
|
|
59
|
-
"jsdoc-type-pratt-parser": "^9.
|
|
59
|
+
"jsdoc-type-pratt-parser": "^9.1.1",
|
|
60
60
|
"json-schema": "^0.4.0",
|
|
61
61
|
"json-schema-to-typescript": "^15.0.4",
|
|
62
62
|
"lint-staged": "^17.3.0",
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"sinon": "^22.1.0",
|
|
70
70
|
"ts-api-utils": "^2.5.0",
|
|
71
71
|
"typescript": "5.9.3",
|
|
72
|
-
"typescript-eslint": "8.
|
|
72
|
+
"typescript-eslint": "8.67.0"
|
|
73
73
|
},
|
|
74
74
|
"engines": {
|
|
75
75
|
"node": "^22.22.2 || >=24.15.0"
|
|
@@ -160,18 +160,13 @@
|
|
|
160
160
|
"test-cov": "TIMING=1 c8 --reporter text pnpm run test-no-cov",
|
|
161
161
|
"test-index": "pnpm run test-no-cov test/rules/index.js"
|
|
162
162
|
},
|
|
163
|
-
"version": "64.0
|
|
163
|
+
"version": "64.2.0-depup.0",
|
|
164
164
|
"depup": {
|
|
165
|
-
"changes": {
|
|
166
|
-
|
|
167
|
-
"from": "~0.93.2",
|
|
168
|
-
"to": "^0.94.0"
|
|
169
|
-
}
|
|
170
|
-
},
|
|
171
|
-
"depsUpdated": 1,
|
|
165
|
+
"changes": {},
|
|
166
|
+
"depsUpdated": 0,
|
|
172
167
|
"originalPackage": "eslint-plugin-jsdoc",
|
|
173
|
-
"originalVersion": "64.0
|
|
174
|
-
"processedAt": "2026-08-
|
|
168
|
+
"originalVersion": "64.2.0",
|
|
169
|
+
"processedAt": "2026-08-15T08:07:17.964Z",
|
|
175
170
|
"smokeTest": "passed"
|
|
176
171
|
}
|
|
177
172
|
}
|
package/src/iterateJsdoc.js
CHANGED
|
@@ -117,6 +117,13 @@ import esquery from 'esquery';
|
|
|
117
117
|
* @returns {string}
|
|
118
118
|
*/
|
|
119
119
|
|
|
120
|
+
/**
|
|
121
|
+
* @typedef {{
|
|
122
|
+
* desc: string,
|
|
123
|
+
* handler: (fixer: import('eslint').Rule.RuleFixer) => import('eslint').Rule.Fix|void
|
|
124
|
+
* }[]} JsdocSuggestions
|
|
125
|
+
*/
|
|
126
|
+
|
|
120
127
|
/**
|
|
121
128
|
* @callback ReportJSDoc
|
|
122
129
|
* @param {string} msg
|
|
@@ -126,6 +133,7 @@ import esquery from 'esquery';
|
|
|
126
133
|
* @param {undefined|{
|
|
127
134
|
* [key: string]: string
|
|
128
135
|
* }} [data]
|
|
136
|
+
* @param {JsdocSuggestions} [suggestions]
|
|
129
137
|
*/
|
|
130
138
|
|
|
131
139
|
/**
|
|
@@ -698,6 +706,7 @@ const getBasicUtils = (context, {
|
|
|
698
706
|
* @param {undefined|{
|
|
699
707
|
* [key: string]: string
|
|
700
708
|
* }} [data]
|
|
709
|
+
* @param {import('eslint').Rule.SuggestionReportDescriptor[]} [suggest]
|
|
701
710
|
* @returns {void}
|
|
702
711
|
*/
|
|
703
712
|
|
|
@@ -808,24 +817,42 @@ const getUtils = (
|
|
|
808
817
|
};
|
|
809
818
|
|
|
810
819
|
/** @type {ReportJSDoc} */
|
|
811
|
-
utils.reportJSDoc = (msg, tag, handler, specRewire, data) => {
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
const
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
820
|
+
utils.reportJSDoc = (msg, tag, handler, specRewire, data, suggestions) => {
|
|
821
|
+
/**
|
|
822
|
+
* @param {(fixer: import('eslint').Rule.RuleFixer) => import('eslint').Rule.Fix|void} fixHandler
|
|
823
|
+
* @returns {import('eslint').Rule.ReportFixer}
|
|
824
|
+
*/
|
|
825
|
+
const makeFix = (fixHandler) => {
|
|
826
|
+
return (fixer) => {
|
|
827
|
+
const extraFix = fixHandler(fixer);
|
|
828
|
+
|
|
829
|
+
const replacement = utils.stringify(jsdoc, specRewire);
|
|
830
|
+
|
|
831
|
+
if (!replacement) {
|
|
832
|
+
const text = sourceCode.getText();
|
|
833
|
+
const lastLineBreakPos = text.slice(
|
|
834
|
+
0, jsdocNode.range[0],
|
|
835
|
+
).search(/\n[ \t]*$/v);
|
|
836
|
+
if (lastLineBreakPos > -1) {
|
|
837
|
+
return [
|
|
838
|
+
fixer.removeRange([
|
|
839
|
+
lastLineBreakPos, jsdocNode.range[1],
|
|
840
|
+
]),
|
|
841
|
+
/* c8 ignore next 2 -- Guard */
|
|
842
|
+
...(extraFix ? [
|
|
843
|
+
extraFix,
|
|
844
|
+
] : []),
|
|
845
|
+
];
|
|
846
|
+
}
|
|
847
|
+
|
|
825
848
|
return [
|
|
826
|
-
fixer.removeRange(
|
|
827
|
-
|
|
828
|
-
|
|
849
|
+
fixer.removeRange(
|
|
850
|
+
(/\s/v).test(text.charAt(jsdocNode.range[1])) ?
|
|
851
|
+
[
|
|
852
|
+
jsdocNode.range[0], jsdocNode.range[1] + 1,
|
|
853
|
+
] :
|
|
854
|
+
jsdocNode.range,
|
|
855
|
+
),
|
|
829
856
|
/* c8 ignore next 2 -- Guard */
|
|
830
857
|
...(extraFix ? [
|
|
831
858
|
extraFix,
|
|
@@ -834,27 +861,29 @@ const getUtils = (
|
|
|
834
861
|
}
|
|
835
862
|
|
|
836
863
|
return [
|
|
837
|
-
fixer.
|
|
838
|
-
(/\s/v).test(text.charAt(jsdocNode.range[1])) ?
|
|
839
|
-
[
|
|
840
|
-
jsdocNode.range[0], jsdocNode.range[1] + 1,
|
|
841
|
-
] :
|
|
842
|
-
jsdocNode.range,
|
|
843
|
-
),
|
|
844
|
-
/* c8 ignore next 2 -- Guard */
|
|
864
|
+
fixer.replaceText(jsdocNode, replacement),
|
|
845
865
|
...(extraFix ? [
|
|
846
866
|
extraFix,
|
|
847
867
|
] : []),
|
|
848
868
|
];
|
|
849
|
-
}
|
|
869
|
+
};
|
|
870
|
+
};
|
|
850
871
|
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
872
|
+
report(
|
|
873
|
+
msg,
|
|
874
|
+
handler ? makeFix(handler) : null,
|
|
875
|
+
tag,
|
|
876
|
+
data,
|
|
877
|
+
suggestions?.map(({
|
|
878
|
+
desc,
|
|
879
|
+
handler: suggestionHandler,
|
|
880
|
+
}) => {
|
|
881
|
+
return {
|
|
882
|
+
desc,
|
|
883
|
+
fix: makeFix(suggestionHandler),
|
|
884
|
+
};
|
|
885
|
+
}),
|
|
886
|
+
);
|
|
858
887
|
};
|
|
859
888
|
|
|
860
889
|
/** @type {GetRegexFromString} */
|
|
@@ -1911,7 +1940,9 @@ const getSettings = (context) => {
|
|
|
1911
1940
|
/** @type {MakeReport} */
|
|
1912
1941
|
const makeReport = (context, commentNode) => {
|
|
1913
1942
|
/** @type {Report} */
|
|
1914
|
-
const report = (
|
|
1943
|
+
const report = (
|
|
1944
|
+
message, fix = null, jsdocLoc = null, data = undefined, suggest = undefined,
|
|
1945
|
+
) => {
|
|
1915
1946
|
let loc;
|
|
1916
1947
|
|
|
1917
1948
|
if (jsdocLoc) {
|
|
@@ -1953,6 +1984,7 @@ const makeReport = (context, commentNode) => {
|
|
|
1953
1984
|
loc,
|
|
1954
1985
|
message,
|
|
1955
1986
|
node: commentNode,
|
|
1987
|
+
suggest,
|
|
1956
1988
|
});
|
|
1957
1989
|
};
|
|
1958
1990
|
|
|
@@ -1,14 +1,107 @@
|
|
|
1
1
|
import iterateJsdoc from '../iterateJsdoc.js';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* @param {import('../jsdocUtils.js').ParamNameInfo} parameter
|
|
5
|
+
* @returns {string|undefined}
|
|
6
|
+
*/
|
|
7
|
+
const getSimpleParameterName = (parameter) => {
|
|
8
|
+
if (typeof parameter === 'string') {
|
|
9
|
+
return parameter;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (
|
|
13
|
+
!parameter ||
|
|
14
|
+
Array.isArray(parameter) ||
|
|
15
|
+
typeof parameter !== 'object' ||
|
|
16
|
+
!('name' in parameter) ||
|
|
17
|
+
typeof parameter.name !== 'string'
|
|
18
|
+
) {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return parameter.name;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @param {import('../iterateJsdoc.js').Integer} firstChangedTagIndex
|
|
27
|
+
* @param {import('comment-parser').Spec[]} orderedTags
|
|
28
|
+
* @param {import('comment-parser').Block} jsdoc
|
|
29
|
+
* @param {import('../iterateJsdoc.js').Utils} utils
|
|
30
|
+
* @returns {() => void}
|
|
31
|
+
*/
|
|
32
|
+
const makeParamOrderFix = (
|
|
33
|
+
firstChangedTagIndex, orderedTags, jsdoc, utils,
|
|
34
|
+
) => {
|
|
35
|
+
return () => {
|
|
36
|
+
const itemsToMoveRange = [
|
|
37
|
+
...Array.from({
|
|
38
|
+
length: jsdoc.tags.length - firstChangedTagIndex,
|
|
39
|
+
}).keys(),
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
const unchangedPriorTagDescriptions = jsdoc.tags.slice(
|
|
43
|
+
0,
|
|
44
|
+
firstChangedTagIndex,
|
|
45
|
+
).reduce((count, {
|
|
46
|
+
source,
|
|
47
|
+
}) => {
|
|
48
|
+
return count + source.length - 1;
|
|
49
|
+
}, 0);
|
|
50
|
+
|
|
51
|
+
const initialOffset =
|
|
52
|
+
/** @type {import('../iterateJsdoc.js').Integer} */ (utils.getFirstLine()) +
|
|
53
|
+
firstChangedTagIndex + unchangedPriorTagDescriptions;
|
|
54
|
+
|
|
55
|
+
for (const index of itemsToMoveRange) {
|
|
56
|
+
utils.removeTag(index + firstChangedTagIndex);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const changedTags = orderedTags.slice(firstChangedTagIndex);
|
|
60
|
+
let extraTagCount = 0;
|
|
61
|
+
|
|
62
|
+
for (const index of itemsToMoveRange) {
|
|
63
|
+
const changedTag = changedTags[index];
|
|
64
|
+
|
|
65
|
+
utils.addTag(
|
|
66
|
+
changedTag.tag,
|
|
67
|
+
extraTagCount + initialOffset + index,
|
|
68
|
+
{
|
|
69
|
+
...changedTag.source[0].tokens,
|
|
70
|
+
end: '',
|
|
71
|
+
},
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
for (const {
|
|
75
|
+
tokens,
|
|
76
|
+
} of changedTag.source.slice(1)) {
|
|
77
|
+
if (!tokens.end) {
|
|
78
|
+
utils.addLine(
|
|
79
|
+
extraTagCount + initialOffset + index + 1,
|
|
80
|
+
{
|
|
81
|
+
...tokens,
|
|
82
|
+
end: '',
|
|
83
|
+
},
|
|
84
|
+
);
|
|
85
|
+
extraTagCount++;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
|
|
3
92
|
/**
|
|
4
93
|
* @param {string} targetTagName
|
|
5
94
|
* @param {boolean} allowExtraTrailingParamDocs
|
|
95
|
+
* @param {boolean} badParamNames
|
|
96
|
+
* @param {boolean} badParamOrder
|
|
6
97
|
* @param {boolean} checkDestructured
|
|
7
98
|
* @param {boolean} checkRestProperty
|
|
8
99
|
* @param {RegExp} checkTypesRegex
|
|
9
100
|
* @param {boolean} disableExtraPropertyReporting
|
|
10
101
|
* @param {boolean} disableMissingParamChecks
|
|
102
|
+
* @param {boolean} duplicateParams
|
|
11
103
|
* @param {boolean} enableFixer
|
|
104
|
+
* @param {boolean} extraParams
|
|
12
105
|
* @param {import('../jsdocUtils.js').ParamNameInfo[]} functionParameterNames
|
|
13
106
|
* @param {import('comment-parser').Block} jsdoc
|
|
14
107
|
* @param {import('../iterateJsdoc.js').Utils} utils
|
|
@@ -18,12 +111,16 @@ import iterateJsdoc from '../iterateJsdoc.js';
|
|
|
18
111
|
const validateParameterNames = (
|
|
19
112
|
targetTagName,
|
|
20
113
|
allowExtraTrailingParamDocs,
|
|
114
|
+
badParamNames,
|
|
115
|
+
badParamOrder,
|
|
21
116
|
checkDestructured,
|
|
22
117
|
checkRestProperty,
|
|
23
118
|
checkTypesRegex,
|
|
24
119
|
disableExtraPropertyReporting,
|
|
25
120
|
disableMissingParamChecks,
|
|
121
|
+
duplicateParams,
|
|
26
122
|
enableFixer,
|
|
123
|
+
extraParams,
|
|
27
124
|
functionParameterNames, jsdoc, utils, report,
|
|
28
125
|
) => {
|
|
29
126
|
const paramTags = Object.entries(jsdoc.tags).filter(([
|
|
@@ -36,12 +133,39 @@ const validateParameterNames = (
|
|
|
36
133
|
]) => {
|
|
37
134
|
return !tag.name.includes('.');
|
|
38
135
|
});
|
|
136
|
+
const actualParamNames = paramTagsNonNested.map(([
|
|
137
|
+
, tag,
|
|
138
|
+
]) => {
|
|
139
|
+
return tag.name.trim();
|
|
140
|
+
});
|
|
141
|
+
const documentsThis = actualParamNames.includes('this');
|
|
142
|
+
const simpleFunctionParameterNames = functionParameterNames.filter((parameter) => {
|
|
143
|
+
return documentsThis || parameter !== 'this';
|
|
144
|
+
}).map(getSimpleParameterName);
|
|
145
|
+
const hasOnlySimpleParameterNames = simpleFunctionParameterNames.every((name) => {
|
|
146
|
+
return name !== undefined;
|
|
147
|
+
});
|
|
148
|
+
const expectedParamNames = /** @type {string[]} */ (simpleFunctionParameterNames);
|
|
149
|
+
const sortedActualParamNames = actualParamNames.toSorted();
|
|
150
|
+
const sortedExpectedParamNames = expectedParamNames.toSorted();
|
|
151
|
+
const sameParamNames = hasOnlySimpleParameterNames &&
|
|
152
|
+
actualParamNames.length === expectedParamNames.length &&
|
|
153
|
+
sortedActualParamNames.every((name, index) => {
|
|
154
|
+
return name === sortedExpectedParamNames[index];
|
|
155
|
+
});
|
|
156
|
+
const isBadParamOrder = sameParamNames && actualParamNames.some((name, index) => {
|
|
157
|
+
return name !== expectedParamNames[index];
|
|
158
|
+
});
|
|
159
|
+
const canFixParamOrder =
|
|
160
|
+
paramTags.length === paramTagsNonNested.length &&
|
|
161
|
+
new Set(actualParamNames).size === actualParamNames.length;
|
|
39
162
|
|
|
40
163
|
let dotted = 0;
|
|
41
164
|
let thisOffset = 0;
|
|
42
165
|
|
|
43
166
|
return paramTags.some(([
|
|
44
|
-
,
|
|
167
|
+
,
|
|
168
|
+
tag,
|
|
45
169
|
// eslint-disable-next-line complexity
|
|
46
170
|
], index) => {
|
|
47
171
|
/** @type {import('../iterateJsdoc.js').Integer} */
|
|
@@ -54,7 +178,7 @@ const validateParameterNames = (
|
|
|
54
178
|
|
|
55
179
|
return tg.name === tag.name && idx !== index;
|
|
56
180
|
});
|
|
57
|
-
if (dupeTagInfo) {
|
|
181
|
+
if (dupeTagInfo && duplicateParams) {
|
|
58
182
|
utils.reportJSDoc(`Duplicate @${targetTagName} "${tag.name}"`, dupeTagInfo[1], enableFixer ? () => {
|
|
59
183
|
utils.removeTag(tagsIndex);
|
|
60
184
|
} : null);
|
|
@@ -62,6 +186,14 @@ const validateParameterNames = (
|
|
|
62
186
|
return true;
|
|
63
187
|
}
|
|
64
188
|
|
|
189
|
+
if (!duplicateParams && paramTags.some(([
|
|
190
|
+
, earlierTag,
|
|
191
|
+
], earlierIndex) => {
|
|
192
|
+
return earlierIndex < index && earlierTag.name === tag.name;
|
|
193
|
+
})) {
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
|
|
65
197
|
if (tag.name.includes('.')) {
|
|
66
198
|
dotted++;
|
|
67
199
|
|
|
@@ -69,7 +201,7 @@ const validateParameterNames = (
|
|
|
69
201
|
}
|
|
70
202
|
|
|
71
203
|
let functionParameterName = functionParameterNames[index - dotted + thisOffset];
|
|
72
|
-
if (functionParameterName === 'this' && tag.name.trim() !== 'this') {
|
|
204
|
+
if (!documentsThis && functionParameterName === 'this' && tag.name.trim() !== 'this') {
|
|
73
205
|
++thisOffset;
|
|
74
206
|
functionParameterName = functionParameterNames[index - dotted + thisOffset];
|
|
75
207
|
}
|
|
@@ -79,10 +211,25 @@ const validateParameterNames = (
|
|
|
79
211
|
return false;
|
|
80
212
|
}
|
|
81
213
|
|
|
82
|
-
|
|
214
|
+
const removeExtraParam = () => {
|
|
215
|
+
const currentTagIndex = jsdoc.tags.indexOf(tag);
|
|
216
|
+
if (currentTagIndex !== -1) {
|
|
217
|
+
utils.removeTag(currentTagIndex);
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
utils.reportJSDoc(
|
|
83
222
|
`@${targetTagName} "${tag.name}" does not match an existing function parameter.`,
|
|
84
|
-
null,
|
|
85
223
|
tag,
|
|
224
|
+
extraParams ? removeExtraParam : null,
|
|
225
|
+
false,
|
|
226
|
+
undefined,
|
|
227
|
+
[
|
|
228
|
+
{
|
|
229
|
+
desc: `Remove the extra @${targetTagName} "${tag.name}".`,
|
|
230
|
+
handler: removeExtraParam,
|
|
231
|
+
},
|
|
232
|
+
],
|
|
86
233
|
);
|
|
87
234
|
|
|
88
235
|
return true;
|
|
@@ -267,8 +414,59 @@ const validateParameterNames = (
|
|
|
267
414
|
|
|
268
415
|
return item;
|
|
269
416
|
}).filter((item) => {
|
|
270
|
-
return item !== 'this';
|
|
417
|
+
return documentsThis || item !== 'this';
|
|
271
418
|
});
|
|
419
|
+
const message = `Expected @${targetTagName} names to be "${
|
|
420
|
+
expectedNames.map((expectedName) => {
|
|
421
|
+
return typeof expectedName === 'object' &&
|
|
422
|
+
'name' in expectedName &&
|
|
423
|
+
expectedName.restElement ?
|
|
424
|
+
'...' + expectedName.name :
|
|
425
|
+
expectedName;
|
|
426
|
+
}).join(', ')
|
|
427
|
+
}". Got "${actualNames.join(', ')}".`;
|
|
428
|
+
|
|
429
|
+
if (isBadParamOrder) {
|
|
430
|
+
if (!badParamOrder) {
|
|
431
|
+
return false;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
let orderFix = null;
|
|
435
|
+
if (enableFixer && canFixParamOrder) {
|
|
436
|
+
const orderedTags =
|
|
437
|
+
/** @type {import('comment-parser').Spec[]} */ (
|
|
438
|
+
JSON.parse(JSON.stringify(jsdoc.tags))
|
|
439
|
+
);
|
|
440
|
+
for (const [
|
|
441
|
+
paramIndex,
|
|
442
|
+
expectedName,
|
|
443
|
+
] of expectedParamNames.entries()) {
|
|
444
|
+
const matchingTag = /** @type {[string, import('comment-parser').Spec]} */ (
|
|
445
|
+
paramTagsNonNested.find(([
|
|
446
|
+
, candidateTag,
|
|
447
|
+
]) => {
|
|
448
|
+
return candidateTag.name.trim() === expectedName;
|
|
449
|
+
})
|
|
450
|
+
);
|
|
451
|
+
orderedTags[Number(paramTagsNonNested[paramIndex][0])] =
|
|
452
|
+
JSON.parse(JSON.stringify(matchingTag[1]));
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
const firstChangedParamIndex = actualParamNames.findIndex((name, paramIndex) => {
|
|
456
|
+
return name !== expectedParamNames[paramIndex];
|
|
457
|
+
});
|
|
458
|
+
orderFix = makeParamOrderFix(
|
|
459
|
+
Number(paramTagsNonNested[firstChangedParamIndex][0]),
|
|
460
|
+
orderedTags,
|
|
461
|
+
jsdoc,
|
|
462
|
+
utils,
|
|
463
|
+
);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
utils.reportJSDoc(message, tag, orderFix, true);
|
|
467
|
+
|
|
468
|
+
return true;
|
|
469
|
+
}
|
|
272
470
|
|
|
273
471
|
// When disableMissingParamChecks is true tag names can be omitted.
|
|
274
472
|
// Report when the tag names do not match the expected names or they are used out of order.
|
|
@@ -286,18 +484,22 @@ const validateParameterNames = (
|
|
|
286
484
|
}
|
|
287
485
|
}
|
|
288
486
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
'...' + expectedName.name :
|
|
296
|
-
expectedName;
|
|
297
|
-
}).join(', ')
|
|
298
|
-
}". Got "${actualNames.join(', ')}".`,
|
|
299
|
-
null,
|
|
487
|
+
const renameBadParam = () => {
|
|
488
|
+
tag.source[0].tokens.name = String(funcParamName);
|
|
489
|
+
};
|
|
490
|
+
|
|
491
|
+
utils.reportJSDoc(
|
|
492
|
+
message,
|
|
300
493
|
tag,
|
|
494
|
+
badParamNames ? renameBadParam : null,
|
|
495
|
+
true,
|
|
496
|
+
undefined,
|
|
497
|
+
[
|
|
498
|
+
{
|
|
499
|
+
desc: `Rename @${targetTagName} "${tag.name.trim()}" to "${funcParamName}".`,
|
|
500
|
+
handler: renameBadParam,
|
|
501
|
+
},
|
|
502
|
+
],
|
|
301
503
|
);
|
|
302
504
|
|
|
303
505
|
return true;
|
|
@@ -377,12 +579,16 @@ export default iterateJsdoc(({
|
|
|
377
579
|
}) => {
|
|
378
580
|
const {
|
|
379
581
|
allowExtraTrailingParamDocs,
|
|
582
|
+
badParamNames = false,
|
|
583
|
+
badParamOrder = true,
|
|
380
584
|
checkDestructured = true,
|
|
381
585
|
checkRestProperty = false,
|
|
382
586
|
checkTypesPattern = '/^(?:[oO]bject|[aA]rray|PlainObject|Generic(?:Object|Array))$/',
|
|
383
587
|
disableExtraPropertyReporting = false,
|
|
384
588
|
disableMissingParamChecks = false,
|
|
589
|
+
duplicateParams = true,
|
|
385
590
|
enableFixer = false,
|
|
591
|
+
extraParams = false,
|
|
386
592
|
useDefaultObjectProperties = false,
|
|
387
593
|
} = context.options[0] || {};
|
|
388
594
|
|
|
@@ -416,12 +622,16 @@ export default iterateJsdoc(({
|
|
|
416
622
|
const isError = validateParameterNames(
|
|
417
623
|
targetTagName,
|
|
418
624
|
allowExtraTrailingParamDocs,
|
|
625
|
+
badParamNames,
|
|
626
|
+
badParamOrder,
|
|
419
627
|
checkDestructured,
|
|
420
628
|
checkRestProperty,
|
|
421
629
|
checkTypesRegex,
|
|
422
630
|
disableExtraPropertyReporting,
|
|
423
631
|
disableMissingParamChecks,
|
|
632
|
+
duplicateParams,
|
|
424
633
|
enableFixer,
|
|
634
|
+
extraParams,
|
|
425
635
|
functionParameterNames,
|
|
426
636
|
jsdoc,
|
|
427
637
|
utils,
|
|
@@ -443,6 +653,7 @@ export default iterateJsdoc(({
|
|
|
443
653
|
url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-param-names.md#repos-sticky-header',
|
|
444
654
|
},
|
|
445
655
|
fixable: 'code',
|
|
656
|
+
hasSuggestions: true,
|
|
446
657
|
schema: [
|
|
447
658
|
{
|
|
448
659
|
additionalProperties: false,
|
|
@@ -454,6 +665,16 @@ their presence within the function signature. Other inconsistencies between
|
|
|
454
665
|
\`@param\`'s and present function parameters will still be reported.`,
|
|
455
666
|
type: 'boolean',
|
|
456
667
|
},
|
|
668
|
+
badParamNames: {
|
|
669
|
+
description: `Whether to auto-fix a mismatched \`@param\` name to the corresponding
|
|
670
|
+
function parameter name. A suggestion is always offered. Defaults to \`false\`.`,
|
|
671
|
+
type: 'boolean',
|
|
672
|
+
},
|
|
673
|
+
badParamOrder: {
|
|
674
|
+
description: `Whether to report \`@param\` definitions whose names match the function
|
|
675
|
+
parameters but appear in a different order. Defaults to \`true\`.`,
|
|
676
|
+
type: 'boolean',
|
|
677
|
+
},
|
|
457
678
|
checkDestructured: {
|
|
458
679
|
description: 'Whether to check destructured properties. Defaults to `true`.',
|
|
459
680
|
type: 'boolean',
|
|
@@ -516,15 +737,24 @@ that are available and actually used in the function.`,
|
|
|
516
737
|
description: 'Whether to avoid checks for missing `@param` definitions. Defaults to `false`. Change to `true` if you want to be able to omit properties.',
|
|
517
738
|
type: 'boolean',
|
|
518
739
|
},
|
|
740
|
+
duplicateParams: {
|
|
741
|
+
description: 'Whether to report duplicate `@param` definitions. Defaults to `true`.',
|
|
742
|
+
type: 'boolean',
|
|
743
|
+
},
|
|
519
744
|
enableFixer: {
|
|
520
|
-
description: `Set to \`true\` to
|
|
521
|
-
names).
|
|
745
|
+
description: `Set to \`true\` to reorder non-nested \`@param\` definitions to match the
|
|
746
|
+
function signature and to auto-remove duplicates (based on identical names).
|
|
522
747
|
|
|
523
748
|
Note that this option will remove duplicates of the same name even if
|
|
524
749
|
the definitions do not match in other ways (e.g., the second param will
|
|
525
750
|
be removed even if it has a different type or description).`,
|
|
526
751
|
type: 'boolean',
|
|
527
752
|
},
|
|
753
|
+
extraParams: {
|
|
754
|
+
description: `Whether to auto-remove an \`@param\` that has no corresponding function
|
|
755
|
+
parameter. A suggestion is always offered. Defaults to \`false\`.`,
|
|
756
|
+
type: 'boolean',
|
|
757
|
+
},
|
|
528
758
|
useDefaultObjectProperties: {
|
|
529
759
|
description: `Set to \`true\` if you wish to avoid reporting of child property documentation
|
|
530
760
|
where instead of destructuring, a whole plain object is supplied as default
|
package/src/rules.d.ts
CHANGED
|
@@ -143,6 +143,16 @@ export interface Rules {
|
|
|
143
143
|
* `@param`'s and present function parameters will still be reported.
|
|
144
144
|
*/
|
|
145
145
|
allowExtraTrailingParamDocs?: boolean;
|
|
146
|
+
/**
|
|
147
|
+
* Whether to offer a suggestion to rename a mismatched `@param` to the
|
|
148
|
+
* corresponding function parameter name. Defaults to `false`.
|
|
149
|
+
*/
|
|
150
|
+
badParamNames?: boolean;
|
|
151
|
+
/**
|
|
152
|
+
* Whether to report `@param` definitions whose names match the function
|
|
153
|
+
* parameters but appear in a different order. Defaults to `true`.
|
|
154
|
+
*/
|
|
155
|
+
badParamOrder?: boolean;
|
|
146
156
|
/**
|
|
147
157
|
* Whether to check destructured properties. Defaults to `true`.
|
|
148
158
|
*/
|
|
@@ -206,14 +216,23 @@ export interface Rules {
|
|
|
206
216
|
*/
|
|
207
217
|
disableMissingParamChecks?: boolean;
|
|
208
218
|
/**
|
|
209
|
-
*
|
|
210
|
-
|
|
219
|
+
* Whether to report duplicate `@param` definitions. Defaults to `true`.
|
|
220
|
+
*/
|
|
221
|
+
duplicateParams?: boolean;
|
|
222
|
+
/**
|
|
223
|
+
* Set to `true` to reorder non-nested `@param` definitions to match the
|
|
224
|
+
* function signature and to auto-remove duplicates (based on identical names).
|
|
211
225
|
*
|
|
212
226
|
* Note that this option will remove duplicates of the same name even if
|
|
213
227
|
* the definitions do not match in other ways (e.g., the second param will
|
|
214
228
|
* be removed even if it has a different type or description).
|
|
215
229
|
*/
|
|
216
230
|
enableFixer?: boolean;
|
|
231
|
+
/**
|
|
232
|
+
* Whether to offer a suggestion to remove an `@param` that has no
|
|
233
|
+
* corresponding function parameter. Defaults to `false`.
|
|
234
|
+
*/
|
|
235
|
+
extraParams?: boolean;
|
|
217
236
|
/**
|
|
218
237
|
* Set to `true` if you wish to avoid reporting of child property documentation
|
|
219
238
|
* where instead of destructuring, a whole plain object is supplied as default
|