eslint-plugin-jsdoc 55.3.0 → 56.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.
Files changed (156) hide show
  1. package/dist/cjs/WarnSettings.d.ts +16 -0
  2. package/dist/cjs/WarnSettings.js +30 -0
  3. package/dist/cjs/alignTransform.d.ts +33 -0
  4. package/dist/cjs/alignTransform.js +285 -0
  5. package/dist/cjs/defaultTagOrder.d.ts +4 -0
  6. package/dist/cjs/defaultTagOrder.js +152 -0
  7. package/dist/cjs/exportParser.d.ts +40 -0
  8. package/dist/cjs/exportParser.js +754 -0
  9. package/dist/cjs/getDefaultTagStructureForMode.d.ts +10 -0
  10. package/dist/cjs/getDefaultTagStructureForMode.js +840 -0
  11. package/dist/cjs/getJsdocProcessorPlugin.cjs +4 -0
  12. package/dist/cjs/getJsdocProcessorPlugin.d.cts +1 -0
  13. package/dist/cjs/getJsdocProcessorPlugin.d.ts +66 -0
  14. package/dist/cjs/getJsdocProcessorPlugin.js +553 -0
  15. package/dist/cjs/index-cjs.d.ts +16 -0
  16. package/dist/cjs/index-cjs.js +492 -0
  17. package/dist/cjs/index.cjs.cjs +6 -0
  18. package/dist/cjs/index.cjs.d.cts +2 -0
  19. package/dist/cjs/iterateJsdoc.cjs +38 -0
  20. package/dist/cjs/iterateJsdoc.d.cts +2 -0
  21. package/dist/cjs/iterateJsdoc.d.ts +462 -0
  22. package/dist/cjs/iterateJsdoc.js +1981 -0
  23. package/dist/cjs/jsdocUtils.d.ts +454 -0
  24. package/dist/cjs/jsdocUtils.js +1470 -0
  25. package/dist/cjs/rules/checkAccess.d.ts +2 -0
  26. package/dist/cjs/rules/checkAccess.js +35 -0
  27. package/dist/cjs/rules/checkAlignment.d.ts +2 -0
  28. package/dist/cjs/rules/checkAlignment.js +63 -0
  29. package/dist/cjs/rules/checkExamples.d.ts +3 -0
  30. package/dist/cjs/rules/checkExamples.js +486 -0
  31. package/dist/cjs/rules/checkIndentation.d.ts +2 -0
  32. package/dist/cjs/rules/checkIndentation.js +66 -0
  33. package/dist/cjs/rules/checkLineAlignment.d.ts +9 -0
  34. package/dist/cjs/rules/checkLineAlignment.js +297 -0
  35. package/dist/cjs/rules/checkParamNames.d.ts +2 -0
  36. package/dist/cjs/rules/checkParamNames.js +320 -0
  37. package/dist/cjs/rules/checkPropertyNames.d.ts +2 -0
  38. package/dist/cjs/rules/checkPropertyNames.js +105 -0
  39. package/dist/cjs/rules/checkSyntax.d.ts +2 -0
  40. package/dist/cjs/rules/checkSyntax.js +27 -0
  41. package/dist/cjs/rules/checkTagNames.d.ts +2 -0
  42. package/dist/cjs/rules/checkTagNames.js +252 -0
  43. package/dist/cjs/rules/checkTemplateNames.d.ts +2 -0
  44. package/dist/cjs/rules/checkTemplateNames.js +189 -0
  45. package/dist/cjs/rules/checkTypes.d.ts +2 -0
  46. package/dist/cjs/rules/checkTypes.js +421 -0
  47. package/dist/cjs/rules/checkValues.d.ts +2 -0
  48. package/dist/cjs/rules/checkValues.js +163 -0
  49. package/dist/cjs/rules/convertToJsdocComments.d.ts +251 -0
  50. package/dist/cjs/rules/convertToJsdocComments.js +313 -0
  51. package/dist/cjs/rules/emptyTags.d.ts +2 -0
  52. package/dist/cjs/rules/emptyTags.js +79 -0
  53. package/dist/cjs/rules/implementsOnClasses.d.ts +2 -0
  54. package/dist/cjs/rules/implementsOnClasses.js +63 -0
  55. package/dist/cjs/rules/importsAsDependencies.d.ts +2 -0
  56. package/dist/cjs/rules/importsAsDependencies.js +105 -0
  57. package/dist/cjs/rules/informativeDocs.d.ts +2 -0
  58. package/dist/cjs/rules/informativeDocs.js +153 -0
  59. package/dist/cjs/rules/linesBeforeBlock.d.ts +2 -0
  60. package/dist/cjs/rules/linesBeforeBlock.js +106 -0
  61. package/dist/cjs/rules/matchDescription.d.ts +2 -0
  62. package/dist/cjs/rules/matchDescription.js +240 -0
  63. package/dist/cjs/rules/matchName.d.ts +2 -0
  64. package/dist/cjs/rules/matchName.js +122 -0
  65. package/dist/cjs/rules/multilineBlocks.d.ts +2 -0
  66. package/dist/cjs/rules/multilineBlocks.js +339 -0
  67. package/dist/cjs/rules/noBadBlocks.d.ts +2 -0
  68. package/dist/cjs/rules/noBadBlocks.js +88 -0
  69. package/dist/cjs/rules/noBlankBlockDescriptions.d.ts +2 -0
  70. package/dist/cjs/rules/noBlankBlockDescriptions.js +56 -0
  71. package/dist/cjs/rules/noBlankBlocks.d.ts +2 -0
  72. package/dist/cjs/rules/noBlankBlocks.js +41 -0
  73. package/dist/cjs/rules/noDefaults.d.ts +2 -0
  74. package/dist/cjs/rules/noDefaults.js +84 -0
  75. package/dist/cjs/rules/noMissingSyntax.d.ts +9 -0
  76. package/dist/cjs/rules/noMissingSyntax.js +164 -0
  77. package/dist/cjs/rules/noMultiAsterisks.d.ts +2 -0
  78. package/dist/cjs/rules/noMultiAsterisks.js +83 -0
  79. package/dist/cjs/rules/noRestrictedSyntax.d.ts +2 -0
  80. package/dist/cjs/rules/noRestrictedSyntax.js +75 -0
  81. package/dist/cjs/rules/noTypes.d.ts +2 -0
  82. package/dist/cjs/rules/noTypes.js +88 -0
  83. package/dist/cjs/rules/noUndefinedTypes.d.ts +2 -0
  84. package/dist/cjs/rules/noUndefinedTypes.js +451 -0
  85. package/dist/cjs/rules/requireAsteriskPrefix.d.ts +2 -0
  86. package/dist/cjs/rules/requireAsteriskPrefix.js +144 -0
  87. package/dist/cjs/rules/requireDescription.d.ts +2 -0
  88. package/dist/cjs/rules/requireDescription.js +136 -0
  89. package/dist/cjs/rules/requireDescriptionCompleteSentence.d.ts +2 -0
  90. package/dist/cjs/rules/requireDescriptionCompleteSentence.js +258 -0
  91. package/dist/cjs/rules/requireExample.d.ts +2 -0
  92. package/dist/cjs/rules/requireExample.js +103 -0
  93. package/dist/cjs/rules/requireFileOverview.d.ts +2 -0
  94. package/dist/cjs/rules/requireFileOverview.js +117 -0
  95. package/dist/cjs/rules/requireHyphenBeforeParamDescription.d.ts +2 -0
  96. package/dist/cjs/rules/requireHyphenBeforeParamDescription.js +144 -0
  97. package/dist/cjs/rules/requireJsdoc.d.ts +25 -0
  98. package/dist/cjs/rules/requireJsdoc.js +629 -0
  99. package/dist/cjs/rules/requireParam.d.ts +3 -0
  100. package/dist/cjs/rules/requireParam.js +480 -0
  101. package/dist/cjs/rules/requireParamDescription.d.ts +2 -0
  102. package/dist/cjs/rules/requireParamDescription.js +77 -0
  103. package/dist/cjs/rules/requireParamName.d.ts +2 -0
  104. package/dist/cjs/rules/requireParamName.js +52 -0
  105. package/dist/cjs/rules/requireParamType.d.ts +2 -0
  106. package/dist/cjs/rules/requireParamType.js +77 -0
  107. package/dist/cjs/rules/requireProperty.d.ts +2 -0
  108. package/dist/cjs/rules/requireProperty.js +44 -0
  109. package/dist/cjs/rules/requirePropertyDescription.d.ts +2 -0
  110. package/dist/cjs/rules/requirePropertyDescription.js +22 -0
  111. package/dist/cjs/rules/requirePropertyName.d.ts +2 -0
  112. package/dist/cjs/rules/requirePropertyName.js +22 -0
  113. package/dist/cjs/rules/requirePropertyType.d.ts +2 -0
  114. package/dist/cjs/rules/requirePropertyType.js +22 -0
  115. package/dist/cjs/rules/requireReturns.d.ts +2 -0
  116. package/dist/cjs/rules/requireReturns.js +197 -0
  117. package/dist/cjs/rules/requireReturnsCheck.d.ts +2 -0
  118. package/dist/cjs/rules/requireReturnsCheck.js +108 -0
  119. package/dist/cjs/rules/requireReturnsDescription.d.ts +2 -0
  120. package/dist/cjs/rules/requireReturnsDescription.js +58 -0
  121. package/dist/cjs/rules/requireReturnsType.d.ts +2 -0
  122. package/dist/cjs/rules/requireReturnsType.js +52 -0
  123. package/dist/cjs/rules/requireTemplate.d.ts +2 -0
  124. package/dist/cjs/rules/requireTemplate.js +173 -0
  125. package/dist/cjs/rules/requireThrows.d.ts +2 -0
  126. package/dist/cjs/rules/requireThrows.js +101 -0
  127. package/dist/cjs/rules/requireYields.d.ts +2 -0
  128. package/dist/cjs/rules/requireYields.js +172 -0
  129. package/dist/cjs/rules/requireYieldsCheck.d.ts +2 -0
  130. package/dist/cjs/rules/requireYieldsCheck.js +164 -0
  131. package/dist/cjs/rules/sortTags.d.ts +2 -0
  132. package/dist/cjs/rules/sortTags.js +392 -0
  133. package/dist/cjs/rules/tagLines.d.ts +2 -0
  134. package/dist/cjs/rules/tagLines.js +259 -0
  135. package/dist/cjs/rules/textEscaping.d.ts +2 -0
  136. package/dist/cjs/rules/textEscaping.js +125 -0
  137. package/dist/cjs/rules/typeFormatting.d.ts +2 -0
  138. package/dist/cjs/rules/typeFormatting.js +328 -0
  139. package/dist/cjs/rules/validTypes.d.ts +2 -0
  140. package/dist/cjs/rules/validTypes.js +333 -0
  141. package/dist/cjs/tagNames.d.ts +15 -0
  142. package/dist/cjs/tagNames.js +209 -0
  143. package/dist/cjs/utils/hasReturnValue.d.ts +19 -0
  144. package/dist/cjs/utils/hasReturnValue.js +469 -0
  145. package/dist/getJsdocProcessorPlugin.cts +3 -0
  146. package/dist/index.cjs.cts +3 -0
  147. package/dist/iterateJsdoc.cts +6 -0
  148. package/dist/rules/typeFormatting.cjs +82 -38
  149. package/dist/rules/typeFormatting.cjs.map +1 -1
  150. package/dist/rules.d.ts +4 -7
  151. package/package.json +24 -13
  152. package/src/getJsdocProcessorPlugin.cts +3 -0
  153. package/src/index.cjs.cts +3 -0
  154. package/src/iterateJsdoc.cts +6 -0
  155. package/src/rules/typeFormatting.js +104 -40
  156. package/src/rules.d.ts +4 -7
@@ -0,0 +1,297 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const alignTransform_js_1 = __importDefault(require("../alignTransform.js"));
7
+ const iterateJsdoc_js_1 = __importDefault(require("../iterateJsdoc.js"));
8
+ const comment_parser_1 = require("comment-parser");
9
+ const { flow: commentFlow, } = comment_parser_1.transforms;
10
+ /**
11
+ * @typedef {{
12
+ * postDelimiter: import('../iterateJsdoc.js').Integer,
13
+ * postHyphen: import('../iterateJsdoc.js').Integer,
14
+ * postName: import('../iterateJsdoc.js').Integer,
15
+ * postTag: import('../iterateJsdoc.js').Integer,
16
+ * postType: import('../iterateJsdoc.js').Integer,
17
+ * }} CustomSpacings
18
+ */
19
+ /**
20
+ * @param {import('../iterateJsdoc.js').Utils} utils
21
+ * @param {import('comment-parser').Spec & {
22
+ * line: import('../iterateJsdoc.js').Integer
23
+ * }} tag
24
+ * @param {CustomSpacings} customSpacings
25
+ */
26
+ const checkNotAlignedPerTag = (utils, tag, customSpacings) => {
27
+ /*
28
+ start +
29
+ delimiter +
30
+ postDelimiter +
31
+ tag +
32
+ postTag +
33
+ type +
34
+ postType +
35
+ name +
36
+ postName +
37
+ description +
38
+ end +
39
+ lineEnd
40
+ */
41
+ /**
42
+ * @typedef {"tag"|"type"|"name"|"description"} ContentProp
43
+ */
44
+ /** @type {("postDelimiter"|"postTag"|"postType"|"postName")[]} */
45
+ let spacerProps;
46
+ /** @type {ContentProp[]} */
47
+ let contentProps;
48
+ const mightHaveNamepath = utils.tagMightHaveNamepath(tag.tag);
49
+ if (mightHaveNamepath) {
50
+ spacerProps = [
51
+ 'postDelimiter', 'postTag', 'postType', 'postName',
52
+ ];
53
+ contentProps = [
54
+ 'tag', 'type', 'name', 'description',
55
+ ];
56
+ }
57
+ else {
58
+ spacerProps = [
59
+ 'postDelimiter', 'postTag', 'postType',
60
+ ];
61
+ contentProps = [
62
+ 'tag', 'type', 'description',
63
+ ];
64
+ }
65
+ const { tokens, } = tag.source[0];
66
+ /**
67
+ * @param {import('../iterateJsdoc.js').Integer} idx
68
+ * @param {(notRet: boolean, contentProp: ContentProp) => void} [callbck]
69
+ */
70
+ const followedBySpace = (idx, callbck) => {
71
+ const nextIndex = idx + 1;
72
+ return spacerProps.slice(nextIndex).some((spacerProp, innerIdx) => {
73
+ const contentProp = contentProps[nextIndex + innerIdx];
74
+ const spacePropVal = tokens[spacerProp];
75
+ const ret = spacePropVal;
76
+ if (callbck) {
77
+ callbck(!ret, contentProp);
78
+ }
79
+ return ret && (callbck || !contentProp);
80
+ });
81
+ };
82
+ const postHyphenSpacing = customSpacings?.postHyphen ?? 1;
83
+ const exactHyphenSpacing = new RegExp(`^\\s*-\\s{${postHyphenSpacing},${postHyphenSpacing}}(?!\\s)`, 'v');
84
+ const hasNoHyphen = !(/^\s*-(?!$)(?=\s)/v).test(tokens.description);
85
+ const hasExactHyphenSpacing = exactHyphenSpacing.test(tokens.description);
86
+ // If checking alignment on multiple lines, need to check other `source`
87
+ // items
88
+ // Go through `post*` spacing properties and exit to indicate problem if
89
+ // extra spacing detected
90
+ const ok = !spacerProps.some((spacerProp, idx) => {
91
+ const contentProp = contentProps[idx];
92
+ const contentPropVal = tokens[contentProp];
93
+ const spacerPropVal = tokens[spacerProp];
94
+ const spacing = customSpacings?.[spacerProp] || 1;
95
+ // There will be extra alignment if...
96
+ // 1. The spaces don't match the space it should have (1 or custom spacing) OR
97
+ return spacerPropVal.length !== spacing && spacerPropVal.length !== 0 ||
98
+ // 2. There is a (single) space, no immediate content, and yet another
99
+ // space is found subsequently (not separated by intervening content)
100
+ spacerPropVal && !contentPropVal && followedBySpace(idx);
101
+ }) && (hasNoHyphen || hasExactHyphenSpacing);
102
+ if (ok) {
103
+ return;
104
+ }
105
+ const fix = () => {
106
+ for (const [idx, spacerProp,] of spacerProps.entries()) {
107
+ const contentProp = contentProps[idx];
108
+ const contentPropVal = tokens[contentProp];
109
+ if (contentPropVal) {
110
+ const spacing = customSpacings?.[spacerProp] || 1;
111
+ tokens[spacerProp] = ''.padStart(spacing, ' ');
112
+ followedBySpace(idx, (hasSpace, contentPrp) => {
113
+ if (hasSpace) {
114
+ tokens[contentPrp] = '';
115
+ }
116
+ });
117
+ }
118
+ else {
119
+ tokens[spacerProp] = '';
120
+ }
121
+ }
122
+ if (!hasExactHyphenSpacing) {
123
+ const hyphenSpacing = /^\s*-\s+/v;
124
+ tokens.description = tokens.description.replace(hyphenSpacing, '-' + ''.padStart(postHyphenSpacing, ' '));
125
+ }
126
+ utils.setTag(tag, tokens);
127
+ };
128
+ utils.reportJSDoc('Expected JSDoc block lines to not be aligned.', tag, fix, true);
129
+ };
130
+ /**
131
+ * @param {object} cfg
132
+ * @param {CustomSpacings} cfg.customSpacings
133
+ * @param {string} cfg.indent
134
+ * @param {import('comment-parser').Block} cfg.jsdoc
135
+ * @param {import('eslint').Rule.Node & {
136
+ * range: [number, number]
137
+ * }} cfg.jsdocNode
138
+ * @param {boolean} cfg.preserveMainDescriptionPostDelimiter
139
+ * @param {import('../iterateJsdoc.js').Report} cfg.report
140
+ * @param {string[]} cfg.tags
141
+ * @param {import('../iterateJsdoc.js').Utils} cfg.utils
142
+ * @param {string} cfg.wrapIndent
143
+ * @param {boolean} cfg.disableWrapIndent
144
+ * @returns {void}
145
+ */
146
+ const checkAlignment = ({ customSpacings, disableWrapIndent, indent, jsdoc, jsdocNode, preserveMainDescriptionPostDelimiter, report, tags, utils, wrapIndent, }) => {
147
+ const transform = commentFlow((0, alignTransform_js_1.default)({
148
+ customSpacings,
149
+ disableWrapIndent,
150
+ indent,
151
+ preserveMainDescriptionPostDelimiter,
152
+ tags,
153
+ wrapIndent,
154
+ }));
155
+ const transformedJsdoc = transform(jsdoc);
156
+ const comment = '/*' +
157
+ /**
158
+ * @type {import('eslint').Rule.Node & {
159
+ * range: [number, number], value: string
160
+ * }}
161
+ */ (jsdocNode).value + '*/';
162
+ const formatted = utils.stringify(transformedJsdoc)
163
+ .trimStart();
164
+ if (comment !== formatted) {
165
+ report('Expected JSDoc block lines to be aligned.',
166
+ /** @type {import('eslint').Rule.ReportFixer} */ (fixer) => {
167
+ return fixer.replaceText(jsdocNode, formatted);
168
+ });
169
+ }
170
+ };
171
+ exports.default = (0, iterateJsdoc_js_1.default)(({ context, indent, jsdoc, jsdocNode, report, utils, }) => {
172
+ const { customSpacings, disableWrapIndent = false, preserveMainDescriptionPostDelimiter, tags: applicableTags = [
173
+ 'param', 'arg', 'argument', 'property', 'prop', 'returns', 'return', 'template',
174
+ ], wrapIndent = '', } = context.options[1] || {};
175
+ if (context.options[0] === 'always') {
176
+ // Skip if it contains only a single line.
177
+ if (!(
178
+ /**
179
+ * @type {import('eslint').Rule.Node & {
180
+ * range: [number, number], value: string
181
+ * }}
182
+ */
183
+ (jsdocNode).value.includes('\n'))) {
184
+ return;
185
+ }
186
+ checkAlignment({
187
+ customSpacings,
188
+ disableWrapIndent,
189
+ indent,
190
+ jsdoc,
191
+ jsdocNode,
192
+ preserveMainDescriptionPostDelimiter,
193
+ report,
194
+ tags: applicableTags,
195
+ utils,
196
+ wrapIndent,
197
+ });
198
+ return;
199
+ }
200
+ const foundTags = utils.getPresentTags(applicableTags);
201
+ if (context.options[0] !== 'any') {
202
+ for (const tag of foundTags) {
203
+ checkNotAlignedPerTag(utils,
204
+ /**
205
+ * @type {import('comment-parser').Spec & {
206
+ * line: import('../iterateJsdoc.js').Integer
207
+ * }}
208
+ */
209
+ (tag), customSpacings);
210
+ }
211
+ }
212
+ for (const tag of foundTags) {
213
+ if (tag.source.length > 1) {
214
+ let idx = 0;
215
+ for (const { tokens,
216
+ // Avoid the tag line
217
+ } of tag.source.slice(1)) {
218
+ idx++;
219
+ if (!tokens.description ||
220
+ // Avoid first lines after multiline type
221
+ tokens.type ||
222
+ tokens.name) {
223
+ continue;
224
+ }
225
+ // Don't include a single separating space/tab
226
+ if (!disableWrapIndent && tokens.postDelimiter.slice(1) !== wrapIndent) {
227
+ utils.reportJSDoc('Expected wrap indent', {
228
+ line: tag.source[0].number + idx,
229
+ }, () => {
230
+ tokens.postDelimiter = tokens.postDelimiter.charAt(0) + wrapIndent;
231
+ });
232
+ return;
233
+ }
234
+ }
235
+ }
236
+ }
237
+ }, {
238
+ iterateAllJsdocs: true,
239
+ meta: {
240
+ docs: {
241
+ description: 'Reports invalid alignment of JSDoc block lines.',
242
+ url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-line-alignment.md#repos-sticky-header',
243
+ },
244
+ fixable: 'whitespace',
245
+ schema: [
246
+ {
247
+ enum: [
248
+ 'always', 'never', 'any',
249
+ ],
250
+ type: 'string',
251
+ },
252
+ {
253
+ additionalProperties: false,
254
+ properties: {
255
+ customSpacings: {
256
+ additionalProperties: false,
257
+ properties: {
258
+ postDelimiter: {
259
+ type: 'integer',
260
+ },
261
+ postHyphen: {
262
+ type: 'integer',
263
+ },
264
+ postName: {
265
+ type: 'integer',
266
+ },
267
+ postTag: {
268
+ type: 'integer',
269
+ },
270
+ postType: {
271
+ type: 'integer',
272
+ },
273
+ },
274
+ },
275
+ disableWrapIndent: {
276
+ type: 'boolean',
277
+ },
278
+ preserveMainDescriptionPostDelimiter: {
279
+ default: false,
280
+ type: 'boolean',
281
+ },
282
+ tags: {
283
+ items: {
284
+ type: 'string',
285
+ },
286
+ type: 'array',
287
+ },
288
+ wrapIndent: {
289
+ type: 'string',
290
+ },
291
+ },
292
+ type: 'object',
293
+ },
294
+ ],
295
+ type: 'layout',
296
+ },
297
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("eslint").Rule.RuleModule;
2
+ export default _default;
@@ -0,0 +1,320 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const iterateJsdoc_js_1 = __importDefault(require("../iterateJsdoc.js"));
7
+ /**
8
+ * @param {string} targetTagName
9
+ * @param {boolean} allowExtraTrailingParamDocs
10
+ * @param {boolean} checkDestructured
11
+ * @param {boolean} checkRestProperty
12
+ * @param {RegExp} checkTypesRegex
13
+ * @param {boolean} disableExtraPropertyReporting
14
+ * @param {boolean} disableMissingParamChecks
15
+ * @param {boolean} enableFixer
16
+ * @param {import('../jsdocUtils.js').ParamNameInfo[]} functionParameterNames
17
+ * @param {import('comment-parser').Block} jsdoc
18
+ * @param {import('../iterateJsdoc.js').Utils} utils
19
+ * @param {import('../iterateJsdoc.js').Report} report
20
+ * @returns {boolean}
21
+ */
22
+ const validateParameterNames = (targetTagName, allowExtraTrailingParamDocs, checkDestructured, checkRestProperty, checkTypesRegex, disableExtraPropertyReporting, disableMissingParamChecks, enableFixer, functionParameterNames, jsdoc, utils, report) => {
23
+ const paramTags = Object.entries(jsdoc.tags).filter(([, tag,]) => {
24
+ return tag.tag === targetTagName;
25
+ });
26
+ const paramTagsNonNested = paramTags.filter(([, tag,]) => {
27
+ return !tag.name.includes('.');
28
+ });
29
+ let dotted = 0;
30
+ let thisOffset = 0;
31
+ // eslint-disable-next-line complexity
32
+ return paramTags.some(([, tag,], index) => {
33
+ /** @type {import('../iterateJsdoc.js').Integer} */
34
+ let tagsIndex;
35
+ const dupeTagInfo = paramTags.find(([tgsIndex, tg,], idx) => {
36
+ tagsIndex = Number(tgsIndex);
37
+ return tg.name === tag.name && idx !== index;
38
+ });
39
+ if (dupeTagInfo) {
40
+ utils.reportJSDoc(`Duplicate @${targetTagName} "${tag.name}"`, dupeTagInfo[1], enableFixer ? () => {
41
+ utils.removeTag(tagsIndex);
42
+ } : null);
43
+ return true;
44
+ }
45
+ if (tag.name.includes('.')) {
46
+ dotted++;
47
+ return false;
48
+ }
49
+ let functionParameterName = functionParameterNames[index - dotted + thisOffset];
50
+ if (functionParameterName === 'this' && tag.name.trim() !== 'this') {
51
+ ++thisOffset;
52
+ functionParameterName = functionParameterNames[index - dotted + thisOffset];
53
+ }
54
+ if (!functionParameterName) {
55
+ if (allowExtraTrailingParamDocs) {
56
+ return false;
57
+ }
58
+ report(`@${targetTagName} "${tag.name}" does not match an existing function parameter.`, null, tag);
59
+ return true;
60
+ }
61
+ if (typeof functionParameterName === 'object' &&
62
+ 'name' in functionParameterName &&
63
+ Array.isArray(functionParameterName.name)) {
64
+ const actualName = tag.name.trim();
65
+ const expectedName = functionParameterName.name[index];
66
+ if (actualName === expectedName) {
67
+ thisOffset--;
68
+ return false;
69
+ }
70
+ report(`Expected @${targetTagName} name to be "${expectedName}". Got "${actualName}".`, null, tag);
71
+ return true;
72
+ }
73
+ if (Array.isArray(functionParameterName)) {
74
+ if (!checkDestructured) {
75
+ return false;
76
+ }
77
+ if (tag.type && tag.type.search(checkTypesRegex) === -1) {
78
+ return false;
79
+ }
80
+ const [parameterName, { annotationParamName, hasPropertyRest, names: properties, rests, },] =
81
+ /**
82
+ * @type {[string | undefined, import('../jsdocUtils.js').FlattendRootInfo & {
83
+ * annotationParamName?: string | undefined;
84
+ }]} */ (functionParameterName);
85
+ if (annotationParamName !== undefined) {
86
+ const name = tag.name.trim();
87
+ if (name !== annotationParamName) {
88
+ report(`@${targetTagName} "${name}" does not match parameter name "${annotationParamName}"`, null, tag);
89
+ }
90
+ }
91
+ const tagName = parameterName === undefined ? tag.name.trim() : parameterName;
92
+ const expectedNames = properties.map((name) => {
93
+ return `${tagName}.${name}`;
94
+ });
95
+ const actualNames = paramTags.map(([, paramTag,]) => {
96
+ return paramTag.name.trim();
97
+ });
98
+ const actualTypes = paramTags.map(([, paramTag,]) => {
99
+ return paramTag.type;
100
+ });
101
+ const missingProperties = [];
102
+ /** @type {string[]} */
103
+ const notCheckingNames = [];
104
+ for (const [idx, name,] of expectedNames.entries()) {
105
+ if (notCheckingNames.some((notCheckingName) => {
106
+ return name.startsWith(notCheckingName);
107
+ })) {
108
+ continue;
109
+ }
110
+ const actualNameIdx = actualNames.findIndex((actualName) => {
111
+ return utils.comparePaths(name)(actualName);
112
+ });
113
+ if (actualNameIdx === -1) {
114
+ if (!checkRestProperty && rests[idx]) {
115
+ continue;
116
+ }
117
+ const missingIndex = actualNames.findIndex((actualName) => {
118
+ return utils.pathDoesNotBeginWith(name, actualName);
119
+ });
120
+ const line = tag.source[0].number - 1 + (missingIndex > -1 ? missingIndex : actualNames.length);
121
+ missingProperties.push({
122
+ name,
123
+ tagPlacement: {
124
+ line: line === 0 ? 1 : line,
125
+ },
126
+ });
127
+ }
128
+ else if (actualTypes[actualNameIdx].search(checkTypesRegex) === -1 && actualTypes[actualNameIdx] !== '') {
129
+ notCheckingNames.push(name);
130
+ }
131
+ }
132
+ const hasMissing = missingProperties.length;
133
+ if (hasMissing) {
134
+ for (const { name: missingProperty, tagPlacement, } of missingProperties) {
135
+ report(`Missing @${targetTagName} "${missingProperty}"`, null, tagPlacement);
136
+ }
137
+ }
138
+ if (!hasPropertyRest || checkRestProperty) {
139
+ /** @type {[string, import('comment-parser').Spec][]} */
140
+ const extraProperties = [];
141
+ for (const [idx, name,] of actualNames.entries()) {
142
+ const match = name.startsWith(tag.name.trim() + '.');
143
+ if (match && !expectedNames.some(utils.comparePaths(name)) && !utils.comparePaths(name)(tag.name) &&
144
+ (!disableExtraPropertyReporting || properties.some((prop) => {
145
+ return prop.split('.').length >= name.split('.').length - 1;
146
+ }))) {
147
+ extraProperties.push([
148
+ name, paramTags[idx][1],
149
+ ]);
150
+ }
151
+ }
152
+ if (extraProperties.length) {
153
+ for (const [extraProperty, tg,] of extraProperties) {
154
+ report(`@${targetTagName} "${extraProperty}" does not exist on ${tag.name}`, null, tg);
155
+ }
156
+ return true;
157
+ }
158
+ }
159
+ return hasMissing;
160
+ }
161
+ let funcParamName;
162
+ if (typeof functionParameterName === 'object') {
163
+ const { name, } = functionParameterName;
164
+ funcParamName = name;
165
+ }
166
+ else {
167
+ funcParamName = functionParameterName;
168
+ }
169
+ if (funcParamName !== tag.name.trim()) {
170
+ // Todo: Improve for array or object child items
171
+ const actualNames = paramTagsNonNested.map(([, { name, },]) => {
172
+ return name.trim();
173
+ });
174
+ const expectedNames = functionParameterNames.map((item, idx) => {
175
+ if ( /**
176
+ * @type {[string|undefined, (import('../jsdocUtils.js').FlattendRootInfo & {
177
+ * annotationParamName?: string,
178
+ })]} */(item)?.[1]?.names) {
179
+ return actualNames[idx];
180
+ }
181
+ return item;
182
+ }).filter((item) => {
183
+ return item !== 'this';
184
+ });
185
+ // When disableMissingParamChecks is true tag names can be omitted.
186
+ // Report when the tag names do not match the expected names or they are used out of order.
187
+ if (disableMissingParamChecks) {
188
+ const usedExpectedNames = expectedNames.map((a) => {
189
+ return a?.toString();
190
+ }).filter((expectedName) => {
191
+ return expectedName && actualNames.includes(expectedName);
192
+ });
193
+ const usedInOrder = actualNames.every((actualName, idx) => {
194
+ return actualName === usedExpectedNames[idx];
195
+ });
196
+ if (usedInOrder) {
197
+ return false;
198
+ }
199
+ }
200
+ report(`Expected @${targetTagName} names to be "${expectedNames.map((expectedName) => {
201
+ return typeof expectedName === 'object' &&
202
+ 'name' in expectedName &&
203
+ expectedName.restElement ?
204
+ '...' + expectedName.name :
205
+ expectedName;
206
+ }).join(', ')}". Got "${actualNames.join(', ')}".`, null, tag);
207
+ return true;
208
+ }
209
+ return false;
210
+ });
211
+ };
212
+ /**
213
+ * @param {string} targetTagName
214
+ * @param {boolean} _allowExtraTrailingParamDocs
215
+ * @param {{
216
+ * name: string,
217
+ * idx: import('../iterateJsdoc.js').Integer
218
+ * }[]} jsdocParameterNames
219
+ * @param {import('comment-parser').Block} jsdoc
220
+ * @param {Function} report
221
+ * @returns {boolean}
222
+ */
223
+ const validateParameterNamesDeep = (targetTagName, _allowExtraTrailingParamDocs, jsdocParameterNames, jsdoc, report) => {
224
+ /** @type {string} */
225
+ let lastRealParameter;
226
+ return jsdocParameterNames.some(({ idx, name: jsdocParameterName, }) => {
227
+ const isPropertyPath = jsdocParameterName.includes('.');
228
+ if (isPropertyPath) {
229
+ if (!lastRealParameter) {
230
+ report(`@${targetTagName} path declaration ("${jsdocParameterName}") appears before any real parameter.`, null, jsdoc.tags[idx]);
231
+ return true;
232
+ }
233
+ let pathRootNodeName = jsdocParameterName.slice(0, jsdocParameterName.indexOf('.'));
234
+ if (pathRootNodeName.endsWith('[]')) {
235
+ pathRootNodeName = pathRootNodeName.slice(0, -2);
236
+ }
237
+ if (pathRootNodeName !== lastRealParameter) {
238
+ report(`@${targetTagName} path declaration ("${jsdocParameterName}") root node name ("${pathRootNodeName}") ` +
239
+ `does not match previous real parameter name ("${lastRealParameter}").`, null, jsdoc.tags[idx]);
240
+ return true;
241
+ }
242
+ }
243
+ else {
244
+ lastRealParameter = jsdocParameterName;
245
+ }
246
+ return false;
247
+ });
248
+ };
249
+ const allowedNodes = [
250
+ 'ArrowFunctionExpression', 'FunctionDeclaration', 'FunctionExpression', 'TSDeclareFunction',
251
+ // Add this to above defaults
252
+ 'TSMethodSignature',
253
+ ];
254
+ exports.default = (0, iterateJsdoc_js_1.default)(({ context, jsdoc, node, report, utils, }) => {
255
+ const { allowExtraTrailingParamDocs, checkDestructured = true, checkRestProperty = false, checkTypesPattern = '/^(?:[oO]bject|[aA]rray|PlainObject|Generic(?:Object|Array))$/', disableExtraPropertyReporting = false, disableMissingParamChecks = false, enableFixer = false, useDefaultObjectProperties = false, } = context.options[0] || {};
256
+ // Although we might just remove global settings contexts from applying to
257
+ // this rule (as they can cause problems with `getFunctionParameterNames`
258
+ // checks if they are not functions but say variables), the user may
259
+ // instead wish to narrow contexts in those settings, so this check
260
+ // is still useful
261
+ if (!allowedNodes.includes(/** @type {import('estree').Node} */ (node).type)) {
262
+ return;
263
+ }
264
+ const checkTypesRegex = utils.getRegexFromString(checkTypesPattern);
265
+ const jsdocParameterNamesDeep = utils.getJsdocTagsDeep('param');
266
+ if (!jsdocParameterNamesDeep || !jsdocParameterNamesDeep.length) {
267
+ return;
268
+ }
269
+ const functionParameterNames = utils.getFunctionParameterNames(useDefaultObjectProperties);
270
+ const targetTagName = /** @type {string} */ (utils.getPreferredTagName({
271
+ tagName: 'param',
272
+ }));
273
+ const isError = validateParameterNames(targetTagName, allowExtraTrailingParamDocs, checkDestructured, checkRestProperty, checkTypesRegex, disableExtraPropertyReporting, disableMissingParamChecks, enableFixer, functionParameterNames, jsdoc, utils, report);
274
+ if (isError || !checkDestructured) {
275
+ return;
276
+ }
277
+ validateParameterNamesDeep(targetTagName, allowExtraTrailingParamDocs, jsdocParameterNamesDeep, jsdoc, report);
278
+ }, {
279
+ contextDefaults: allowedNodes,
280
+ meta: {
281
+ docs: {
282
+ description: 'Ensures that parameter names in JSDoc match those in the function declaration.',
283
+ url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-param-names.md#repos-sticky-header',
284
+ },
285
+ fixable: 'code',
286
+ schema: [
287
+ {
288
+ additionalProperties: false,
289
+ properties: {
290
+ allowExtraTrailingParamDocs: {
291
+ type: 'boolean',
292
+ },
293
+ checkDestructured: {
294
+ type: 'boolean',
295
+ },
296
+ checkRestProperty: {
297
+ type: 'boolean',
298
+ },
299
+ checkTypesPattern: {
300
+ type: 'string',
301
+ },
302
+ disableExtraPropertyReporting: {
303
+ type: 'boolean',
304
+ },
305
+ disableMissingParamChecks: {
306
+ type: 'boolean',
307
+ },
308
+ enableFixer: {
309
+ type: 'boolean',
310
+ },
311
+ useDefaultObjectProperties: {
312
+ type: 'boolean',
313
+ },
314
+ },
315
+ type: 'object',
316
+ },
317
+ ],
318
+ type: 'suggestion',
319
+ },
320
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("eslint").Rule.RuleModule;
2
+ export default _default;