@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 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.2.1 |
17
- | Processed | 2026-08-18 |
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 | 0 |
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
@@ -1,5 +1,10 @@
1
1
  {
2
- "bumped": {},
3
- "timestamp": "2026-08-18T00:15:32.670Z",
4
- "totalUpdated": 0
2
+ "bumped": {
3
+ "@es-joy/jsdoccomment": {
4
+ "from": "~0.95.1",
5
+ "to": "^0.96.0"
6
+ }
7
+ },
8
+ "timestamp": "2026-08-30T00:56:30.602Z",
9
+ "totalUpdated": 1
5
10
  }
@@ -0,0 +1,3 @@
1
+ declare const _default: import("eslint").Rule.RuleModule;
2
+ export default _default;
3
+ //# sourceMappingURL=noUnnecessaryTypeAssertion.d.ts.map
package/dist/rules.d.ts CHANGED
@@ -144,8 +144,8 @@ export interface Rules {
144
144
  */
145
145
  allowExtraTrailingParamDocs?: boolean;
146
146
  /**
147
- * Whether to offer a suggestion to rename a mismatched `@param` to the
148
- * corresponding function parameter name. Defaults to `false`.
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 offer a suggestion to remove an `@param` that has no
233
- * corresponding function parameter. Defaults to `false`.
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": "~0.95.1",
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.2.1-depup.0",
164
+ "version": "64.3.1-depup.0",
164
165
  "depup": {
165
- "changes": {},
166
- "depsUpdated": 0,
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.2.1",
169
- "processedAt": "2026-08-18T00:15:57.166Z",
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 offer a suggestion to rename a mismatched `@param` to the
148
- * corresponding function parameter name. Defaults to `false`.
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 offer a suggestion to remove an `@param` that has no
233
- * corresponding function parameter. Defaults to `false`.
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
  | []