eslint-plugin-jsdoc 64.5.3 → 65.0.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
@@ -265,7 +265,7 @@ and specify `eslint-plugin-jsdoc` as a plugin.
265
265
 
266
266
  Finally, enable all of the rules that you would like to use.
267
267
 
268
- ```javascript
268
+ ```json5
269
269
  {
270
270
  "rules": {
271
271
  "jsdoc/check-access": 1, // Recommended
@@ -298,6 +298,9 @@ Finally, enable all of the rules that you would like to use.
298
298
  "jsdoc/no-restricted-syntax": 1,
299
299
  "jsdoc/no-types": 1, // Recommended for TS configs
300
300
  "jsdoc/no-undefined-types": 1, // Recommended for non-TS configs
301
+ "jsdoc/no-unnecessary-type-assertion": 1,
302
+ "jsdoc/normalize-see-links": 1,
303
+ "jsdoc/prefer-import-tag": 1,
301
304
  "jsdoc/reject-any-type": 1, // Recommended
302
305
  "jsdoc/reject-function-type": 1, // Recommended
303
306
  "jsdoc/require-asterisk-prefix": 1,
@@ -322,6 +325,7 @@ Finally, enable all of the rules that you would like to use.
322
325
  "jsdoc/require-returns-description": 1, // Recommended
323
326
  "jsdoc/require-returns-type": 1, // Recommended in non-TS configs
324
327
  "jsdoc/require-returns": 1, // Recommended
328
+ "jsdoc/require-tags": 1,
325
329
  "jsdoc/require-template": 1,
326
330
  "jsdoc/require-template-description": 1,
327
331
  "jsdoc/require-throws": 1,
@@ -334,9 +338,11 @@ Finally, enable all of the rules that you would like to use.
334
338
  "jsdoc/sort-tags": 1,
335
339
  "jsdoc/tag-lines": 1, // Recommended
336
340
  "jsdoc/text-escaping": 1,
341
+ "jsdoc/ts-ban-ts-comment": 1,
337
342
  "jsdoc/ts-method-signature-style": 1,
338
- "jsdoc/ts-prefer-function-type": 1,
343
+ "jsdoc/ts-no-empty-object-type": 1, // Recommended
339
344
  "jsdoc/ts-no-unnecessary-template-expression": 1,
345
+ "jsdoc/ts-prefer-function-type": 1,
340
346
  "jsdoc/type-formatting": 1,
341
347
  "jsdoc/valid-types": 1 // Recommended
342
348
  }
package/dist/rules.d.ts CHANGED
@@ -51,6 +51,10 @@ export interface Rules {
51
51
  * Allows indentation of nested sections on subsequent lines (like bullet lists)
52
52
  */
53
53
  allowIndentedSections?: boolean;
54
+ /**
55
+ * Allows there to be no space after asterisks and before content.
56
+ */
57
+ allowNoSpaceAfterAsterisk?: boolean;
54
58
  /**
55
59
  * Array of tags (e.g., `['example', 'description']`) whose content will be
56
60
  * "hidden" from the `check-indentation` rule. Defaults to `['example']`.
@@ -121,6 +125,7 @@ export interface Rules {
121
125
  /**
122
126
  * Use this to change the tags which are sought for alignment changes. Defaults to an array of
123
127
  * `['param', 'arg', 'argument', 'property', 'prop', 'returns', 'return', 'template']`.
128
+ * Add the value "-any" to the array if you want alignment to apply to all tags.
124
129
  */
125
130
  tags?: string[];
126
131
  /**
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "dependencies": {
8
8
  "@es-joy/jsdoccomment": "~0.98.0",
9
9
  "@es-joy/resolve.exports": "1.2.0",
10
- "@typescript-eslint/utils": "^8.70.0",
10
+ "@typescript-eslint/utils": "^8.70.1",
11
11
  "are-docs-informative": "^0.1.1",
12
12
  "comment-parser": "1.4.9",
13
13
  "debug": "^4.4.3",
@@ -24,34 +24,34 @@
24
24
  "description": "JSDoc linting rules for ESLint.",
25
25
  "devDependencies": {
26
26
  "@arethetypeswrong/cli": "^0.18.5",
27
- "@babel/core": "8.0.5",
27
+ "@babel/core": "8.0.6",
28
28
  "@babel/eslint-parser": "8.0.5",
29
29
  "@babel/plugin-transform-flow-strip-types": "8.0.1",
30
- "@babel/preset-env": "8.0.5",
30
+ "@babel/preset-env": "8.0.6",
31
31
  "@es-joy/escodegen": "^4.2.0",
32
32
  "@es-joy/jsdoc-eslint-parser": "^0.29.0",
33
33
  "@eslint/core": "^1.2.1",
34
34
  "@hkdobrev/run-if-changed": "^0.9.0",
35
35
  "@semantic-release/commit-analyzer": "^13.0.1",
36
- "@semantic-release/github": "^12.0.9",
37
- "@semantic-release/npm": "^13.1.5",
36
+ "@semantic-release/github": "^12.0.10",
37
+ "@semantic-release/npm": "^13.2.0",
38
38
  "@types/chai": "^5.2.3",
39
39
  "@types/debug": "^4.1.13",
40
40
  "@types/esquery": "^1.5.4",
41
41
  "@types/estree": "^1.0.9",
42
42
  "@types/json-schema": "^7.0.15",
43
43
  "@types/mocha": "^10.0.10",
44
- "@types/node": "^26.6.1",
44
+ "@types/node": "^26.6.2",
45
45
  "@types/semver": "^7.8.0",
46
46
  "@types/spdx-expression-parse": "^4.0.0",
47
- "@typescript-eslint/types": "8.70.0",
47
+ "@typescript-eslint/types": "8.70.1",
48
48
  "babel-plugin-add-module-exports": "^1.0.4",
49
49
  "babel-plugin-transform-import-meta": "^3.0.0",
50
50
  "c8": "^12.0.0",
51
51
  "camelcase": "^9.0.0",
52
52
  "chai": "^6.2.2",
53
53
  "decamelize": "^6.0.1",
54
- "eslint": "10.10.0",
54
+ "eslint": "10.11.0",
55
55
  "eslint-config-canonical": "^47.4.2",
56
56
  "gitdown": "^4.1.1",
57
57
  "glob": "^13.0.6",
@@ -70,7 +70,7 @@
70
70
  "sinon": "^22.1.0",
71
71
  "ts-api-utils": "^2.5.0",
72
72
  "typescript": "6.0.3",
73
- "typescript-eslint": "8.70.0"
73
+ "typescript-eslint": "8.70.1"
74
74
  },
75
75
  "engines": {
76
76
  "node": "^22.22.2 || >=24.15.0"
@@ -163,5 +163,5 @@
163
163
  "test-cov": "TIMING=1 c8 --reporter text pnpm run test-no-cov",
164
164
  "test-index": "pnpm run test-no-cov test/rules/index.js"
165
165
  },
166
- "version": "64.5.3"
166
+ "version": "65.0.0"
167
167
  }
@@ -66,6 +66,10 @@ const zeroWidth = {
66
66
  * @returns {boolean}
67
67
  */
68
68
  const shouldAlign = (tags, index, source) => {
69
+ if (tags.includes('-any')) {
70
+ return true;
71
+ }
72
+
69
73
  const tag = source[index].tokens.tag.replace('@', '');
70
74
  const includesTag = tags.includes(tag);
71
75
 
@@ -32,8 +32,7 @@ const maskCodeBlocks = (str) => {
32
32
  */
33
33
  const getLineNumber = (lines, lineIndex) => {
34
34
  const precedingText = lines.slice(0, lineIndex).join('\n');
35
- const lineBreaks = precedingText.match(/\n/gv) || [];
36
- return lineBreaks.length + 1;
35
+ return precedingText.split('\n').length;
37
36
  };
38
37
 
39
38
  export default iterateJsdoc(({
@@ -43,8 +42,17 @@ export default iterateJsdoc(({
43
42
  sourceCode,
44
43
  }) => {
45
44
  const options = context.options[0] || {};
46
- const /** @type {{excludeTags: string[], allowIndentedSections: boolean}} */ {
45
+
46
+ /**
47
+ * @type {{
48
+ * excludeTags: string[],
49
+ * allowIndentedSections: boolean,
50
+ * allowNoSpaceAfterAsterisk: boolean,
51
+ * }}
52
+ */
53
+ const {
47
54
  allowIndentedSections = false,
55
+ allowNoSpaceAfterAsterisk = false,
48
56
  excludeTags = [
49
57
  'example',
50
58
  ],
@@ -64,6 +72,14 @@ export default iterateJsdoc(({
64
72
  lineIndex,
65
73
  line,
66
74
  ] of lines.entries()) {
75
+ // Check for no space between the asterisk prefix and content
76
+ if (!allowNoSpaceAfterAsterisk && /^(?:\/?\**|[\t ]*)\*[^\s*\/]/v.test(line)) {
77
+ report('There must be a space after the asterisk.', null, {
78
+ line: getLineNumber(lines, lineIndex),
79
+ });
80
+ return;
81
+ }
82
+
67
83
  // Check for indentation (two or more spaces after *)
68
84
  const indentMatch = line.match(/^(?:\/?\**|[\t ]*)\*([\t ]{2,})/v);
69
85
 
@@ -118,11 +134,37 @@ export default iterateJsdoc(({
118
134
  }
119
135
  }
120
136
  } else {
137
+ // Check for no space between the asterisk prefix and content
138
+ let noSpaceLastIndex = 0;
139
+ if (!allowNoSpaceAfterAsterisk) {
140
+ const noSpaceReg = /^(?:\/?\**|[ \t]*)\*[^\s*\/]/gmv;
141
+ if (noSpaceReg.test(text)) {
142
+ noSpaceLastIndex = noSpaceReg.lastIndex;
143
+ }
144
+ }
145
+
146
+ // Check for indentation (two or more spaces after *)
121
147
  const reg = /^(?:\/?\**|[ \t]*)\*[ \t]{2}/gmv;
148
+ let hasIndent = false;
149
+ let indentLastIndex = 0;
122
150
  if (reg.test(text)) {
123
- const lineBreaks = text.slice(0, reg.lastIndex).match(/\n/gv) || [];
151
+ hasIndent = true;
152
+ indentLastIndex = reg.lastIndex;
153
+ }
154
+
155
+ // Report whichever issue appears first in the text
156
+ if (noSpaceLastIndex && (!hasIndent || noSpaceLastIndex <= indentLastIndex)) {
157
+ const line = text.slice(0, noSpaceLastIndex).split('\n').length - 1;
158
+ report('There must be a space after the asterisk.', null, {
159
+ line,
160
+ });
161
+ return;
162
+ }
163
+
164
+ if (hasIndent) {
165
+ const line = text.slice(0, indentLastIndex).split('\n').length - 1;
124
166
  report('There must be no indentation.', null, {
125
- line: lineBreaks.length,
167
+ line,
126
168
  });
127
169
  }
128
170
  }
@@ -141,6 +183,10 @@ export default iterateJsdoc(({
141
183
  description: 'Allows indentation of nested sections on subsequent lines (like bullet lists)',
142
184
  type: 'boolean',
143
185
  },
186
+ allowNoSpaceAfterAsterisk: {
187
+ description: 'Allows there to be no space after asterisks and before content.',
188
+ type: 'boolean',
189
+ },
144
190
  excludeTags: {
145
191
  description: `Array of tags (e.g., \`['example', 'description']\`) whose content will be
146
192
  "hidden" from the \`check-indentation\` rule. Defaults to \`['example']\`.
@@ -311,7 +311,10 @@ export default iterateJsdoc(({
311
311
  return;
312
312
  }
313
313
 
314
- const foundTags = utils.getPresentTags(applicableTags);
314
+ const foundTags = applicableTags.includes('-any') ?
315
+ utils.filterTags(Boolean) :
316
+ utils.getPresentTags(applicableTags);
317
+
315
318
  if (context.options[0] !== 'any') {
316
319
  for (const tag of foundTags) {
317
320
  checkNotAlignedPerTag(
@@ -433,7 +436,8 @@ main description. If \`false\` or unset, will be set to a single space.`,
433
436
  },
434
437
  tags: {
435
438
  description: `Use this to change the tags which are sought for alignment changes. Defaults to an array of
436
- \`['param', 'arg', 'argument', 'property', 'prop', 'returns', 'return', 'template']\`.`,
439
+ \`['param', 'arg', 'argument', 'property', 'prop', 'returns', 'return', 'template']\`.
440
+ Add the value "-any" to the array if you want alignment to apply to all tags.`,
437
441
  items: {
438
442
  type: 'string',
439
443
  },
@@ -10,24 +10,11 @@ let warned = false;
10
10
  /** @type {any} */
11
11
  let ts;
12
12
 
13
+ let tsAttempted = false;
14
+
13
15
  // 1. Create a require function bound to the current file's URL
14
16
  const require = createRequire(import.meta.url);
15
17
 
16
- try {
17
- // 2. Attempt to import the package synchronously
18
- ts = require('typescript');
19
- /* c8 ignore next 10 -- Guard */
20
- } catch (error) {
21
- // 3. Fall back gracefully if it is not installed
22
- if (/** @type {{code?: string}} */ (error).code !== 'MODULE_NOT_FOUND') {
23
- // Re-throw if it's a different error (e.g., syntax error inside the package)
24
- throw error;
25
- }
26
-
27
- // eslint-disable-next-line no-console -- Warning user
28
- console.warn('⚠️ typescript is not installed. `jsdoc/no-unnecessary-type-assertion` will not work. To disable this warning, you must disable the rule.');
29
- }
30
-
31
18
  // Helper to check for standard literals and boolean/enum/template literals
32
19
  /**
33
20
  * @param {any} type The type is `ts.Type`
@@ -70,9 +57,30 @@ export default iterateJsdoc(({
70
57
  utils,
71
58
  // eslint-disable-next-line complexity -- Numerous type/option permutations
72
59
  }) => {
73
- /* c8 ignore next 4 -- Guard */
74
60
  // Already handled
75
61
  if (!ts) {
62
+ /* c8 ignore next 3 -- Guard (only reachable if `typescript` failed to load on a prior call) */
63
+ if (tsAttempted) {
64
+ return;
65
+ }
66
+
67
+ try {
68
+ // 2. Attempt to import the package synchronously
69
+ ts = require('typescript');
70
+ /* c8 ignore next 10 -- Guard */
71
+ } catch (error) {
72
+ // 3. Fall back gracefully if it is not installed
73
+ if (/** @type {{code?: string}} */ (error).code !== 'MODULE_NOT_FOUND') {
74
+ // Re-throw if it's a different error (e.g., syntax error inside the package)
75
+ throw error;
76
+ }
77
+
78
+ // eslint-disable-next-line no-console -- Warning user
79
+ console.warn('⚠️ typescript is not installed. `jsdoc/no-unnecessary-type-assertion` will not work. To disable this warning, you must disable the rule.');
80
+ } finally {
81
+ tsAttempted = true;
82
+ }
83
+
76
84
  return;
77
85
  }
78
86
 
package/src/rules.d.ts CHANGED
@@ -51,6 +51,10 @@ export interface Rules {
51
51
  * Allows indentation of nested sections on subsequent lines (like bullet lists)
52
52
  */
53
53
  allowIndentedSections?: boolean;
54
+ /**
55
+ * Allows there to be no space after asterisks and before content.
56
+ */
57
+ allowNoSpaceAfterAsterisk?: boolean;
54
58
  /**
55
59
  * Array of tags (e.g., `['example', 'description']`) whose content will be
56
60
  * "hidden" from the `check-indentation` rule. Defaults to `['example']`.
@@ -121,6 +125,7 @@ export interface Rules {
121
125
  /**
122
126
  * Use this to change the tags which are sought for alignment changes. Defaults to an array of
123
127
  * `['param', 'arg', 'argument', 'property', 'prop', 'returns', 'return', 'template']`.
128
+ * Add the value "-any" to the array if you want alignment to apply to all tags.
124
129
  */
125
130
  tags?: string[];
126
131
  /**