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,1981 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.parseComment = exports.getSettings = void 0;
40
+ exports.default = iterateJsdoc;
41
+ const jsdocUtils = __importStar(require("./jsdocUtils.js"));
42
+ const jsdoccomment_1 = require("@es-joy/jsdoccomment");
43
+ const comment_parser_1 = require("comment-parser");
44
+ const esquery_1 = __importDefault(require("esquery"));
45
+ /**
46
+ * @typedef {number} Integer
47
+ */
48
+ /**
49
+ * @typedef {import('@es-joy/jsdoccomment').JsdocBlockWithInline} JsdocBlockWithInline
50
+ */
51
+ /**
52
+ * @typedef {{
53
+ * disallowName?: string,
54
+ * allowName?: string,
55
+ * context?: string,
56
+ * comment?: string,
57
+ * tags?: string[],
58
+ * replacement?: string,
59
+ * minimum?: Integer,
60
+ * message?: string,
61
+ * forceRequireReturn?: boolean
62
+ * }} ContextObject
63
+ */
64
+ /**
65
+ * @typedef {string|ContextObject} Context
66
+ */
67
+ /**
68
+ * @callback CheckJsdoc
69
+ * @param {{
70
+ * lastIndex?: Integer,
71
+ * isFunctionContext?: boolean,
72
+ * selector?: string,
73
+ * comment?: string
74
+ * }} info
75
+ * @param {null|((jsdoc: import('@es-joy/jsdoccomment').JsdocBlockWithInline) => boolean|undefined)} handler
76
+ * @param {import('eslint').Rule.Node} node
77
+ * @returns {void}
78
+ */
79
+ /**
80
+ * @callback ForEachPreferredTag
81
+ * @param {string} tagName
82
+ * @param {(
83
+ * matchingJsdocTag: import('@es-joy/jsdoccomment').JsdocTagWithInline,
84
+ * targetTagName: string
85
+ * ) => void} arrayHandler
86
+ * @param {boolean} [skipReportingBlockedTag]
87
+ * @returns {void}
88
+ */
89
+ /**
90
+ * @callback ReportSettings
91
+ * @param {string} message
92
+ * @returns {void}
93
+ */
94
+ /**
95
+ * @callback ParseClosureTemplateTag
96
+ * @param {import('comment-parser').Spec} tag
97
+ * @returns {string[]}
98
+ */
99
+ /**
100
+ * @callback GetPreferredTagNameObject
101
+ * @param {{
102
+ * tagName: string
103
+ * }} cfg
104
+ * @returns {string|false|{
105
+ * message: string;
106
+ * replacement?: string|undefined
107
+ * }|{
108
+ * blocked: true,
109
+ * tagName: string
110
+ * }}
111
+ */
112
+ /**
113
+ * @typedef {{
114
+ * forEachPreferredTag: ForEachPreferredTag,
115
+ * reportSettings: ReportSettings,
116
+ * parseClosureTemplateTag: ParseClosureTemplateTag,
117
+ * getPreferredTagNameObject: GetPreferredTagNameObject,
118
+ * pathDoesNotBeginWith: import('./jsdocUtils.js').PathDoesNotBeginWith
119
+ * }} BasicUtils
120
+ */
121
+ /**
122
+ * @callback IsIteratingFunction
123
+ * @returns {boolean}
124
+ */
125
+ /**
126
+ * @callback IsVirtualFunction
127
+ * @returns {boolean}
128
+ */
129
+ /**
130
+ * @callback Stringify
131
+ * @param {import('comment-parser').Block} tagBlock
132
+ * @param {boolean} [specRewire]
133
+ * @returns {string}
134
+ */
135
+ /**
136
+ * @callback ReportJSDoc
137
+ * @param {string} msg
138
+ * @param {null|import('comment-parser').Spec|{line: Integer, column?: Integer}} [tag]
139
+ * @param {(() => void)|null} [handler]
140
+ * @param {boolean} [specRewire]
141
+ * @param {undefined|{
142
+ * [key: string]: string
143
+ * }} [data]
144
+ */
145
+ /**
146
+ * @callback GetRegexFromString
147
+ * @param {string} str
148
+ * @param {string} [requiredFlags]
149
+ * @returns {RegExp}
150
+ */
151
+ /**
152
+ * @callback GetTagDescription
153
+ * @param {import('comment-parser').Spec} tg
154
+ * @param {boolean} [returnArray]
155
+ * @returns {string[]|string}
156
+ */
157
+ /**
158
+ * @callback SetTagDescription
159
+ * @param {import('comment-parser').Spec} tg
160
+ * @param {RegExp} matcher
161
+ * @param {(description: string) => string} setter
162
+ * @returns {Integer}
163
+ */
164
+ /**
165
+ * @callback GetDescription
166
+ * @returns {{
167
+ * description: string,
168
+ * descriptions: string[],
169
+ * lastDescriptionLine: Integer
170
+ * }}
171
+ */
172
+ /**
173
+ * @callback SetBlockDescription
174
+ * @param {(
175
+ * info: {
176
+ * delimiter: string,
177
+ * postDelimiter: string,
178
+ * start: string
179
+ * },
180
+ * seedTokens: (
181
+ * tokens?: Partial<import('comment-parser').Tokens>
182
+ * ) => import('comment-parser').Tokens,
183
+ * descLines: string[]
184
+ * ) => import('comment-parser').Line[]} setter
185
+ * @returns {void}
186
+ */
187
+ /**
188
+ * @callback SetDescriptionLines
189
+ * @param {RegExp} matcher
190
+ * @param {(description: string) => string} setter
191
+ * @returns {Integer}
192
+ */
193
+ /**
194
+ * @callback ChangeTag
195
+ * @param {import('comment-parser').Spec} tag
196
+ * @param {...Partial<import('comment-parser').Tokens>} tokens
197
+ * @returns {void}
198
+ */
199
+ /**
200
+ * @callback SetTag
201
+ * @param {import('comment-parser').Spec & {
202
+ * line: Integer
203
+ * }} tag
204
+ * @param {Partial<import('comment-parser').Tokens>} [tokens]
205
+ * @returns {void}
206
+ */
207
+ /**
208
+ * @callback RemoveTag
209
+ * @param {Integer} tagIndex
210
+ * @param {{
211
+ * removeEmptyBlock?: boolean,
212
+ * tagSourceOffset?: Integer
213
+ * }} [cfg]
214
+ * @returns {void}
215
+ */
216
+ /**
217
+ * @callback AddTag
218
+ * @param {string} targetTagName
219
+ * @param {Integer} [number]
220
+ * @param {import('comment-parser').Tokens|{}} [tokens]
221
+ * @returns {void}
222
+ */
223
+ /**
224
+ * @callback GetFirstLine
225
+ * @returns {Integer|undefined}
226
+ */
227
+ /**
228
+ * @typedef {(
229
+ * tokens?: Partial<import('comment-parser').Tokens> | undefined
230
+ * ) => import('comment-parser').Tokens} SeedTokens
231
+ */
232
+ /**
233
+ * Sets tokens to empty string.
234
+ * @callback EmptyTokens
235
+ * @param {import('comment-parser').Tokens} tokens
236
+ * @returns {void}
237
+ */
238
+ /**
239
+ * @callback AddLine
240
+ * @param {Integer} sourceIndex
241
+ * @param {Partial<import('comment-parser').Tokens>} tokens
242
+ * @returns {void}
243
+ */
244
+ /**
245
+ * @callback AddLines
246
+ * @param {Integer} tagIndex
247
+ * @param {Integer} tagSourceOffset
248
+ * @param {Integer} numLines
249
+ * @returns {void}
250
+ */
251
+ /**
252
+ * @callback MakeMultiline
253
+ * @returns {void}
254
+ */
255
+ /**
256
+ * @callback GetFunctionParameterNames
257
+ * @param {boolean} [useDefaultObjectProperties]
258
+ * @returns {import('./jsdocUtils.js').ParamNameInfo[]}
259
+ */
260
+ /**
261
+ * @callback HasParams
262
+ * @returns {Integer}
263
+ */
264
+ /**
265
+ * @callback IsGenerator
266
+ * @returns {boolean}
267
+ */
268
+ /**
269
+ * @callback IsConstructor
270
+ * @returns {boolean}
271
+ */
272
+ /**
273
+ * @callback GetJsdocTagsDeep
274
+ * @param {string} tagName
275
+ * @returns {false|{
276
+ * idx: Integer,
277
+ * name: string,
278
+ * type: string
279
+ * }[]}
280
+ */
281
+ /**
282
+ * @callback GetPreferredTagName
283
+ * @param {{
284
+ * tagName: string,
285
+ * skipReportingBlockedTag?: boolean,
286
+ * allowObjectReturn?: boolean,
287
+ * defaultMessage?: string
288
+ * }} cfg
289
+ * @returns {string|undefined|false|{
290
+ * message: string;
291
+ * replacement?: string|undefined;
292
+ * }|{
293
+ * blocked: true,
294
+ * tagName: string
295
+ * }}
296
+ */
297
+ /**
298
+ * @callback IsValidTag
299
+ * @param {string} name
300
+ * @param {string[]} definedTags
301
+ * @returns {boolean}
302
+ */
303
+ /**
304
+ * @callback HasATag
305
+ * @param {string[]} names
306
+ * @returns {boolean}
307
+ */
308
+ /**
309
+ * @callback HasTag
310
+ * @param {string} name
311
+ * @returns {boolean}
312
+ */
313
+ /**
314
+ * @callback ComparePaths
315
+ * @param {string} name
316
+ * @returns {(otherPathName: string) => boolean}
317
+ */
318
+ /**
319
+ * @callback DropPathSegmentQuotes
320
+ * @param {string} name
321
+ * @returns {string}
322
+ */
323
+ /**
324
+ * @callback AvoidDocs
325
+ * @returns {boolean}
326
+ */
327
+ /**
328
+ * @callback TagMightHaveNamePositionTypePosition
329
+ * @param {string} tagName
330
+ * @param {import('./getDefaultTagStructureForMode.js').
331
+ * TagStructure[]} [otherModeMaps]
332
+ * @returns {boolean|{otherMode: true}}
333
+ */
334
+ /**
335
+ * @callback TagMustHave
336
+ * @param {string} tagName
337
+ * @param {import('./getDefaultTagStructureForMode.js').
338
+ * TagStructure[]} otherModeMaps
339
+ * @returns {boolean|{
340
+ * otherMode: false
341
+ * }}
342
+ */
343
+ /**
344
+ * @callback TagMissingRequiredTypeOrNamepath
345
+ * @param {import('comment-parser').Spec} tag
346
+ * @param {import('./getDefaultTagStructureForMode.js').
347
+ * TagStructure[]} otherModeMaps
348
+ * @returns {boolean|{
349
+ * otherMode: false
350
+ * }}
351
+ */
352
+ /**
353
+ * @callback IsNamepathX
354
+ * @param {string} tagName
355
+ * @returns {boolean}
356
+ */
357
+ /**
358
+ * @callback GetTagStructureForMode
359
+ * @param {import('./jsdocUtils.js').ParserMode} mde
360
+ * @returns {import('./getDefaultTagStructureForMode.js').TagStructure}
361
+ */
362
+ /**
363
+ * @callback MayBeUndefinedTypeTag
364
+ * @param {import('comment-parser').Spec} tag
365
+ * @returns {boolean}
366
+ */
367
+ /**
368
+ * @callback HasValueOrExecutorHasNonEmptyResolveValue
369
+ * @param {boolean} anyPromiseAsReturn
370
+ * @param {boolean} [allBranches]
371
+ * @returns {boolean}
372
+ */
373
+ /**
374
+ * @callback HasYieldValue
375
+ * @returns {boolean}
376
+ */
377
+ /**
378
+ * @callback HasYieldReturnValue
379
+ * @returns {boolean}
380
+ */
381
+ /**
382
+ * @callback HasThrowValue
383
+ * @returns {boolean}
384
+ */
385
+ /**
386
+ * @callback IsAsync
387
+ * @returns {boolean|undefined}
388
+ */
389
+ /**
390
+ * @callback GetTags
391
+ * @param {string} tagName
392
+ * @returns {import('comment-parser').Spec[]}
393
+ */
394
+ /**
395
+ * @callback GetPresentTags
396
+ * @param {string[]} tagList
397
+ * @returns {import('@es-joy/jsdoccomment').JsdocTagWithInline[]}
398
+ */
399
+ /**
400
+ * @callback FilterTags
401
+ * @param {(tag: import('@es-joy/jsdoccomment').JsdocTagWithInline) => boolean} filter
402
+ * @returns {import('@es-joy/jsdoccomment').JsdocTagWithInline[]}
403
+ */
404
+ /**
405
+ * @callback FilterAllTags
406
+ * @param {(tag: (import('comment-parser').Spec|
407
+ * import('@es-joy/jsdoccomment').JsdocInlineTagNoType)) => boolean} filter
408
+ * @returns {(import('comment-parser').Spec|
409
+ * import('@es-joy/jsdoccomment').JsdocInlineTagNoType)[]}
410
+ */
411
+ /**
412
+ * @callback GetTagsByType
413
+ * @param {import('comment-parser').Spec[]} tags
414
+ * @returns {{
415
+ * tagsWithNames: import('comment-parser').Spec[],
416
+ * tagsWithoutNames: import('comment-parser').Spec[]
417
+ * }}
418
+ */
419
+ /**
420
+ * @callback HasOptionTag
421
+ * @param {string} tagName
422
+ * @returns {boolean}
423
+ */
424
+ /**
425
+ * @callback GetClassNode
426
+ * @returns {Node|null}
427
+ */
428
+ /**
429
+ * @callback GetClassJsdoc
430
+ * @returns {null|JsdocBlockWithInline}
431
+ */
432
+ /**
433
+ * @callback ClassHasTag
434
+ * @param {string} tagName
435
+ * @returns {boolean}
436
+ */
437
+ /**
438
+ * @callback FindContext
439
+ * @param {Context[]} contexts
440
+ * @param {string|undefined} comment
441
+ * @returns {{
442
+ * foundContext: Context|undefined,
443
+ * contextStr: string
444
+ * }}
445
+ */
446
+ /**
447
+ * @typedef {BasicUtils & {
448
+ * isIteratingFunction: IsIteratingFunction,
449
+ * isIteratingFunctionOrVariable: IsIteratingFunction,
450
+ * isVirtualFunction: IsVirtualFunction,
451
+ * stringify: Stringify,
452
+ * reportJSDoc: ReportJSDoc,
453
+ * getRegexFromString: GetRegexFromString,
454
+ * getTagDescription: GetTagDescription,
455
+ * setTagDescription: SetTagDescription,
456
+ * getDescription: GetDescription,
457
+ * setBlockDescription: SetBlockDescription,
458
+ * setDescriptionLines: SetDescriptionLines,
459
+ * changeTag: ChangeTag,
460
+ * setTag: SetTag,
461
+ * removeTag: RemoveTag,
462
+ * addTag: AddTag,
463
+ * getFirstLine: GetFirstLine,
464
+ * seedTokens: SeedTokens,
465
+ * emptyTokens: EmptyTokens,
466
+ * addLine: AddLine,
467
+ * addLines: AddLines,
468
+ * makeMultiline: MakeMultiline,
469
+ * flattenRoots: import('./jsdocUtils.js').FlattenRoots,
470
+ * getFunctionParameterNames: GetFunctionParameterNames,
471
+ * hasParams: HasParams,
472
+ * isGenerator: IsGenerator,
473
+ * isConstructor: IsConstructor,
474
+ * getJsdocTagsDeep: GetJsdocTagsDeep,
475
+ * getPreferredTagName: GetPreferredTagName,
476
+ * isValidTag: IsValidTag,
477
+ * hasATag: HasATag,
478
+ * hasTag: HasTag,
479
+ * comparePaths: ComparePaths,
480
+ * dropPathSegmentQuotes: DropPathSegmentQuotes,
481
+ * avoidDocs: AvoidDocs,
482
+ * tagMightHaveNamePosition: TagMightHaveNamePositionTypePosition,
483
+ * tagMightHaveTypePosition: TagMightHaveNamePositionTypePosition,
484
+ * tagMustHaveNamePosition: TagMustHave,
485
+ * tagMustHaveTypePosition: TagMustHave,
486
+ * tagMissingRequiredTypeOrNamepath: TagMissingRequiredTypeOrNamepath,
487
+ * isNamepathDefiningTag: IsNamepathX,
488
+ * isNamepathReferencingTag: IsNamepathX,
489
+ * isNamepathOrUrlReferencingTag: IsNamepathX,
490
+ * tagMightHaveNamepath: IsNamepathX,
491
+ * getTagStructureForMode: GetTagStructureForMode,
492
+ * mayBeUndefinedTypeTag: MayBeUndefinedTypeTag,
493
+ * hasValueOrExecutorHasNonEmptyResolveValue: HasValueOrExecutorHasNonEmptyResolveValue,
494
+ * hasYieldValue: HasYieldValue,
495
+ * hasYieldReturnValue: HasYieldReturnValue,
496
+ * hasThrowValue: HasThrowValue,
497
+ * isAsync: IsAsync,
498
+ * getTags: GetTags,
499
+ * getPresentTags: GetPresentTags,
500
+ * filterTags: FilterTags,
501
+ * filterAllTags: FilterAllTags,
502
+ * getTagsByType: GetTagsByType,
503
+ * hasOptionTag: HasOptionTag,
504
+ * getClassNode: GetClassNode,
505
+ * getClassJsdoc: GetClassJsdoc,
506
+ * classHasTag: ClassHasTag,
507
+ * findContext: FindContext
508
+ * }} Utils
509
+ */
510
+ const { rewireSpecs, seedTokens, } = comment_parser_1.util;
511
+ // todo: Change these `any` types once importing types properly.
512
+ /**
513
+ * Should use ESLint rule's typing.
514
+ * @typedef {import('eslint').Rule.RuleMetaData} EslintRuleMeta
515
+ */
516
+ /**
517
+ * A plain object for tracking state as needed by rules across iterations.
518
+ * @typedef {{
519
+ * globalTags: {},
520
+ * hasDuplicates: {
521
+ * [key: string]: boolean
522
+ * },
523
+ * selectorMap: {
524
+ * [selector: string]: {
525
+ * [comment: string]: Integer
526
+ * }
527
+ * },
528
+ * hasTag: {
529
+ * [key: string]: boolean
530
+ * },
531
+ * hasNonComment: number,
532
+ * hasNonCommentBeforeTag: {
533
+ * [key: string]: boolean|number
534
+ * }
535
+ * }} StateObject
536
+ */
537
+ /**
538
+ * The Node AST as supplied by the parser.
539
+ * @typedef {import('eslint').Rule.Node} Node
540
+ */
541
+ /*
542
+ const {
543
+ align as commentAlign,
544
+ flow: commentFlow,
545
+ indent: commentIndent,
546
+ } = transforms;
547
+ */
548
+ const globalState = new Map();
549
+ /**
550
+ * @param {import('eslint').Rule.RuleContext} context
551
+ * @param {{
552
+ * tagNamePreference?: import('./jsdocUtils.js').TagNamePreference,
553
+ * mode?: import('./jsdocUtils.js').ParserMode
554
+ * }} cfg
555
+ * @returns {BasicUtils}
556
+ */
557
+ const getBasicUtils = (context, { mode, tagNamePreference, }) => {
558
+ /** @type {BasicUtils} */
559
+ const utils = {};
560
+ /** @type {ReportSettings} */
561
+ utils.reportSettings = (message) => {
562
+ context.report({
563
+ loc: {
564
+ end: {
565
+ column: 1,
566
+ line: 1,
567
+ },
568
+ start: {
569
+ column: 1,
570
+ line: 1,
571
+ },
572
+ },
573
+ message,
574
+ });
575
+ };
576
+ /** @type {ParseClosureTemplateTag} */
577
+ utils.parseClosureTemplateTag = (tag) => {
578
+ return jsdocUtils.parseClosureTemplateTag(tag);
579
+ };
580
+ utils.pathDoesNotBeginWith = jsdocUtils.pathDoesNotBeginWith;
581
+ /** @type {GetPreferredTagNameObject} */
582
+ utils.getPreferredTagNameObject = ({ tagName, }) => {
583
+ const ret = jsdocUtils.getPreferredTagNameSimple(tagName,
584
+ /** @type {import('./jsdocUtils.js').ParserMode} */ (mode), tagNamePreference, context);
585
+ const isObject = ret && typeof ret === 'object';
586
+ if (ret === false || (isObject && !ret.replacement)) {
587
+ return {
588
+ blocked: true,
589
+ tagName,
590
+ };
591
+ }
592
+ return ret;
593
+ };
594
+ return utils;
595
+ };
596
+ /**
597
+ * @callback Report
598
+ * @param {string} message
599
+ * @param {import('eslint').Rule.ReportFixer|null} [fix]
600
+ * @param {null|
601
+ * {line?: Integer, column?: Integer}|
602
+ * import('comment-parser').Spec & {line?: Integer}
603
+ * } [jsdocLoc]
604
+ * @param {undefined|{
605
+ * [key: string]: string
606
+ * }} [data]
607
+ * @returns {void}
608
+ */
609
+ /**
610
+ * @param {Node|null} node
611
+ * @param {JsdocBlockWithInline} jsdoc
612
+ * @param {import('eslint').AST.Token} jsdocNode
613
+ * @param {Settings} settings
614
+ * @param {Report} report
615
+ * @param {import('eslint').Rule.RuleContext} context
616
+ * @param {import('eslint').SourceCode} sc
617
+ * @param {boolean|undefined} iteratingAll
618
+ * @param {RuleConfig} ruleConfig
619
+ * @param {string} indent
620
+ * @returns {Utils}
621
+ */
622
+ const getUtils = (node, jsdoc, jsdocNode, settings, report, context, sc, iteratingAll, ruleConfig, indent) => {
623
+ const ancestors = /** @type {import('eslint').Rule.Node[]} */ (node ?
624
+ (sc.getAncestors ?
625
+ (sc.getAncestors(node)
626
+ /* c8 ignore next 5 */
627
+ ) :
628
+ (
629
+ // @ts-expect-error ESLint 8
630
+ context.getAncestors())) :
631
+ []);
632
+ /* c8 ignore next -- Fallback to deprecated method */
633
+ const { sourceCode = context.getSourceCode(), } = context;
634
+ const utils = /** @type {Utils} */ (getBasicUtils(context, settings));
635
+ const { augmentsExtendsReplacesDocs, ignoreReplacesDocs, implementsReplacesDocs, maxLines, minLines, mode, overrideReplacesDocs, tagNamePreference, } = settings;
636
+ const functionTypes = [
637
+ 'ArrowFunctionExpression',
638
+ 'FunctionDeclaration',
639
+ 'FunctionExpression',
640
+ 'MethodDefinition',
641
+ ];
642
+ /** @type {IsIteratingFunction} */
643
+ utils.isIteratingFunction = () => {
644
+ return !iteratingAll || functionTypes.includes(String(node?.type));
645
+ };
646
+ /** @type {IsIteratingFunction} */
647
+ utils.isIteratingFunctionOrVariable = () => {
648
+ if (utils.isIteratingFunction()) {
649
+ return true;
650
+ }
651
+ /** @type {import('estree').VariableDeclarator[]} */
652
+ const declarations = node?.type === 'VariableDeclaration' ?
653
+ node.declarations :
654
+ (node?.type === 'ExportNamedDeclaration' && node.declaration?.type === 'VariableDeclaration' ?
655
+ node.declaration.declarations :
656
+ []);
657
+ return declarations.some(({ init, }) => {
658
+ return functionTypes.includes(String(init?.type));
659
+ });
660
+ };
661
+ /** @type {IsVirtualFunction} */
662
+ utils.isVirtualFunction = () => {
663
+ return Boolean(iteratingAll) && utils.hasATag([
664
+ 'callback', 'function', 'func', 'method',
665
+ ]);
666
+ };
667
+ /** @type {Stringify} */
668
+ utils.stringify = (tagBlock, specRewire) => {
669
+ let block;
670
+ if (specRewire) {
671
+ block = rewireSpecs(tagBlock);
672
+ }
673
+ return (0, comment_parser_1.stringify)(/** @type {import('comment-parser').Block} */ (specRewire ? block : tagBlock));
674
+ };
675
+ /** @type {ReportJSDoc} */
676
+ utils.reportJSDoc = (msg, tag, handler, specRewire, data) => {
677
+ report(msg, handler ? /** @type {import('eslint').Rule.ReportFixer} */ (fixer) => {
678
+ handler();
679
+ const replacement = utils.stringify(jsdoc, specRewire);
680
+ if (!replacement) {
681
+ const text = sourceCode.getText();
682
+ const lastLineBreakPos = text.slice(0, jsdocNode.range[0]).search(/\n[ \t]*$/v);
683
+ if (lastLineBreakPos > -1) {
684
+ return fixer.removeRange([
685
+ lastLineBreakPos, jsdocNode.range[1],
686
+ ]);
687
+ }
688
+ return fixer.removeRange((/\s/v).test(text.charAt(jsdocNode.range[1])) ?
689
+ [
690
+ jsdocNode.range[0], jsdocNode.range[1] + 1,
691
+ ] :
692
+ jsdocNode.range);
693
+ }
694
+ return fixer.replaceText(jsdocNode, replacement);
695
+ } : null, tag, data);
696
+ };
697
+ /** @type {GetRegexFromString} */
698
+ utils.getRegexFromString = (str, requiredFlags) => {
699
+ return jsdocUtils.getRegexFromString(str, requiredFlags);
700
+ };
701
+ /** @type {GetTagDescription} */
702
+ utils.getTagDescription = (tg, returnArray) => {
703
+ return jsdocUtils.getTagDescription(tg, returnArray);
704
+ };
705
+ /** @type {SetTagDescription} */
706
+ utils.setTagDescription = (tg, matcher, setter) => {
707
+ let finalIdx = 0;
708
+ tg.source.some(({ tokens: { description, }, }, idx) => {
709
+ if (description && matcher.test(description)) {
710
+ tg.source[idx].tokens.description = setter(description);
711
+ finalIdx = idx;
712
+ return true;
713
+ }
714
+ return false;
715
+ });
716
+ return finalIdx;
717
+ };
718
+ /** @type {GetDescription} */
719
+ utils.getDescription = () => {
720
+ /** @type {string[]} */
721
+ const descriptions = [];
722
+ let lastDescriptionLine = 0;
723
+ let tagsBegun = false;
724
+ jsdoc.source.some(({ tokens: { description, end, tag, }, }, idx) => {
725
+ if (tag) {
726
+ tagsBegun = true;
727
+ }
728
+ if (idx && (tag || end)) {
729
+ lastDescriptionLine = idx - 1;
730
+ if (!tagsBegun && description) {
731
+ descriptions.push(description);
732
+ }
733
+ return true;
734
+ }
735
+ if (!tagsBegun && (idx || description)) {
736
+ descriptions.push(description || (descriptions.length ? '' : '\n'));
737
+ }
738
+ return false;
739
+ });
740
+ return {
741
+ description: descriptions.join('\n'),
742
+ descriptions,
743
+ lastDescriptionLine,
744
+ };
745
+ };
746
+ /** @type {SetBlockDescription} */
747
+ utils.setBlockDescription = (setter) => {
748
+ /** @type {string[]} */
749
+ const descLines = [];
750
+ /**
751
+ * @type {undefined|Integer}
752
+ */
753
+ let startIdx;
754
+ /**
755
+ * @type {undefined|Integer}
756
+ */
757
+ let endIdx;
758
+ /**
759
+ * @type {undefined|{
760
+ * delimiter: string,
761
+ * postDelimiter: string,
762
+ * start: string
763
+ * }}
764
+ */
765
+ let info;
766
+ jsdoc.source.some(({ tokens: { delimiter, description, end, postDelimiter, start, tag, }, }, idx) => {
767
+ if (delimiter === '/**') {
768
+ return false;
769
+ }
770
+ if (startIdx === undefined) {
771
+ startIdx = idx;
772
+ info = {
773
+ delimiter,
774
+ postDelimiter,
775
+ start,
776
+ };
777
+ }
778
+ if (tag || end) {
779
+ endIdx = idx;
780
+ return true;
781
+ }
782
+ descLines.push(description);
783
+ return false;
784
+ });
785
+ /* c8 ignore else -- Won't be called if missing */
786
+ if (descLines.length) {
787
+ jsdoc.source.splice(
788
+ /** @type {Integer} */ (startIdx),
789
+ /** @type {Integer} */ (endIdx) - /** @type {Integer} */ (startIdx), ...setter(
790
+ /**
791
+ * @type {{
792
+ * delimiter: string,
793
+ * postDelimiter: string,
794
+ * start: string
795
+ * }}
796
+ */
797
+ (info), seedTokens, descLines));
798
+ }
799
+ };
800
+ /** @type {SetDescriptionLines} */
801
+ utils.setDescriptionLines = (matcher, setter) => {
802
+ let finalIdx = 0;
803
+ jsdoc.source.some(({ tokens: { description, end, tag, }, }, idx) => {
804
+ /* c8 ignore next 3 -- Already checked */
805
+ if (idx && (tag || end)) {
806
+ return true;
807
+ }
808
+ if (description && matcher.test(description)) {
809
+ jsdoc.source[idx].tokens.description = setter(description);
810
+ finalIdx = idx;
811
+ return true;
812
+ }
813
+ return false;
814
+ });
815
+ return finalIdx;
816
+ };
817
+ /** @type {ChangeTag} */
818
+ utils.changeTag = (tag, ...tokens) => {
819
+ for (const [idx, src,] of tag.source.entries()) {
820
+ src.tokens = {
821
+ ...src.tokens,
822
+ ...tokens[idx],
823
+ };
824
+ }
825
+ };
826
+ /** @type {SetTag} */
827
+ utils.setTag = (tag, tokens) => {
828
+ tag.source = [
829
+ {
830
+ number: tag.line,
831
+ // Or tag.source[0].number?
832
+ source: '',
833
+ tokens: seedTokens({
834
+ delimiter: '*',
835
+ postDelimiter: ' ',
836
+ start: indent + ' ',
837
+ tag: '@' + tag.tag,
838
+ ...tokens,
839
+ }),
840
+ },
841
+ ];
842
+ };
843
+ /** @type {RemoveTag} */
844
+ utils.removeTag = (tagIndex, { removeEmptyBlock = false, tagSourceOffset = 0, } = {}) => {
845
+ const { source: tagSource, } = jsdoc.tags[tagIndex];
846
+ /** @type {Integer|undefined} */
847
+ let lastIndex;
848
+ const firstNumber = jsdoc.source[0].number;
849
+ tagSource.some(({ number, }, tagIdx) => {
850
+ const sourceIndex = jsdoc.source.findIndex(({ number: srcNumber, }) => {
851
+ return number === srcNumber;
852
+ });
853
+ // c8 ignore else
854
+ if (sourceIndex > -1) {
855
+ let spliceCount = 1;
856
+ tagSource.slice(tagIdx + 1).some(({ tokens: { end: ending, tag, }, }) => {
857
+ if (!tag && !ending) {
858
+ spliceCount++;
859
+ return false;
860
+ }
861
+ return true;
862
+ });
863
+ const spliceIdx = sourceIndex + tagSourceOffset;
864
+ const { delimiter, end, } = jsdoc.source[spliceIdx].tokens;
865
+ if (spliceIdx === 0 && jsdoc.tags.length >= 2 ||
866
+ !removeEmptyBlock && (end || delimiter === '/**')) {
867
+ const { tokens, } = jsdoc.source[spliceIdx];
868
+ for (const item of [
869
+ 'postDelimiter',
870
+ 'tag',
871
+ 'postTag',
872
+ 'type',
873
+ 'postType',
874
+ 'name',
875
+ 'postName',
876
+ 'description',
877
+ ]) {
878
+ tokens[
879
+ /**
880
+ * @type {"postDelimiter"|"tag"|"type"|"postType"|
881
+ * "postTag"|"name"|"postName"|"description"}
882
+ */ (item)] = '';
883
+ }
884
+ }
885
+ else {
886
+ jsdoc.source.splice(spliceIdx, spliceCount - tagSourceOffset + (spliceIdx ? 0 : jsdoc.source.length));
887
+ tagSource.splice(tagIdx + tagSourceOffset, spliceCount - tagSourceOffset + (spliceIdx ? 0 : jsdoc.source.length));
888
+ }
889
+ lastIndex = sourceIndex;
890
+ return true;
891
+ }
892
+ /* c8 ignore next 2 */
893
+ // eslint-disable-next-line @stylistic/padding-line-between-statements -- c8
894
+ return false;
895
+ });
896
+ for (const [idx, src,] of jsdoc.source.slice(lastIndex).entries()) {
897
+ src.number = firstNumber + /** @type {Integer} */ (lastIndex) + idx;
898
+ }
899
+ // Todo: Once rewiring of tags may be fixed in comment-parser to reflect
900
+ // missing tags, this step should be added here (so that, e.g.,
901
+ // if accessing `jsdoc.tags`, such as to add a new tag, the
902
+ // correct information will be available)
903
+ };
904
+ /** @type {AddTag} */
905
+ utils.addTag = (targetTagName, number = (jsdoc.tags[jsdoc.tags.length - 1]?.source[0]?.number ?? jsdoc.source.findIndex(({ tokens: { tag, }, }) => {
906
+ return tag;
907
+ }) - 1) + 1, tokens = {}) => {
908
+ jsdoc.source.splice(number, 0, {
909
+ number,
910
+ source: '',
911
+ tokens: seedTokens({
912
+ delimiter: '*',
913
+ postDelimiter: ' ',
914
+ start: indent + ' ',
915
+ tag: `@${targetTagName}`,
916
+ ...tokens,
917
+ }),
918
+ });
919
+ for (const src of jsdoc.source.slice(number + 1)) {
920
+ src.number++;
921
+ }
922
+ };
923
+ /** @type {GetFirstLine} */
924
+ utils.getFirstLine = () => {
925
+ let firstLine;
926
+ for (const { number, tokens: { tag, }, } of jsdoc.source) {
927
+ if (tag) {
928
+ firstLine = number;
929
+ break;
930
+ }
931
+ }
932
+ return firstLine;
933
+ };
934
+ /** @type {SeedTokens} */
935
+ utils.seedTokens = seedTokens;
936
+ /** @type {EmptyTokens} */
937
+ utils.emptyTokens = (tokens) => {
938
+ for (const prop of [
939
+ 'start',
940
+ 'postDelimiter',
941
+ 'tag',
942
+ 'type',
943
+ 'postType',
944
+ 'postTag',
945
+ 'name',
946
+ 'postName',
947
+ 'description',
948
+ 'end',
949
+ 'lineEnd',
950
+ ]) {
951
+ tokens[
952
+ /**
953
+ * @type {"start"|"postDelimiter"|"tag"|"type"|"postType"|
954
+ * "postTag"|"name"|"postName"|"description"|"end"|"lineEnd"}
955
+ */ (prop)] = '';
956
+ }
957
+ };
958
+ /** @type {AddLine} */
959
+ utils.addLine = (sourceIndex, tokens) => {
960
+ const number = (jsdoc.source[sourceIndex - 1]?.number || 0) + 1;
961
+ jsdoc.source.splice(sourceIndex, 0, {
962
+ number,
963
+ source: '',
964
+ tokens: seedTokens(tokens),
965
+ });
966
+ for (const src of jsdoc.source.slice(number + 1)) {
967
+ src.number++;
968
+ }
969
+ // If necessary, we can rewire the tags (misnamed method)
970
+ // rewireSource(jsdoc);
971
+ };
972
+ /** @type {AddLines} */
973
+ utils.addLines = (tagIndex, tagSourceOffset, numLines) => {
974
+ const { source: tagSource, } = jsdoc.tags[tagIndex];
975
+ /** @type {Integer|undefined} */
976
+ let lastIndex;
977
+ const firstNumber = jsdoc.source[0].number;
978
+ tagSource.some(({ number, }) => {
979
+ const makeLine = () => {
980
+ return {
981
+ number,
982
+ source: '',
983
+ tokens: seedTokens({
984
+ delimiter: '*',
985
+ start: indent + ' ',
986
+ }),
987
+ };
988
+ };
989
+ const makeLines = () => {
990
+ return Array.from({
991
+ length: numLines,
992
+ }, makeLine);
993
+ };
994
+ const sourceIndex = jsdoc.source.findIndex(({ number: srcNumber, tokens: { end, }, }) => {
995
+ return number === srcNumber && !end;
996
+ });
997
+ // c8 ignore else
998
+ if (sourceIndex > -1) {
999
+ const lines = makeLines();
1000
+ jsdoc.source.splice(sourceIndex + tagSourceOffset, 0, ...lines);
1001
+ // tagSource.splice(tagIdx + 1, 0, ...makeLines());
1002
+ lastIndex = sourceIndex;
1003
+ return true;
1004
+ }
1005
+ /* c8 ignore next 2 */
1006
+ // eslint-disable-next-line @stylistic/padding-line-between-statements -- c8
1007
+ return false;
1008
+ });
1009
+ for (const [idx, src,] of jsdoc.source.slice(lastIndex).entries()) {
1010
+ src.number = firstNumber + /** @type {Integer} */ (lastIndex) + idx;
1011
+ }
1012
+ };
1013
+ /** @type {MakeMultiline} */
1014
+ utils.makeMultiline = () => {
1015
+ const { source: [{ tokens, },], } = jsdoc;
1016
+ const { description, lineEnd, name, postDelimiter, tag, type, } = tokens;
1017
+ let { tokens: { postName, postTag, postType, }, } = jsdoc.source[0];
1018
+ // Strip trailing leftovers from single line ending
1019
+ if (!description) {
1020
+ if (postName) {
1021
+ postName = '';
1022
+ }
1023
+ else if (postType) {
1024
+ postType = '';
1025
+ }
1026
+ else /* c8 ignore else -- `comment-parser` prevents empty blocks currently per https://github.com/syavorsky/comment-parser/issues/128 */ if (postTag) {
1027
+ postTag = '';
1028
+ }
1029
+ }
1030
+ utils.emptyTokens(tokens);
1031
+ utils.addLine(1, {
1032
+ delimiter: '*',
1033
+ // If a description were present, it may have whitespace attached
1034
+ // due to being at the end of the single line
1035
+ description: description.trimEnd(),
1036
+ name,
1037
+ postDelimiter,
1038
+ postName,
1039
+ postTag,
1040
+ postType,
1041
+ start: indent + ' ',
1042
+ tag,
1043
+ type,
1044
+ });
1045
+ utils.addLine(2, {
1046
+ end: '*/',
1047
+ lineEnd,
1048
+ start: indent + ' ',
1049
+ });
1050
+ };
1051
+ /**
1052
+ * @type {import('./jsdocUtils.js').FlattenRoots}
1053
+ */
1054
+ utils.flattenRoots = jsdocUtils.flattenRoots;
1055
+ /** @type {GetFunctionParameterNames} */
1056
+ utils.getFunctionParameterNames = (useDefaultObjectProperties) => {
1057
+ return jsdocUtils.getFunctionParameterNames(node, useDefaultObjectProperties);
1058
+ };
1059
+ /** @type {HasParams} */
1060
+ utils.hasParams = () => {
1061
+ return jsdocUtils.hasParams(/** @type {Node} */ (node));
1062
+ };
1063
+ /** @type {IsGenerator} */
1064
+ utils.isGenerator = () => {
1065
+ return node !== null && Boolean(
1066
+ /**
1067
+ * @type {import('estree').FunctionDeclaration|
1068
+ * import('estree').FunctionExpression}
1069
+ */ (node).generator ||
1070
+ node.type === 'MethodDefinition' && node.value.generator ||
1071
+ [
1072
+ 'ExportDefaultDeclaration', 'ExportNamedDeclaration',
1073
+ ].includes(node.type) &&
1074
+ /** @type {import('estree').FunctionDeclaration} */
1075
+ (
1076
+ /**
1077
+ * @type {import('estree').ExportNamedDeclaration|
1078
+ * import('estree').ExportDefaultDeclaration}
1079
+ */ (node).declaration)?.generator);
1080
+ };
1081
+ /** @type {IsConstructor} */
1082
+ utils.isConstructor = () => {
1083
+ return jsdocUtils.isConstructor(/** @type {Node} */ (node));
1084
+ };
1085
+ /** @type {GetJsdocTagsDeep} */
1086
+ utils.getJsdocTagsDeep = (tagName) => {
1087
+ const name = /** @type {string|false} */ (utils.getPreferredTagName({
1088
+ tagName,
1089
+ }));
1090
+ if (!name) {
1091
+ return false;
1092
+ }
1093
+ return jsdocUtils.getJsdocTagsDeep(jsdoc, name);
1094
+ };
1095
+ /** @type {GetPreferredTagName} */
1096
+ utils.getPreferredTagName = (args) => {
1097
+ return jsdocUtils.getPreferredTagName(jsdoc, {
1098
+ ...args,
1099
+ context,
1100
+ mode,
1101
+ report,
1102
+ tagNamePreference,
1103
+ });
1104
+ };
1105
+ /** @type {IsValidTag} */
1106
+ utils.isValidTag = (name, definedTags) => {
1107
+ return jsdocUtils.isValidTag(context, mode, name, definedTags);
1108
+ };
1109
+ /** @type {HasATag} */
1110
+ utils.hasATag = (names) => {
1111
+ return jsdocUtils.hasATag(jsdoc, names);
1112
+ };
1113
+ /** @type {HasTag} */
1114
+ utils.hasTag = (name) => {
1115
+ return jsdocUtils.hasTag(jsdoc, name);
1116
+ };
1117
+ /** @type {ComparePaths} */
1118
+ utils.comparePaths = (name) => {
1119
+ return jsdocUtils.comparePaths(name);
1120
+ };
1121
+ /** @type {DropPathSegmentQuotes} */
1122
+ utils.dropPathSegmentQuotes = (name) => {
1123
+ return jsdocUtils.dropPathSegmentQuotes(name);
1124
+ };
1125
+ /** @type {AvoidDocs} */
1126
+ utils.avoidDocs = () => {
1127
+ if (ignoreReplacesDocs !== false &&
1128
+ (utils.hasTag('ignore') || utils.classHasTag('ignore')) ||
1129
+ overrideReplacesDocs !== false &&
1130
+ (utils.hasTag('override') || utils.classHasTag('override')) ||
1131
+ implementsReplacesDocs !== false &&
1132
+ (utils.hasTag('implements') || utils.classHasTag('implements')) ||
1133
+ augmentsExtendsReplacesDocs &&
1134
+ (utils.hasATag([
1135
+ 'augments', 'extends',
1136
+ ]) ||
1137
+ utils.classHasTag('augments') ||
1138
+ utils.classHasTag('extends'))) {
1139
+ return true;
1140
+ }
1141
+ if (jsdocUtils.exemptSpeciaMethods(jsdoc, node, context,
1142
+ /** @type {import('json-schema').JSONSchema4|import('json-schema').JSONSchema4[]} */ (ruleConfig.meta.schema))) {
1143
+ return true;
1144
+ }
1145
+ const exemptedBy = context.options[0]?.exemptedBy ?? [
1146
+ 'inheritDoc',
1147
+ ...mode === 'closure' ? [] : [
1148
+ 'inheritdoc',
1149
+ ],
1150
+ ];
1151
+ if (exemptedBy.length && utils.getPresentTags(exemptedBy).length) {
1152
+ return true;
1153
+ }
1154
+ return false;
1155
+ };
1156
+ for (const method of [
1157
+ 'tagMightHaveNamePosition',
1158
+ 'tagMightHaveTypePosition',
1159
+ ]) {
1160
+ /** @type {TagMightHaveNamePositionTypePosition} */
1161
+ utils[
1162
+ /** @type {"tagMightHaveNamePosition"|"tagMightHaveTypePosition"} */ (method)] = (tagName, otherModeMaps) => {
1163
+ const result = jsdocUtils[
1164
+ /** @type {"tagMightHaveNamePosition"|"tagMightHaveTypePosition"} */
1165
+ (method)](tagName);
1166
+ if (result) {
1167
+ return true;
1168
+ }
1169
+ if (!otherModeMaps) {
1170
+ return false;
1171
+ }
1172
+ const otherResult = otherModeMaps.some((otherModeMap) => {
1173
+ return jsdocUtils[
1174
+ /** @type {"tagMightHaveNamePosition"|"tagMightHaveTypePosition"} */
1175
+ (method)](tagName, otherModeMap);
1176
+ });
1177
+ return otherResult ? {
1178
+ otherMode: true,
1179
+ } : false;
1180
+ };
1181
+ }
1182
+ /** @type {TagMissingRequiredTypeOrNamepath} */
1183
+ utils.tagMissingRequiredTypeOrNamepath = (tagName, otherModeMaps) => {
1184
+ const result = jsdocUtils.tagMissingRequiredTypeOrNamepath(tagName);
1185
+ if (!result) {
1186
+ return false;
1187
+ }
1188
+ const otherResult = otherModeMaps.every((otherModeMap) => {
1189
+ return jsdocUtils.tagMissingRequiredTypeOrNamepath(tagName, otherModeMap);
1190
+ });
1191
+ return otherResult ? true : {
1192
+ otherMode: false,
1193
+ };
1194
+ };
1195
+ for (const method of [
1196
+ 'tagMustHaveNamePosition',
1197
+ 'tagMustHaveTypePosition',
1198
+ ]) {
1199
+ /** @type {TagMustHave} */
1200
+ utils[
1201
+ /** @type {"tagMustHaveNamePosition"|"tagMustHaveTypePosition"} */
1202
+ (method)] = (tagName, otherModeMaps) => {
1203
+ const result = jsdocUtils[
1204
+ /** @type {"tagMustHaveNamePosition"|"tagMustHaveTypePosition"} */
1205
+ (method)](tagName);
1206
+ if (!result) {
1207
+ return false;
1208
+ }
1209
+ // if (!otherModeMaps) { return true; }
1210
+ const otherResult = otherModeMaps.every((otherModeMap) => {
1211
+ return jsdocUtils[
1212
+ /** @type {"tagMustHaveNamePosition"|"tagMustHaveTypePosition"} */
1213
+ (method)](tagName, otherModeMap);
1214
+ });
1215
+ return otherResult ? true : {
1216
+ otherMode: false,
1217
+ };
1218
+ };
1219
+ }
1220
+ for (const method of [
1221
+ 'isNamepathDefiningTag',
1222
+ 'isNamepathReferencingTag',
1223
+ 'isNamepathOrUrlReferencingTag',
1224
+ 'tagMightHaveNamepath',
1225
+ ]) {
1226
+ /** @type {IsNamepathX} */
1227
+ utils[
1228
+ /** @type {"isNamepathDefiningTag"|"isNamepathReferencingTag"|"isNamepathOrUrlReferencingTag"|"tagMightHaveNamepath"} */ (method)] = (tagName) => {
1229
+ return jsdocUtils[
1230
+ /** @type {"isNamepathDefiningTag"|"isNamepathReferencingTag"|"isNamepathOrUrlReferencingTag"|"tagMightHaveNamepath"} */
1231
+ (method)](tagName);
1232
+ };
1233
+ }
1234
+ /** @type {GetTagStructureForMode} */
1235
+ utils.getTagStructureForMode = (mde) => {
1236
+ return jsdocUtils.getTagStructureForMode(mde, settings.structuredTags);
1237
+ };
1238
+ /** @type {MayBeUndefinedTypeTag} */
1239
+ utils.mayBeUndefinedTypeTag = (tag) => {
1240
+ return jsdocUtils.mayBeUndefinedTypeTag(tag, settings.mode);
1241
+ };
1242
+ /** @type {HasValueOrExecutorHasNonEmptyResolveValue} */
1243
+ utils.hasValueOrExecutorHasNonEmptyResolveValue = (anyPromiseAsReturn, allBranches) => {
1244
+ return jsdocUtils.hasValueOrExecutorHasNonEmptyResolveValue(
1245
+ /** @type {Node} */ (node), anyPromiseAsReturn, allBranches);
1246
+ };
1247
+ /** @type {HasYieldValue} */
1248
+ utils.hasYieldValue = () => {
1249
+ if ([
1250
+ 'ExportDefaultDeclaration', 'ExportNamedDeclaration',
1251
+ ].includes(/** @type {Node} */ (node).type)) {
1252
+ return jsdocUtils.hasYieldValue(
1253
+ /** @type {import('estree').Declaration|import('estree').Expression} */ (
1254
+ /** @type {import('estree').ExportNamedDeclaration|import('estree').ExportDefaultDeclaration} */
1255
+ (node).declaration));
1256
+ }
1257
+ return jsdocUtils.hasYieldValue(/** @type {Node} */ (node));
1258
+ };
1259
+ /** @type {HasYieldReturnValue} */
1260
+ utils.hasYieldReturnValue = () => {
1261
+ return jsdocUtils.hasYieldValue(/** @type {Node} */ (node), true);
1262
+ };
1263
+ /** @type {HasThrowValue} */
1264
+ utils.hasThrowValue = () => {
1265
+ return jsdocUtils.hasThrowValue(node);
1266
+ };
1267
+ /** @type {IsAsync} */
1268
+ utils.isAsync = () => {
1269
+ return Boolean(node && 'async' in node && node.async);
1270
+ };
1271
+ /** @type {GetTags} */
1272
+ utils.getTags = (tagName) => {
1273
+ return jsdocUtils.getTags(jsdoc, tagName);
1274
+ };
1275
+ /** @type {GetPresentTags} */
1276
+ utils.getPresentTags = (tagList) => {
1277
+ return jsdocUtils.filterTags(jsdoc, (tag) => {
1278
+ return tagList.includes(tag.tag);
1279
+ });
1280
+ };
1281
+ /** @type {FilterTags} */
1282
+ utils.filterTags = (filter) => {
1283
+ return jsdocUtils.filterTags(jsdoc, (tag) => {
1284
+ return filter(tag);
1285
+ });
1286
+ };
1287
+ /** @type {FilterAllTags} */
1288
+ utils.filterAllTags = (filter) => {
1289
+ const tags = jsdocUtils.getAllTags(jsdoc);
1290
+ return tags.filter((tag) => {
1291
+ return filter(tag);
1292
+ });
1293
+ };
1294
+ /** @type {GetTagsByType} */
1295
+ utils.getTagsByType = (tags) => {
1296
+ return jsdocUtils.getTagsByType(context, mode, tags);
1297
+ };
1298
+ /** @type {HasOptionTag} */
1299
+ utils.hasOptionTag = (tagName) => {
1300
+ const { tags, } = context.options[0] ?? {};
1301
+ return Boolean(tags && tags.includes(tagName));
1302
+ };
1303
+ /** @type {GetClassNode} */
1304
+ utils.getClassNode = () => {
1305
+ // eslint-disable-next-line canonical/no-use-extend-native -- Not extending
1306
+ return [
1307
+ ...ancestors, node,
1308
+ ].toReversed().find((parent) => {
1309
+ return parent && [
1310
+ 'ClassDeclaration', 'ClassExpression',
1311
+ ].includes(parent.type);
1312
+ }) ?? null;
1313
+ };
1314
+ /** @type {GetClassJsdoc} */
1315
+ utils.getClassJsdoc = () => {
1316
+ const classNode = utils.getClassNode();
1317
+ if (!classNode) {
1318
+ return null;
1319
+ }
1320
+ const classJsdocNode = (0, jsdoccomment_1.getJSDocComment)(sourceCode, classNode, {
1321
+ maxLines,
1322
+ minLines,
1323
+ });
1324
+ if (classJsdocNode) {
1325
+ return (0, jsdoccomment_1.parseComment)(classJsdocNode, '');
1326
+ }
1327
+ return null;
1328
+ };
1329
+ /** @type {ClassHasTag} */
1330
+ utils.classHasTag = (tagName) => {
1331
+ const classJsdoc = utils.getClassJsdoc();
1332
+ return classJsdoc !== null && jsdocUtils.hasTag(classJsdoc, tagName);
1333
+ };
1334
+ /** @type {ForEachPreferredTag} */
1335
+ utils.forEachPreferredTag = (tagName, arrayHandler, skipReportingBlockedTag) => {
1336
+ return jsdocUtils.forEachPreferredTag(jsdoc, tagName, arrayHandler, {
1337
+ context,
1338
+ mode,
1339
+ report,
1340
+ skipReportingBlockedTag,
1341
+ tagNamePreference,
1342
+ });
1343
+ };
1344
+ /** @type {FindContext} */
1345
+ utils.findContext = (contexts, comment) => {
1346
+ const foundContext = contexts.find((cntxt) => {
1347
+ return typeof cntxt === 'string' ?
1348
+ esquery_1.default.matches(
1349
+ /** @type {Node} */ (node), esquery_1.default.parse(cntxt), undefined, {
1350
+ visitorKeys: sourceCode.visitorKeys,
1351
+ }) :
1352
+ (!cntxt.context || cntxt.context === 'any' ||
1353
+ esquery_1.default.matches(
1354
+ /** @type {Node} */ (node), esquery_1.default.parse(cntxt.context), undefined, {
1355
+ visitorKeys: sourceCode.visitorKeys,
1356
+ })) && comment === cntxt.comment;
1357
+ });
1358
+ const contextStr = typeof foundContext === 'object' ?
1359
+ foundContext.context ?? 'any' :
1360
+ String(foundContext);
1361
+ return {
1362
+ contextStr,
1363
+ foundContext,
1364
+ };
1365
+ };
1366
+ return utils;
1367
+ };
1368
+ /**
1369
+ * @typedef {{
1370
+ * [key: string]: false|string|{
1371
+ * message: string,
1372
+ * replacement?: false|string
1373
+ * skipRootChecking?: boolean
1374
+ * }
1375
+ * }} PreferredTypes
1376
+ */
1377
+ /**
1378
+ * @typedef {{
1379
+ * [key: string]: {
1380
+ * name?: "text"|"namepath-defining"|"namepath-referencing"|false,
1381
+ * type?: boolean|string[],
1382
+ * required?: ("name"|"type"|"typeOrNameRequired")[]
1383
+ * }
1384
+ * }} StructuredTags
1385
+ */
1386
+ /**
1387
+ * Settings from ESLint types.
1388
+ * @typedef {{
1389
+ * maxLines: Integer,
1390
+ * minLines: Integer,
1391
+ * tagNamePreference: import('./jsdocUtils.js').TagNamePreference,
1392
+ * mode: import('./jsdocUtils.js').ParserMode,
1393
+ * preferredTypes: PreferredTypes,
1394
+ * structuredTags: StructuredTags,
1395
+ * [name: string]: any,
1396
+ * contexts?: Context[]
1397
+ * }} Settings
1398
+ */
1399
+ /**
1400
+ * @typedef {{
1401
+ * settings?: {
1402
+ * jsdoc?: {
1403
+ * ignorePrivate: boolean,
1404
+ * ignoreInternal: boolean,
1405
+ * maxLines: Integer,
1406
+ * minLines: Integer,
1407
+ * tagNamePreference: import('./jsdocUtils.js').TagNamePreference,
1408
+ * preferredTypes: PreferredTypes,
1409
+ * structuredTags: StructuredTags,
1410
+ * overrideReplacesDocs: boolean,
1411
+ * ignoreReplacesDocs: boolean,
1412
+ * implementsReplacesDocs: boolean,
1413
+ * augmentsExtendsReplacesDocs: boolean,
1414
+ * exemptDestructuredRootsFromChecks: boolean,
1415
+ * mode: import('./jsdocUtils.js').ParserMode,
1416
+ * contexts: Context[],
1417
+ * }
1418
+ * }
1419
+ * }} JSDocSettings
1420
+ */
1421
+ /**
1422
+ * @param {import('eslint').Rule.RuleContext & JSDocSettings} context
1423
+ * @returns {Settings|false}
1424
+ */
1425
+ const getSettings = (context) => {
1426
+ /* eslint-disable perfectionist/sort-objects */
1427
+ const settings = {
1428
+ // All rules
1429
+ ignorePrivate: Boolean(context.settings.jsdoc?.ignorePrivate),
1430
+ ignoreInternal: Boolean(context.settings.jsdoc?.ignoreInternal),
1431
+ maxLines: Number(context.settings.jsdoc?.maxLines ?? 1),
1432
+ minLines: Number(context.settings.jsdoc?.minLines ?? 0),
1433
+ // `check-tag-names` and many returns/param rules
1434
+ tagNamePreference: context.settings.jsdoc?.tagNamePreference ?? {},
1435
+ // `check-types` and `no-undefined-types`
1436
+ preferredTypes: context.settings.jsdoc?.preferredTypes ?? {},
1437
+ // `check-types`, `no-undefined-types`, `valid-types`
1438
+ structuredTags: context.settings.jsdoc?.structuredTags ?? {},
1439
+ // `require-param`, `require-description`, `require-example`,
1440
+ // `require-returns`, `require-throw`, `require-yields`
1441
+ overrideReplacesDocs: context.settings.jsdoc?.overrideReplacesDocs,
1442
+ ignoreReplacesDocs: context.settings.jsdoc?.ignoreReplacesDocs,
1443
+ implementsReplacesDocs: context.settings.jsdoc?.implementsReplacesDocs,
1444
+ augmentsExtendsReplacesDocs: context.settings.jsdoc?.augmentsExtendsReplacesDocs,
1445
+ // `require-param-type`, `require-param-description`
1446
+ exemptDestructuredRootsFromChecks: context.settings.jsdoc?.exemptDestructuredRootsFromChecks,
1447
+ // Many rules, e.g., `check-tag-names`
1448
+ mode: context.settings.jsdoc?.mode ?? 'typescript',
1449
+ // Many rules
1450
+ contexts: context.settings.jsdoc?.contexts,
1451
+ };
1452
+ /* eslint-enable perfectionist/sort-objects */
1453
+ jsdocUtils.setTagStructure(settings.mode);
1454
+ try {
1455
+ jsdocUtils.overrideTagStructure(settings.structuredTags);
1456
+ }
1457
+ catch (error) {
1458
+ context.report({
1459
+ loc: {
1460
+ end: {
1461
+ column: 1,
1462
+ line: 1,
1463
+ },
1464
+ start: {
1465
+ column: 1,
1466
+ line: 1,
1467
+ },
1468
+ },
1469
+ message: /** @type {Error} */ (error).message,
1470
+ });
1471
+ return false;
1472
+ }
1473
+ return settings;
1474
+ };
1475
+ exports.getSettings = getSettings;
1476
+ /**
1477
+ * Create the report function
1478
+ * @callback MakeReport
1479
+ * @param {import('eslint').Rule.RuleContext} context
1480
+ * @param {import('estree').Node} commentNode
1481
+ * @returns {Report}
1482
+ */
1483
+ /** @type {MakeReport} */
1484
+ const makeReport = (context, commentNode) => {
1485
+ /** @type {Report} */
1486
+ const report = (message, fix = null, jsdocLoc = null, data = undefined) => {
1487
+ let loc;
1488
+ if (jsdocLoc) {
1489
+ if (!('line' in jsdocLoc)) {
1490
+ jsdocLoc.line = /** @type {import('comment-parser').Spec & {line?: Integer}} */ (jsdocLoc).source[0].number;
1491
+ }
1492
+ const lineNumber = /** @type {import('eslint').AST.SourceLocation} */ (commentNode.loc).start.line +
1493
+ /** @type {Integer} */ (jsdocLoc.line);
1494
+ loc = {
1495
+ end: {
1496
+ column: 0,
1497
+ line: lineNumber,
1498
+ },
1499
+ start: {
1500
+ column: 0,
1501
+ line: lineNumber,
1502
+ },
1503
+ };
1504
+ if ('column' in jsdocLoc && typeof jsdocLoc.column === 'number') {
1505
+ const colNumber = /** @type {import('eslint').AST.SourceLocation} */ (commentNode.loc).start.column + jsdocLoc.column;
1506
+ loc.end.column = colNumber;
1507
+ loc.start.column = colNumber;
1508
+ }
1509
+ }
1510
+ context.report({
1511
+ data,
1512
+ fix,
1513
+ loc,
1514
+ message,
1515
+ node: commentNode,
1516
+ });
1517
+ };
1518
+ return report;
1519
+ };
1520
+ /**
1521
+ * @typedef {(
1522
+ * arg: {
1523
+ * context: import('eslint').Rule.RuleContext,
1524
+ * sourceCode: import('eslint').SourceCode,
1525
+ * indent?: string,
1526
+ * info?: {
1527
+ * comment?: string|undefined,
1528
+ * lastIndex?: Integer|undefined
1529
+ * },
1530
+ * state?: StateObject,
1531
+ * globalState?: Map<string, Map<string, string>>,
1532
+ * jsdoc?: JsdocBlockWithInline,
1533
+ * jsdocNode?: import('eslint').Rule.Node & {
1534
+ * range: [number, number]
1535
+ * },
1536
+ * node?: Node,
1537
+ * allComments?: import('estree').Node[]
1538
+ * report?: Report,
1539
+ * makeReport?: MakeReport,
1540
+ * settings: Settings,
1541
+ * utils: BasicUtils,
1542
+ * }
1543
+ * ) => any } JsdocVisitorBasic
1544
+ */
1545
+ /**
1546
+ * @typedef {(
1547
+ * arg: {
1548
+ * context: import('eslint').Rule.RuleContext,
1549
+ * sourceCode: import('eslint').SourceCode,
1550
+ * indent: string,
1551
+ * info: {
1552
+ * comment?: string|undefined,
1553
+ * lastIndex?: Integer|undefined
1554
+ * },
1555
+ * state: StateObject,
1556
+ * globalState: Map<string, Map<string, string>>,
1557
+ * jsdoc: JsdocBlockWithInline,
1558
+ * jsdocNode: import('eslint').Rule.Node & {
1559
+ * range: [number, number]
1560
+ * },
1561
+ * node: Node|null,
1562
+ * allComments?: import('estree').Node[]
1563
+ * report: Report,
1564
+ * makeReport?: MakeReport,
1565
+ * settings: Settings,
1566
+ * utils: Utils,
1567
+ * }
1568
+ * ) => any } JsdocVisitor
1569
+ */
1570
+ /**
1571
+ * @param {{
1572
+ * comment?: string,
1573
+ * lastIndex?: Integer,
1574
+ * selector?: string,
1575
+ * isFunctionContext?: boolean,
1576
+ * }} info
1577
+ * @param {string} indent
1578
+ * @param {JsdocBlockWithInline} jsdoc
1579
+ * @param {RuleConfig} ruleConfig
1580
+ * @param {import('eslint').Rule.RuleContext} context
1581
+ * @param {import('@es-joy/jsdoccomment').Token} jsdocNode
1582
+ * @param {Node|null} node
1583
+ * @param {Settings} settings
1584
+ * @param {import('eslint').SourceCode} sourceCode
1585
+ * @param {JsdocVisitor} iterator
1586
+ * @param {StateObject} state
1587
+ * @param {boolean} [iteratingAll]
1588
+ * @returns {void}
1589
+ */
1590
+ const iterate = (info, indent, jsdoc, ruleConfig, context, jsdocNode, node, settings, sourceCode, iterator, state, iteratingAll) => {
1591
+ const jsdocNde = /** @type {unknown} */ (jsdocNode);
1592
+ const report = makeReport(context,
1593
+ /** @type {import('estree').Node} */
1594
+ (jsdocNde));
1595
+ const utils = getUtils(node, jsdoc,
1596
+ /** @type {import('eslint').AST.Token} */
1597
+ (jsdocNode), settings, report, context, sourceCode, iteratingAll, ruleConfig, indent);
1598
+ if (!ruleConfig.checkInternal && settings.ignoreInternal &&
1599
+ utils.hasTag('internal')) {
1600
+ return;
1601
+ }
1602
+ if (!ruleConfig.checkPrivate && settings.ignorePrivate &&
1603
+ (utils.hasTag('private') ||
1604
+ jsdocUtils
1605
+ .filterTags(jsdoc, ({ tag, }) => {
1606
+ return tag === 'access';
1607
+ })
1608
+ .some(({ description, }) => {
1609
+ return description === 'private';
1610
+ }))) {
1611
+ return;
1612
+ }
1613
+ iterator({
1614
+ context,
1615
+ globalState,
1616
+ indent,
1617
+ info,
1618
+ jsdoc,
1619
+ jsdocNode: /**
1620
+ * @type {import('eslint').Rule.Node & {
1621
+ * range: [number, number];}}
1622
+ */ (jsdocNde),
1623
+ node,
1624
+ report,
1625
+ settings,
1626
+ sourceCode,
1627
+ state,
1628
+ utils,
1629
+ });
1630
+ };
1631
+ /**
1632
+ * @param {string[]} lines
1633
+ * @param {import('estree').Comment} jsdocNode
1634
+ * @returns {[indent: string, jsdoc: JsdocBlockWithInline]}
1635
+ */
1636
+ const getIndentAndJSDoc = function (lines, jsdocNode) {
1637
+ const sourceLine = lines[
1638
+ /** @type {import('estree').SourceLocation} */
1639
+ (jsdocNode.loc).start.line - 1];
1640
+ let indentChar = sourceLine.charAt(0);
1641
+ if (indentChar !== ' ' && indentChar !== '\t') {
1642
+ indentChar = ' ';
1643
+ }
1644
+ const indnt = indentChar.repeat(
1645
+ /** @type {import('estree').SourceLocation} */
1646
+ (jsdocNode.loc).start.column);
1647
+ const jsdc = (0, jsdoccomment_1.parseComment)(jsdocNode, '');
1648
+ return [
1649
+ indnt, jsdc,
1650
+ ];
1651
+ };
1652
+ /**
1653
+ *
1654
+ * @typedef {{node: Node & {
1655
+ * range: [number, number]
1656
+ * }, state: StateObject}} NonCommentArgs
1657
+ */
1658
+ /**
1659
+ * @typedef {object} RuleConfig
1660
+ * @property {EslintRuleMeta} meta ESLint rule meta
1661
+ * @property {import('./jsdocUtils.js').DefaultContexts} [contextDefaults] Any default contexts
1662
+ * @property {true} [contextSelected] Whether to force a `contexts` check
1663
+ * @property {true} [iterateAllJsdocs] Whether to iterate all JSDoc blocks by default
1664
+ * regardless of context
1665
+ * @property {true} [checkPrivate] Whether to check `@private` blocks (normally exempted)
1666
+ * @property {true} [checkInternal] Whether to check `@internal` blocks (normally exempted)
1667
+ * @property {true} [checkFile] Whether to iterates over all JSDoc blocks regardless of attachment
1668
+ * @property {true} [nonGlobalSettings] Whether to avoid relying on settings for global contexts
1669
+ * @property {true} [noTracking] Whether to disable the tracking of visited comment nodes (as
1670
+ * non-tracked may conduct further actions)
1671
+ * @property {true} [matchContext] Whether the rule expects contexts to be based on a match option
1672
+ * @property {(args: {
1673
+ * context: import('eslint').Rule.RuleContext,
1674
+ * state: StateObject,
1675
+ * settings: Settings,
1676
+ * utils: BasicUtils
1677
+ * }) => void} [exit] Handler to be executed upon exiting iteration of program AST
1678
+ * @property {(nca: NonCommentArgs) => void} [nonComment] Handler to be executed if rule wishes
1679
+ * to be supplied nodes without comments
1680
+ */
1681
+ /**
1682
+ * Create an eslint rule that iterates over all JSDocs, regardless of whether
1683
+ * they are attached to a function-like node.
1684
+ * @param {JsdocVisitor} iterator
1685
+ * @param {RuleConfig} ruleConfig The rule's configuration
1686
+ * @param {ContextObject[]|null} [contexts] The `contexts` containing relevant `comment` info.
1687
+ * @param {boolean} [additiveCommentContexts] If true, will have a separate
1688
+ * iteration for each matching comment context. Otherwise, will iterate
1689
+ * once if there is a single matching comment context.
1690
+ * @returns {import('eslint').Rule.RuleModule}
1691
+ */
1692
+ const iterateAllJsdocs = (iterator, ruleConfig, contexts, additiveCommentContexts) => {
1693
+ const trackedJsdocs = new Set();
1694
+ /** @type {import('@es-joy/jsdoccomment').CommentHandler} */
1695
+ let handler;
1696
+ /** @type {Settings|false} */
1697
+ let settings;
1698
+ /**
1699
+ * @param {import('eslint').Rule.RuleContext} context
1700
+ * @param {Node|null} node
1701
+ * @param {import('estree').Comment[]} jsdocNodes
1702
+ * @param {StateObject} state
1703
+ * @param {boolean} [lastCall]
1704
+ * @returns {void}
1705
+ */
1706
+ const callIterator = (context, node, jsdocNodes, state, lastCall) => {
1707
+ /* c8 ignore next -- Fallback to deprecated method */
1708
+ const { sourceCode = context.getSourceCode(), } = context;
1709
+ const { lines, } = sourceCode;
1710
+ const utils = getBasicUtils(context, /** @type {Settings} */ (settings));
1711
+ for (const jsdocNode of jsdocNodes) {
1712
+ const jsdocNde = /** @type {unknown} */ (jsdocNode);
1713
+ if (!(/^\/\*\*\s/v).test(sourceCode.getText(
1714
+ /** @type {import('estree').Node} */
1715
+ (jsdocNde)))) {
1716
+ continue;
1717
+ }
1718
+ const [indent, jsdoc,] = getIndentAndJSDoc(lines, jsdocNode);
1719
+ if (additiveCommentContexts) {
1720
+ for (const [idx, { comment, },] of /** @type {ContextObject[]} */ (contexts).entries()) {
1721
+ if (comment && handler(comment, jsdoc) === false) {
1722
+ continue;
1723
+ }
1724
+ iterate({
1725
+ comment,
1726
+ lastIndex: idx,
1727
+ selector: node?.type,
1728
+ }, indent, jsdoc, ruleConfig, context, jsdocNode,
1729
+ /** @type {Node} */
1730
+ (node),
1731
+ /** @type {Settings} */
1732
+ (settings), sourceCode, iterator, state, true);
1733
+ }
1734
+ continue;
1735
+ }
1736
+ let lastComment;
1737
+ let lastIndex;
1738
+ // eslint-disable-next-line no-loop-func
1739
+ if (contexts && contexts.every(({ comment, }, idx) => {
1740
+ lastComment = comment;
1741
+ lastIndex = idx;
1742
+ return comment && handler(comment, jsdoc) === false;
1743
+ })) {
1744
+ continue;
1745
+ }
1746
+ iterate(lastComment ? {
1747
+ comment: lastComment,
1748
+ lastIndex,
1749
+ selector: node?.type,
1750
+ } : {
1751
+ lastIndex,
1752
+ selector: node?.type,
1753
+ }, indent, jsdoc, ruleConfig, context, jsdocNode, node,
1754
+ /** @type {Settings} */
1755
+ (settings), sourceCode, iterator, state, true);
1756
+ }
1757
+ const settngs = /** @type {Settings} */ (settings);
1758
+ if (lastCall && ruleConfig.exit) {
1759
+ ruleConfig.exit({
1760
+ context,
1761
+ settings: settngs,
1762
+ state,
1763
+ utils,
1764
+ });
1765
+ }
1766
+ };
1767
+ return {
1768
+ create(context) {
1769
+ /* c8 ignore next -- Fallback to deprecated method */
1770
+ const { sourceCode = context.getSourceCode(), } = context;
1771
+ settings = getSettings(context);
1772
+ if (!settings) {
1773
+ return {};
1774
+ }
1775
+ if (contexts) {
1776
+ handler = (0, jsdoccomment_1.commentHandler)(settings);
1777
+ }
1778
+ const state = {};
1779
+ return {
1780
+ /**
1781
+ * @param {import('eslint').Rule.Node & {
1782
+ * range: [Integer, Integer];
1783
+ * }} node
1784
+ * @returns {void}
1785
+ */
1786
+ '*:not(Program)'(node) {
1787
+ const commentNode = (0, jsdoccomment_1.getJSDocComment)(sourceCode, node, /** @type {Settings} */ (settings));
1788
+ if (!ruleConfig.noTracking && trackedJsdocs.has(commentNode)) {
1789
+ return;
1790
+ }
1791
+ if (!commentNode) {
1792
+ if (ruleConfig.nonComment) {
1793
+ const ste = /** @type {StateObject} */ (state);
1794
+ ruleConfig.nonComment({
1795
+ node,
1796
+ state: ste,
1797
+ });
1798
+ }
1799
+ return;
1800
+ }
1801
+ trackedJsdocs.add(commentNode);
1802
+ callIterator(context, node, [
1803
+ /** @type {import('estree').Comment} */
1804
+ (commentNode),
1805
+ ], /** @type {StateObject} */ (state));
1806
+ },
1807
+ 'Program:exit'() {
1808
+ const allComments = sourceCode.getAllComments();
1809
+ const untrackedJSdoc = allComments.filter((node) => {
1810
+ return !trackedJsdocs.has(node);
1811
+ });
1812
+ callIterator(context, null, untrackedJSdoc,
1813
+ /** @type {StateObject} */
1814
+ (state), true);
1815
+ },
1816
+ };
1817
+ },
1818
+ meta: ruleConfig.meta,
1819
+ };
1820
+ };
1821
+ /**
1822
+ * Create an eslint rule that iterates over all JSDocs, regardless of whether
1823
+ * they are attached to a function-like node.
1824
+ * @param {JsdocVisitorBasic} iterator
1825
+ * @param {RuleConfig} ruleConfig
1826
+ * @returns {import('eslint').Rule.RuleModule}
1827
+ */
1828
+ const checkFile = (iterator, ruleConfig) => {
1829
+ return {
1830
+ create(context) {
1831
+ /* c8 ignore next -- Fallback to deprecated method */
1832
+ const { sourceCode = context.getSourceCode(), } = context;
1833
+ const settings = getSettings(context);
1834
+ if (!settings) {
1835
+ return {};
1836
+ }
1837
+ return {
1838
+ 'Program:exit'() {
1839
+ const allComms = /** @type {unknown} */ (sourceCode.getAllComments());
1840
+ const utils = getBasicUtils(context, settings);
1841
+ iterator({
1842
+ allComments: /** @type {import('estree').Node[]} */ (allComms),
1843
+ context,
1844
+ makeReport,
1845
+ settings,
1846
+ sourceCode,
1847
+ utils,
1848
+ });
1849
+ },
1850
+ };
1851
+ },
1852
+ meta: ruleConfig.meta,
1853
+ };
1854
+ };
1855
+ /**
1856
+ * @param {JsdocVisitor} iterator
1857
+ * @param {RuleConfig} ruleConfig
1858
+ * @returns {import('eslint').Rule.RuleModule}
1859
+ */
1860
+ function iterateJsdoc(iterator, ruleConfig) {
1861
+ const metaType = ruleConfig?.meta?.type;
1862
+ if (!metaType || ![
1863
+ 'layout', 'problem', 'suggestion',
1864
+ ].includes(metaType)) {
1865
+ throw new TypeError('Rule must include `meta.type` option (with value "problem", "suggestion", or "layout")');
1866
+ }
1867
+ if (typeof iterator !== 'function') {
1868
+ throw new TypeError('The iterator argument must be a function.');
1869
+ }
1870
+ if (ruleConfig.checkFile) {
1871
+ return checkFile(
1872
+ /** @type {JsdocVisitorBasic} */ (iterator), ruleConfig);
1873
+ }
1874
+ if (ruleConfig.iterateAllJsdocs) {
1875
+ return iterateAllJsdocs(iterator, ruleConfig);
1876
+ }
1877
+ /** @type {import('eslint').Rule.RuleModule} */
1878
+ return {
1879
+ /**
1880
+ * The entrypoint for the JSDoc rule.
1881
+ * @param {import('eslint').Rule.RuleContext} context
1882
+ * a reference to the context which hold all important information
1883
+ * like settings and the sourcecode to check.
1884
+ * @returns {import('eslint').Rule.RuleListener}
1885
+ * a listener with parser callback function.
1886
+ */
1887
+ create(context) {
1888
+ const settings = getSettings(context);
1889
+ if (!settings) {
1890
+ return {};
1891
+ }
1892
+ /**
1893
+ * @type {Context[]|undefined}
1894
+ */
1895
+ let contexts;
1896
+ if (ruleConfig.contextDefaults || ruleConfig.contextSelected || ruleConfig.matchContext) {
1897
+ contexts = ruleConfig.matchContext && context.options[0]?.match ?
1898
+ context.options[0].match :
1899
+ jsdocUtils.enforcedContexts(context, ruleConfig.contextDefaults, ruleConfig.nonGlobalSettings ? {} : settings);
1900
+ if (contexts) {
1901
+ contexts = contexts.map((obj) => {
1902
+ if (typeof obj === 'object' && !obj.context) {
1903
+ return {
1904
+ ...obj,
1905
+ context: 'any',
1906
+ };
1907
+ }
1908
+ return obj;
1909
+ });
1910
+ }
1911
+ const hasPlainAny = contexts?.includes('any');
1912
+ const hasObjectAny = !hasPlainAny && contexts?.find((ctxt) => {
1913
+ if (typeof ctxt === 'string') {
1914
+ return false;
1915
+ }
1916
+ return ctxt?.context === 'any';
1917
+ });
1918
+ if (hasPlainAny || hasObjectAny) {
1919
+ return iterateAllJsdocs(iterator, ruleConfig, hasObjectAny ? /** @type {ContextObject[]} */ (contexts) : null, ruleConfig.matchContext).create(context);
1920
+ }
1921
+ }
1922
+ /* c8 ignore next -- Fallback to deprecated method */
1923
+ const { sourceCode = context.getSourceCode(), } = context;
1924
+ const { lines, } = sourceCode;
1925
+ /** @type {Partial<StateObject>} */
1926
+ const state = {};
1927
+ /** @type {CheckJsdoc} */
1928
+ const checkJsdoc = (info, handler, node) => {
1929
+ const jsdocNode = (0, jsdoccomment_1.getJSDocComment)(sourceCode, node, settings);
1930
+ if (!jsdocNode) {
1931
+ return;
1932
+ }
1933
+ const [indent, jsdoc,] = getIndentAndJSDoc(lines,
1934
+ /** @type {import('estree').Comment} */
1935
+ (jsdocNode));
1936
+ if (
1937
+ // Note, `handler` should already be bound in its first argument
1938
+ // with these only to be called after the value of
1939
+ // `comment`
1940
+ handler && handler(jsdoc) === false) {
1941
+ return;
1942
+ }
1943
+ iterate(info, indent, jsdoc, ruleConfig, context, jsdocNode, node, settings, sourceCode, iterator,
1944
+ /** @type {StateObject} */
1945
+ (state));
1946
+ };
1947
+ /** @type {import('eslint').Rule.RuleListener} */
1948
+ let contextObject = {};
1949
+ if (contexts && (ruleConfig.contextDefaults || ruleConfig.contextSelected || ruleConfig.matchContext)) {
1950
+ contextObject = jsdocUtils.getContextObject(contexts, checkJsdoc, (0, jsdoccomment_1.commentHandler)(settings));
1951
+ }
1952
+ else {
1953
+ for (const prop of [
1954
+ 'ArrowFunctionExpression',
1955
+ 'FunctionDeclaration',
1956
+ 'FunctionExpression',
1957
+ 'TSDeclareFunction',
1958
+ ]) {
1959
+ contextObject[prop] = checkJsdoc.bind(null, {
1960
+ selector: prop,
1961
+ }, null);
1962
+ }
1963
+ }
1964
+ if (typeof ruleConfig.exit === 'function') {
1965
+ contextObject['Program:exit'] = () => {
1966
+ const ste = /** @type {StateObject} */ (state);
1967
+ // @ts-expect-error `utils` not needed at this point
1968
+ /** @type {Required<RuleConfig>} */ (ruleConfig).exit({
1969
+ context,
1970
+ settings,
1971
+ state: ste,
1972
+ });
1973
+ };
1974
+ }
1975
+ return contextObject;
1976
+ },
1977
+ meta: ruleConfig.meta,
1978
+ };
1979
+ }
1980
+ var jsdoccomment_2 = require("@es-joy/jsdoccomment");
1981
+ Object.defineProperty(exports, "parseComment", { enumerable: true, get: function () { return jsdoccomment_2.parseComment; } });