@depup/eslint-plugin-jsdoc 65.2.2-depup.0 → 65.3.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 CHANGED
@@ -13,8 +13,8 @@ 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) @ 65.2.2 |
17
- | Processed | 2026-10-09 |
16
+ | Original | [eslint-plugin-jsdoc](https://www.npmjs.com/package/eslint-plugin-jsdoc) @ 65.3.0 |
17
+ | Processed | 2026-10-12 |
18
18
  | Smoke test | passed |
19
19
  | Deps updated | 1 |
20
20
 
package/changes.json CHANGED
@@ -5,6 +5,6 @@
5
5
  "to": "^8.71.1"
6
6
  }
7
7
  },
8
- "timestamp": "2026-10-09T16:14:01.740Z",
8
+ "timestamp": "2026-10-12T00:39:11.741Z",
9
9
  "totalUpdated": 1
10
10
  }
package/dist/rules.d.ts CHANGED
@@ -1348,6 +1348,10 @@ export interface Rules {
1348
1348
  * Whether to enable the fixer that removes the redundant `@type` tag (and the JSDoc block if it becomes empty). Defaults to `true`.
1349
1349
  */
1350
1350
  enableFixer?: boolean;
1351
+ /**
1352
+ * Whether the fixer may also remove a redundant assertion that is broader than the inferred type, which changes the declared, exported or returned type (e.g. `/** @type {unknown} * /` on a `string`). When `false`, such an assertion is still reported but not fixed. Only matters when `enableFixer` is `true`. Defaults to `true`.
1353
+ */
1354
+ fixTypeChangingCasts?: boolean;
1351
1355
  /**
1352
1356
  * Whether to report a non-`const` literal-tuple assertion on an array literal (e.g. `/** @type {['foo']} * / (['foo'])`) and fix it to the equivalent, more concise `/** @type {const} * /` assertion. Defaults to `false`.
1353
1357
  */
package/package.json CHANGED
@@ -168,7 +168,7 @@
168
168
  "test-cov": "TIMING=1 c8 --reporter text pnpm run test-no-cov",
169
169
  "test-index": "pnpm run test-no-cov test/rules/index.js"
170
170
  },
171
- "version": "65.2.2-depup.0",
171
+ "version": "65.3.0-depup.0",
172
172
  "depup": {
173
173
  "changes": {
174
174
  "@typescript-eslint/utils": {
@@ -178,8 +178,8 @@
178
178
  },
179
179
  "depsUpdated": 1,
180
180
  "originalPackage": "eslint-plugin-jsdoc",
181
- "originalVersion": "65.2.2",
182
- "processedAt": "2026-10-09T16:14:20.835Z",
181
+ "originalVersion": "65.3.0",
182
+ "processedAt": "2026-10-12T00:39:34.382Z",
183
183
  "smokeTest": "passed"
184
184
  }
185
185
  }
@@ -1418,6 +1418,7 @@ const getUtils = (
1418
1418
  source: '',
1419
1419
  tokens: seedTokens({
1420
1420
  delimiter: '*',
1421
+ lineEnd: newLineEnd,
1421
1422
  start: indent + ' ',
1422
1423
  }),
1423
1424
  };
@@ -64,7 +64,7 @@ export default {
64
64
  * @param {string} messageId
65
65
  * @param {import('estree').Comment|Token} comment
66
66
  * @param {import('eslint').Rule.Node} node
67
- * @param {import('eslint').Rule.ReportFixer} fixer
67
+ * @param {import('eslint').Rule.ReportFixer|null} fixer
68
68
  */
69
69
  const report = (messageId, comment, node, fixer) => {
70
70
  const loc = {
@@ -167,9 +167,21 @@ export default {
167
167
  * @param {Token} [locComment] Comment to anchor the report location to,
168
168
  * e.g., the first comment of a stacked group of line comments, so the
169
169
  * report does not read as though only the last line were at fault.
170
+ * @param {Token[]} [commentGroup] The comments which the fixer would
171
+ * convert. Defaults to just `comment`.
170
172
  */
171
- const reportings = (comment, node, addComment, ctxts, locComment) => {
172
- const fixer = getFixer(node, comment, addComment, ctxts);
173
+ const reportings = (comment, node, addComment, ctxts, locComment, commentGroup = [
174
+ /** @type {Token} */ (comment),
175
+ ]) => {
176
+ // A `*/` inside a comment's text would end the generated JSDoc block
177
+ // early, so leave such comments for the user to convert
178
+ const fixer = commentGroup.some(({
179
+ value,
180
+ }) => {
181
+ return value.includes('*/');
182
+ }) ?
183
+ null :
184
+ getFixer(node, comment, addComment, ctxts);
173
185
 
174
186
  if (comment.type === 'Block') {
175
187
  if (lineOrBlockStyle === 'line') {
@@ -310,7 +322,7 @@ export default {
310
322
  );
311
323
  };
312
324
 
313
- reportings(comment, node, addComment, contexts, commentGroup[0]);
325
+ reportings(comment, node, addComment, contexts, commentGroup[0], commentGroup);
314
326
  };
315
327
 
316
328
  /**
@@ -229,6 +229,7 @@ export default iterateJsdoc(({
229
229
  ...tokens,
230
230
  };
231
231
  utils.emptyTokens(tokens);
232
+ tokens.lineEnd = utils.newLineEnd;
232
233
  const {
233
234
  tokens: {
234
235
  delimiter,
@@ -294,6 +295,7 @@ export default iterateJsdoc(({
294
295
  ...line,
295
296
  delimiter,
296
297
  end: '',
298
+ lineEnd: utils.newLineEnd,
297
299
  });
298
300
  };
299
301
 
@@ -95,6 +95,7 @@ export default iterateJsdoc(({
95
95
  // https://typescript-eslint.io/rules/no-unnecessary-type-assertion/
96
96
  checkLiteralConstAssertions = false,
97
97
  enableFixer = true,
98
+ fixTypeChangingCasts = true,
98
99
  preferConstToLiteralTuples = false,
99
100
  treatAnyAsRedundant = false,
100
101
  typesToIgnore = [],
@@ -354,6 +355,32 @@ export default iterateJsdoc(({
354
355
  checker.isTypeAssignableTo(assertedBaseType, inferredBaseType);
355
356
  };
356
357
 
358
+ /**
359
+ * Whether the fixer may remove a redundant assertion. With
360
+ * `fixTypeChangingCasts` (the default) every redundant assertion may be
361
+ * removed. Without it, a broader assertion (e.g. `unknown` on a `string`, or
362
+ * `'x' | 'y'` on `'x'`) is only reported, since dropping it would change the
363
+ * declared or returned type; it is removed only when the asserted type is
364
+ * also assignable back to the inferred one. A plain widening of a literal
365
+ * (`string` on `'hello'`) is the type TypeScript gives a mutable binding
366
+ * anyway, so it is kept removable.
367
+ * @param {any} rawInferredType `ts.Type`
368
+ * @param {any} rawAssertedType `ts.Type`
369
+ * @returns {boolean}
370
+ */
371
+ const mayRemove = (rawInferredType, rawAssertedType) => {
372
+ if (
373
+ fixTypeChangingCasts || assertedTypeStr === 'const' ||
374
+ checker.isTypeAssignableTo(rawAssertedType, rawInferredType)
375
+ ) {
376
+ return true;
377
+ }
378
+
379
+ const inferredBaseType = checker.getBaseTypeOfLiteralType(rawInferredType);
380
+ return checker.isTypeAssignableTo(inferredBaseType, rawAssertedType) &&
381
+ checker.isTypeAssignableTo(rawAssertedType, inferredBaseType);
382
+ };
383
+
357
384
  /**
358
385
  * A non-`const` tuple type annotation on an array literal (asserting `['foo']`
359
386
  * onto `['foo']`) turns the literal's inferred `T[]` into a tuple; since the
@@ -506,9 +533,15 @@ export default iterateJsdoc(({
506
533
  }
507
534
 
508
535
  if (isRedundantAssertion(declInferredType, declAssertedType)) {
509
- utils.reportJSDoc(message, types[0], fixer, true, {
510
- type: assertedTypeStr,
511
- });
536
+ utils.reportJSDoc(
537
+ message,
538
+ types[0],
539
+ mayRemove(declInferredType, declAssertedType) ? fixer : null,
540
+ true,
541
+ {
542
+ type: assertedTypeStr,
543
+ },
544
+ );
512
545
  }
513
546
 
514
547
  return;
@@ -593,7 +626,7 @@ export default iterateJsdoc(({
593
626
  return;
594
627
  }
595
628
 
596
- const canUnwrap = enableFixer && (
629
+ const canUnwrap = enableFixer && mayRemove(castInferredType, castAssertedType) && (
597
630
  unwrappableParentTypes.has(parent.type) ||
598
631
  (parent.type === 'ConditionalExpression' && parent.test !== node) ||
599
632
  ((parent.type === 'CallExpression' || parent.type === 'NewExpression') &&
@@ -651,6 +684,10 @@ export default iterateJsdoc(({
651
684
  description: 'Whether to enable the fixer that removes the redundant `@type` tag (and the JSDoc block if it becomes empty). Defaults to `true`.',
652
685
  type: 'boolean',
653
686
  },
687
+ fixTypeChangingCasts: {
688
+ description: 'Whether the fixer may also remove a redundant assertion that is broader than the inferred type, which changes the declared, exported or returned type (e.g. `/** @type {unknown} */` on a `string`). When `false`, such an assertion is still reported but not fixed. Only matters when `enableFixer` is `true`. Defaults to `true`.',
689
+ type: 'boolean',
690
+ },
654
691
  preferConstToLiteralTuples: {
655
692
  description: 'Whether to report a non-`const` literal-tuple assertion on an array literal (e.g. `/** @type {[\'foo\']} */ ([\'foo\'])`) and fix it to the equivalent, more concise `/** @type {const} */` assertion. Defaults to `false`.',
656
693
  type: 'boolean',
@@ -715,10 +715,12 @@ export default {
715
715
  } = contxt;
716
716
  return ctxt === node.type;
717
717
  })) || {};
718
+ // Use the line break of the source for the generated block
719
+ const lineBreak = sourceCode.text.includes('\r\n') ? '\r\n' : '\n';
718
720
  const insertion = (inlineCommentBlock ?
719
721
  `/** ${fixerMessage}` :
720
- `/**\n${indent}*${fixerMessage}\n${indent}`) +
721
- `*/${'\n'.repeat(lines)}${indent.slice(0, -1)}`;
722
+ `/**${lineBreak}${indent}*${fixerMessage}${lineBreak}${indent}`) +
723
+ `*/${lineBreak.repeat(lines)}${indent.slice(0, -1)}`;
722
724
 
723
725
  return fixer.insertTextBefore(
724
726
  /** @type {import('eslint').Rule.Node} */
@@ -441,7 +441,7 @@ export default iterateJsdoc(({
441
441
  delimiter: '*',
442
442
  description: '',
443
443
  end: '',
444
- lineEnd: '',
444
+ lineEnd: utils.newLineEnd,
445
445
  name: functionParameterName,
446
446
  newAdd: true,
447
447
  postDelimiter: ' ',
@@ -38,13 +38,16 @@ const checkMaxBlockLines = ({
38
38
  },
39
39
  () => {
40
40
  utils.setBlockDescription((info, seedTokens, descLines, postDelims) => {
41
+ // The run of newlines starts at the end of the preceding text line,
42
+ // so the blank lines to drop begin after that line.
43
+ const excessStart = descLines[excessIndexLine] ? excessIndexLine + 1 : excessIndexLine;
41
44
  const newPostDelims = [
42
- ...postDelims.slice(0, excessIndexLine),
43
- ...postDelims.slice(excessIndexLine + excessBlockLines - 1 - maxBlockLines),
45
+ ...postDelims.slice(0, excessStart),
46
+ ...postDelims.slice(excessStart + excessBlockLines - 1 - maxBlockLines),
44
47
  ];
45
48
  return [
46
- ...descLines.slice(0, excessIndexLine),
47
- ...descLines.slice(excessIndexLine + excessBlockLines - 1 - maxBlockLines),
49
+ ...descLines.slice(0, excessStart),
50
+ ...descLines.slice(excessStart + excessBlockLines - 1 - maxBlockLines),
48
51
  ].map((desc, idx) => {
49
52
  return {
50
53
  number: 0,
@@ -52,6 +55,7 @@ const checkMaxBlockLines = ({
52
55
  tokens: seedTokens({
53
56
  ...info,
54
57
  description: desc,
58
+ lineEnd: utils.newLineEnd,
55
59
  postDelimiter: newPostDelims[idx],
56
60
  }),
57
61
  };
@@ -327,6 +331,7 @@ export default iterateJsdoc(({
327
331
  tokens: seedTokens({
328
332
  ...info,
329
333
  description: desc,
334
+ lineEnd: utils.newLineEnd,
330
335
  postDelimiter: postDelims[idx],
331
336
  }),
332
337
  };
@@ -356,6 +361,7 @@ export default iterateJsdoc(({
356
361
  tokens: seedTokens({
357
362
  ...info,
358
363
  description: desc,
364
+ lineEnd: utils.newLineEnd,
359
365
  postDelimiter: desc.trim() ? postDelims[idx] : '',
360
366
  }),
361
367
  };
package/src/rules.d.ts CHANGED
@@ -1348,6 +1348,10 @@ export interface Rules {
1348
1348
  * Whether to enable the fixer that removes the redundant `@type` tag (and the JSDoc block if it becomes empty). Defaults to `true`.
1349
1349
  */
1350
1350
  enableFixer?: boolean;
1351
+ /**
1352
+ * Whether the fixer may also remove a redundant assertion that is broader than the inferred type, which changes the declared, exported or returned type (e.g. `/** @type {unknown} * /` on a `string`). When `false`, such an assertion is still reported but not fixed. Only matters when `enableFixer` is `true`. Defaults to `true`.
1353
+ */
1354
+ fixTypeChangingCasts?: boolean;
1351
1355
  /**
1352
1356
  * Whether to report a non-`const` literal-tuple assertion on an array literal (e.g. `/** @type {['foo']} * / (['foo'])`) and fix it to the equivalent, more concise `/** @type {const} * /` assertion. Defaults to `false`.
1353
1357
  */