@depup/eslint-plugin-jsdoc 64.2.1-depup.0 → 64.3.1-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 +9 -3
- package/changes.json +8 -3
- package/dist/rules/noUnnecessaryTypeAssertion.d.ts +3 -0
- package/dist/rules.d.ts +24 -4
- package/package.json +12 -6
- package/src/index.js +3 -0
- package/src/rules/noUnnecessaryTypeAssertion.js +232 -0
- package/src/rules.d.ts +24 -4
package/README.md
CHANGED
|
@@ -13,10 +13,16 @@ 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.
|
|
17
|
-
| Processed | 2026-08-
|
|
16
|
+
| Original | [eslint-plugin-jsdoc](https://www.npmjs.com/package/eslint-plugin-jsdoc) @ 64.3.1 |
|
|
17
|
+
| Processed | 2026-08-30 |
|
|
18
18
|
| Smoke test | passed |
|
|
19
|
-
| Deps updated |
|
|
19
|
+
| Deps updated | 1 |
|
|
20
|
+
|
|
21
|
+
## Dependency Changes
|
|
22
|
+
|
|
23
|
+
| Dependency | From | To |
|
|
24
|
+
|------------|------|-----|
|
|
25
|
+
| @es-joy/jsdoccomment | ~0.95.1 | ^0.96.0 |
|
|
20
26
|
|
|
21
27
|
---
|
|
22
28
|
|
package/changes.json
CHANGED
package/dist/rules.d.ts
CHANGED
|
@@ -144,8 +144,8 @@ export interface Rules {
|
|
|
144
144
|
*/
|
|
145
145
|
allowExtraTrailingParamDocs?: boolean;
|
|
146
146
|
/**
|
|
147
|
-
* Whether to
|
|
148
|
-
*
|
|
147
|
+
* Whether to auto-fix a mismatched `@param` name to the corresponding
|
|
148
|
+
* function parameter name. A suggestion is always offered. Defaults to `false`.
|
|
149
149
|
*/
|
|
150
150
|
badParamNames?: boolean;
|
|
151
151
|
/**
|
|
@@ -229,8 +229,8 @@ export interface Rules {
|
|
|
229
229
|
*/
|
|
230
230
|
enableFixer?: boolean;
|
|
231
231
|
/**
|
|
232
|
-
* Whether to
|
|
233
|
-
*
|
|
232
|
+
* Whether to auto-remove an `@param` that has no corresponding function
|
|
233
|
+
* parameter. A suggestion is always offered. Defaults to `false`.
|
|
234
234
|
*/
|
|
235
235
|
extraParams?: boolean;
|
|
236
236
|
/**
|
|
@@ -1311,6 +1311,26 @@ export interface Rules {
|
|
|
1311
1311
|
}
|
|
1312
1312
|
];
|
|
1313
1313
|
|
|
1314
|
+
/** Reports redundant @type tags that match or broaden the naturally inferred TypeScript type. */
|
|
1315
|
+
"jsdoc/no-unnecessary-type-assertion":
|
|
1316
|
+
| []
|
|
1317
|
+
| [
|
|
1318
|
+
{
|
|
1319
|
+
/**
|
|
1320
|
+
* Whether to check `const` type assertions as redundant
|
|
1321
|
+
*/
|
|
1322
|
+
checkLiteralConstAssertions?: boolean;
|
|
1323
|
+
/**
|
|
1324
|
+
* Whether to treat `any` type casts as redundant
|
|
1325
|
+
*/
|
|
1326
|
+
treatAnyAsRedundant?: boolean;
|
|
1327
|
+
/**
|
|
1328
|
+
* An array list of types to ignore
|
|
1329
|
+
*/
|
|
1330
|
+
typesToIgnore?: string[];
|
|
1331
|
+
}
|
|
1332
|
+
];
|
|
1333
|
+
|
|
1314
1334
|
/** Normalizes labeled links in `@see` tags to a canonical `{@link}` form. */
|
|
1315
1335
|
"jsdoc/normalize-see-links":
|
|
1316
1336
|
| []
|
package/package.json
CHANGED
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
"url": "http://gajus.com"
|
|
6
6
|
},
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@es-joy/jsdoccomment": "
|
|
8
|
+
"@es-joy/jsdoccomment": "^0.96.0",
|
|
9
9
|
"@es-joy/resolve.exports": "1.2.0",
|
|
10
|
+
"@typescript-eslint/utils": "^8.68.0",
|
|
10
11
|
"are-docs-informative": "^0.1.1",
|
|
11
12
|
"comment-parser": "1.4.8",
|
|
12
13
|
"debug": "^4.4.3",
|
|
@@ -160,13 +161,18 @@
|
|
|
160
161
|
"test-cov": "TIMING=1 c8 --reporter text pnpm run test-no-cov",
|
|
161
162
|
"test-index": "pnpm run test-no-cov test/rules/index.js"
|
|
162
163
|
},
|
|
163
|
-
"version": "64.
|
|
164
|
+
"version": "64.3.1-depup.0",
|
|
164
165
|
"depup": {
|
|
165
|
-
"changes": {
|
|
166
|
-
|
|
166
|
+
"changes": {
|
|
167
|
+
"@es-joy/jsdoccomment": {
|
|
168
|
+
"from": "~0.95.1",
|
|
169
|
+
"to": "^0.96.0"
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
"depsUpdated": 1,
|
|
167
173
|
"originalPackage": "eslint-plugin-jsdoc",
|
|
168
|
-
"originalVersion": "64.
|
|
169
|
-
"processedAt": "2026-08-
|
|
174
|
+
"originalVersion": "64.3.1",
|
|
175
|
+
"processedAt": "2026-08-30T00:56:47.119Z",
|
|
170
176
|
"smokeTest": "passed"
|
|
171
177
|
}
|
|
172
178
|
}
|
package/src/index.js
CHANGED
|
@@ -39,6 +39,7 @@ import noRestrictedSyntax from './rules/noRestrictedSyntax.js';
|
|
|
39
39
|
import normalizeSeeLinks from './rules/normalizeSeeLinks.js';
|
|
40
40
|
import noTypes from './rules/noTypes.js';
|
|
41
41
|
import noUndefinedTypes from './rules/noUndefinedTypes.js';
|
|
42
|
+
import noUnnecessaryTypeAssertion from './rules/noUnnecessaryTypeAssertion.js';
|
|
42
43
|
import preferImportTag from './rules/preferImportTag.js';
|
|
43
44
|
import requireAsteriskPrefix from './rules/requireAsteriskPrefix.js';
|
|
44
45
|
import requireDescription from './rules/requireDescription.js';
|
|
@@ -134,6 +135,7 @@ index.rules = {
|
|
|
134
135
|
'no-restricted-syntax': noRestrictedSyntax,
|
|
135
136
|
'no-types': noTypes,
|
|
136
137
|
'no-undefined-types': noUndefinedTypes,
|
|
138
|
+
'no-unnecessary-type-assertion': noUnnecessaryTypeAssertion,
|
|
137
139
|
'normalize-see-links': normalizeSeeLinks,
|
|
138
140
|
'prefer-import-tag': preferImportTag,
|
|
139
141
|
'reject-any-type': buildRejectOrPreferRuleDefinition({
|
|
@@ -325,6 +327,7 @@ const createRecommendedRuleset = (warnOrError, flatName) => {
|
|
|
325
327
|
'jsdoc/no-restricted-syntax': 'off',
|
|
326
328
|
'jsdoc/no-types': 'off',
|
|
327
329
|
'jsdoc/no-undefined-types': warnOrError,
|
|
330
|
+
'jsdoc/no-unnecessary-type-assertion': 'off',
|
|
328
331
|
'jsdoc/normalize-see-links': 'off',
|
|
329
332
|
'jsdoc/prefer-import-tag': 'off',
|
|
330
333
|
'jsdoc/reject-any-type': warnOrError,
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/* eslint-disable jsdoc/reject-any-type -- TypeScript types need not be installed */
|
|
2
|
+
import iterateJsdoc from '../iterateJsdoc.js';
|
|
3
|
+
import {
|
|
4
|
+
createRequire,
|
|
5
|
+
} from 'module';
|
|
6
|
+
|
|
7
|
+
let warned = false;
|
|
8
|
+
|
|
9
|
+
/** @type {any} */
|
|
10
|
+
let ts;
|
|
11
|
+
|
|
12
|
+
// 1. Create a require function bound to the current file's URL
|
|
13
|
+
const require = createRequire(import.meta.url);
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
// 2. Attempt to import the package synchronously
|
|
17
|
+
ts = require('typescript');
|
|
18
|
+
/* c8 ignore next 10 -- Guard */
|
|
19
|
+
} catch (error) {
|
|
20
|
+
// 3. Fall back gracefully if it is not installed
|
|
21
|
+
if (/** @type {{code?: string}} */ (error).code !== 'MODULE_NOT_FOUND') {
|
|
22
|
+
// Re-throw if it's a different error (e.g., syntax error inside the package)
|
|
23
|
+
throw error;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// eslint-disable-next-line no-console -- Warning user
|
|
27
|
+
console.warn('⚠️ typescript is not installed. `jsdoc/no-unnecessary-type-assertion` will not work. To disable this warning, you must disable the rule.');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Helper to check for standard literals and boolean/enum/template literals
|
|
31
|
+
/**
|
|
32
|
+
* @param {any} type The type is `ts.Type`
|
|
33
|
+
* @returns {boolean}
|
|
34
|
+
*/
|
|
35
|
+
const isLiteralType = (type) => {
|
|
36
|
+
// Standard primitive literals (string, number, bigint, boolean literal flags)
|
|
37
|
+
if (type.isLiteral()) {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Check using TypeFlags for specific edge cases like boolean or template literals
|
|
42
|
+
// eslint-disable-next-line no-bitwise -- Convenient
|
|
43
|
+
if (type.flags & (ts.TypeFlags.BooleanLiteral | ts.TypeFlags.TemplateLiteral)) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// If dealing with a union (e.g. 'a' | 'b'), you can check if all constituents are literals
|
|
48
|
+
if (type.isUnion()) {
|
|
49
|
+
return type.types.every(
|
|
50
|
+
/**
|
|
51
|
+
* @param {any} typ
|
|
52
|
+
*/
|
|
53
|
+
(typ) => {
|
|
54
|
+
return isLiteralType(typ);
|
|
55
|
+
},
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return false;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export default iterateJsdoc(({
|
|
63
|
+
context,
|
|
64
|
+
node: nde,
|
|
65
|
+
report,
|
|
66
|
+
utils,
|
|
67
|
+
}) => {
|
|
68
|
+
/* c8 ignore next 4 -- Guard */
|
|
69
|
+
// Already handled
|
|
70
|
+
if (!ts) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const types = utils.getTags('type');
|
|
75
|
+
|
|
76
|
+
// 1. Only proceed if there is a @type tag
|
|
77
|
+
if (!types.length) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const {
|
|
82
|
+
// https://typescript-eslint.io/rules/no-unnecessary-type-assertion/
|
|
83
|
+
checkLiteralConstAssertions = false,
|
|
84
|
+
treatAnyAsRedundant = false,
|
|
85
|
+
typesToIgnore = [],
|
|
86
|
+
} = context.options[0] ?? {};
|
|
87
|
+
|
|
88
|
+
const node =
|
|
89
|
+
/**
|
|
90
|
+
* @type {import('@typescript-eslint/utils').TSESTree.Node}
|
|
91
|
+
*/ (nde);
|
|
92
|
+
|
|
93
|
+
// 2. Safely get TypeScript parser services and TypeChecker
|
|
94
|
+
const services =
|
|
95
|
+
/**
|
|
96
|
+
* @type {import('@typescript-eslint/utils').ParserServices}
|
|
97
|
+
*/ (context.sourceCode.parserServices);
|
|
98
|
+
|
|
99
|
+
/* c8 ignore next 10 -- Guard */
|
|
100
|
+
if (!services || !services.program) {
|
|
101
|
+
if (!warned) {
|
|
102
|
+
// Cannot proceed without type-aware linting enabled
|
|
103
|
+
// eslint-disable-next-line no-console -- Feedback
|
|
104
|
+
console.warn('⚠️ You must point ESLint to the `typescript-eslint` parser using `languageOptions`. See the documentation for `jsdoc/no-unnecessary-type-assertion`.');
|
|
105
|
+
warned = true;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// 1. Grab the parser services and the active TypeChecker
|
|
112
|
+
// const services = ESLintUtils.getParserServices(context);
|
|
113
|
+
const checker = services.program.getTypeChecker();
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* @param {string} typeStr
|
|
117
|
+
* @returns {any} `ts.Type`
|
|
118
|
+
*/
|
|
119
|
+
const getTypeFromString = (typeStr) => {
|
|
120
|
+
// 2. Parse the type string into a virtual TypeScript SourceFile
|
|
121
|
+
const virtualSourceFile = ts.createSourceFile(
|
|
122
|
+
'inline-type-eval.ts',
|
|
123
|
+
`type __TargetType = ${typeStr};`,
|
|
124
|
+
ts.ScriptTarget.Latest,
|
|
125
|
+
true,
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
// 3. Find the TypeNode in the AST (type __TargetType = <TypeNode>;)
|
|
129
|
+
// Type `ts.TypeAliasDeclaration`
|
|
130
|
+
const typeAlias = /** @type {any} */ (
|
|
131
|
+
virtualSourceFile.statements[0]
|
|
132
|
+
);
|
|
133
|
+
const typeNode = typeAlias.type;
|
|
134
|
+
|
|
135
|
+
// 4. Resolve the type using the TypeChecker
|
|
136
|
+
// Note: If the type string references external symbols or types from your
|
|
137
|
+
// actual codebase, the checker may require a complete program context to resolve them.
|
|
138
|
+
return checker.getTypeFromTypeNode(typeNode);
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// Todo: Support more than just VariableDeclaration!
|
|
142
|
+
|
|
143
|
+
// 3. For this example, let's assume we are checking VariableDeclarators
|
|
144
|
+
// e.g., `/** @type {number} */ const x = 5;`
|
|
145
|
+
if (node?.type === 'VariableDeclaration') {
|
|
146
|
+
const decl = node.declarations[0];
|
|
147
|
+
|
|
148
|
+
/* c8 ignore next 4 -- How to cover? */
|
|
149
|
+
if (!decl.init) {
|
|
150
|
+
// No initializer, type is likely `any`, so @type isn't redundant
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// 4. Map the ESLint AST nodes to TypeScript AST nodes
|
|
155
|
+
// const tsNode = services.esTreeNodeToTSNodeMap.get(decl.id);
|
|
156
|
+
const tsInit = services.esTreeNodeToTSNodeMap.get(decl.init);
|
|
157
|
+
|
|
158
|
+
// 5. Get the types
|
|
159
|
+
// tsNode type includes the JSDoc explicit type
|
|
160
|
+
// tsInit type is the purely inferred type from the right-hand side
|
|
161
|
+
const inferredType = checker.getTypeAtLocation(tsInit);
|
|
162
|
+
|
|
163
|
+
// 6. Compare the types.
|
|
164
|
+
const declaredTypeStr = types[0].type;
|
|
165
|
+
const declaredType = getTypeFromString(declaredTypeStr);
|
|
166
|
+
|
|
167
|
+
const isRedundantType = checker.isTypeAssignableTo(
|
|
168
|
+
inferredType,
|
|
169
|
+
declaredType,
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
if (declaredTypeStr === 'const') {
|
|
173
|
+
if (checkLiteralConstAssertions && isLiteralType(inferredType)) {
|
|
174
|
+
report(
|
|
175
|
+
'The @type tag declaring "{{ type }}" is redundant as TypeScript infers it automatically for literals.',
|
|
176
|
+
null,
|
|
177
|
+
types[0],
|
|
178
|
+
{
|
|
179
|
+
type: declaredTypeStr,
|
|
180
|
+
},
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (
|
|
188
|
+
isRedundantType && (treatAnyAsRedundant || declaredTypeStr !== 'any') &&
|
|
189
|
+
!typesToIgnore.includes(declaredTypeStr)
|
|
190
|
+
) {
|
|
191
|
+
report(
|
|
192
|
+
'The @type tag declaring "{{ type }}" is redundant as TypeScript infers it automatically.',
|
|
193
|
+
null,
|
|
194
|
+
types[0],
|
|
195
|
+
{
|
|
196
|
+
type: declaredTypeStr,
|
|
197
|
+
},
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}, {
|
|
202
|
+
iterateAllJsdocs: true,
|
|
203
|
+
meta: {
|
|
204
|
+
docs: {
|
|
205
|
+
description: 'Reports redundant @type tags that match or broaden the naturally inferred TypeScript type.',
|
|
206
|
+
},
|
|
207
|
+
schema: [
|
|
208
|
+
{
|
|
209
|
+
additionalProperties: false,
|
|
210
|
+
properties: {
|
|
211
|
+
checkLiteralConstAssertions: {
|
|
212
|
+
description: 'Whether to check `const` type assertions as redundant',
|
|
213
|
+
type: 'boolean',
|
|
214
|
+
},
|
|
215
|
+
treatAnyAsRedundant: {
|
|
216
|
+
description: 'Whether to treat `any` type casts as redundant',
|
|
217
|
+
type: 'boolean',
|
|
218
|
+
},
|
|
219
|
+
typesToIgnore: {
|
|
220
|
+
description: 'An array list of types to ignore',
|
|
221
|
+
items: {
|
|
222
|
+
type: 'string',
|
|
223
|
+
},
|
|
224
|
+
type: 'array',
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
type: 'object',
|
|
228
|
+
},
|
|
229
|
+
],
|
|
230
|
+
type: 'suggestion',
|
|
231
|
+
},
|
|
232
|
+
});
|
package/src/rules.d.ts
CHANGED
|
@@ -144,8 +144,8 @@ export interface Rules {
|
|
|
144
144
|
*/
|
|
145
145
|
allowExtraTrailingParamDocs?: boolean;
|
|
146
146
|
/**
|
|
147
|
-
* Whether to
|
|
148
|
-
*
|
|
147
|
+
* Whether to auto-fix a mismatched `@param` name to the corresponding
|
|
148
|
+
* function parameter name. A suggestion is always offered. Defaults to `false`.
|
|
149
149
|
*/
|
|
150
150
|
badParamNames?: boolean;
|
|
151
151
|
/**
|
|
@@ -229,8 +229,8 @@ export interface Rules {
|
|
|
229
229
|
*/
|
|
230
230
|
enableFixer?: boolean;
|
|
231
231
|
/**
|
|
232
|
-
* Whether to
|
|
233
|
-
*
|
|
232
|
+
* Whether to auto-remove an `@param` that has no corresponding function
|
|
233
|
+
* parameter. A suggestion is always offered. Defaults to `false`.
|
|
234
234
|
*/
|
|
235
235
|
extraParams?: boolean;
|
|
236
236
|
/**
|
|
@@ -1311,6 +1311,26 @@ export interface Rules {
|
|
|
1311
1311
|
}
|
|
1312
1312
|
];
|
|
1313
1313
|
|
|
1314
|
+
/** Reports redundant @type tags that match or broaden the naturally inferred TypeScript type. */
|
|
1315
|
+
"jsdoc/no-unnecessary-type-assertion":
|
|
1316
|
+
| []
|
|
1317
|
+
| [
|
|
1318
|
+
{
|
|
1319
|
+
/**
|
|
1320
|
+
* Whether to check `const` type assertions as redundant
|
|
1321
|
+
*/
|
|
1322
|
+
checkLiteralConstAssertions?: boolean;
|
|
1323
|
+
/**
|
|
1324
|
+
* Whether to treat `any` type casts as redundant
|
|
1325
|
+
*/
|
|
1326
|
+
treatAnyAsRedundant?: boolean;
|
|
1327
|
+
/**
|
|
1328
|
+
* An array list of types to ignore
|
|
1329
|
+
*/
|
|
1330
|
+
typesToIgnore?: string[];
|
|
1331
|
+
}
|
|
1332
|
+
];
|
|
1333
|
+
|
|
1314
1334
|
/** Normalizes labeled links in `@see` tags to a canonical `{@link}` form. */
|
|
1315
1335
|
"jsdoc/normalize-see-links":
|
|
1316
1336
|
| []
|