eslint-plugin-jsdoc 53.0.1 → 54.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 (359) hide show
  1. package/dist/WarnSettings.cjs +35 -18
  2. package/dist/WarnSettings.cjs.map +1 -1
  3. package/dist/alignTransform.cjs +305 -224
  4. package/dist/alignTransform.cjs.map +1 -1
  5. package/dist/defaultTagOrder.cjs +43 -132
  6. package/dist/defaultTagOrder.cjs.map +1 -1
  7. package/dist/exportParser.cjs +696 -478
  8. package/dist/exportParser.cjs.map +1 -1
  9. package/dist/generateRule.cjs +242 -0
  10. package/dist/generateRule.cjs.map +1 -0
  11. package/dist/getDefaultTagStructureForMode.cjs +288 -184
  12. package/dist/getDefaultTagStructureForMode.cjs.map +1 -1
  13. package/dist/getJsdocProcessorPlugin.cjs +550 -364
  14. package/dist/getJsdocProcessorPlugin.cjs.map +1 -1
  15. package/dist/getJsdocProcessorPlugin.d.ts +65 -68
  16. package/dist/getJsdocProcessorPlugin.d.ts.map +1 -1
  17. package/dist/index.cjs +410 -2
  18. package/dist/index.cjs.map +1 -0
  19. package/dist/index.d.ts +17 -2
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/iterateJsdoc.cjs +2005 -1539
  22. package/dist/iterateJsdoc.cjs.map +1 -1
  23. package/dist/iterateJsdoc.d.ts +350 -359
  24. package/dist/iterateJsdoc.d.ts.map +1 -1
  25. package/dist/jsdocUtils.cjs +1376 -1009
  26. package/dist/jsdocUtils.cjs.map +1 -1
  27. package/dist/rules/checkAccess.cjs +36 -29
  28. package/dist/rules/checkAccess.cjs.map +1 -1
  29. package/dist/rules/checkAlignment.cjs +54 -41
  30. package/dist/rules/checkAlignment.cjs.map +1 -1
  31. package/dist/rules/checkExamples.cjs +484 -327
  32. package/dist/rules/checkExamples.cjs.map +1 -1
  33. package/dist/rules/checkIndentation.cjs +65 -50
  34. package/dist/rules/checkIndentation.cjs.map +1 -1
  35. package/dist/rules/checkLineAlignment.cjs +311 -220
  36. package/dist/rules/checkLineAlignment.cjs.map +1 -1
  37. package/dist/rules/checkParamNames.cjs +335 -227
  38. package/dist/rules/checkParamNames.cjs.map +1 -1
  39. package/dist/rules/checkPropertyNames.cjs +106 -78
  40. package/dist/rules/checkPropertyNames.cjs.map +1 -1
  41. package/dist/rules/checkSyntax.cjs +34 -21
  42. package/dist/rules/checkSyntax.cjs.map +1 -1
  43. package/dist/rules/checkTagNames.cjs +210 -188
  44. package/dist/rules/checkTagNames.cjs.map +1 -1
  45. package/dist/rules/checkTemplateNames.cjs +178 -121
  46. package/dist/rules/checkTemplateNames.cjs.map +1 -1
  47. package/dist/rules/checkTypes.cjs +385 -291
  48. package/dist/rules/checkTypes.cjs.map +1 -1
  49. package/dist/rules/checkValues.cjs +146 -100
  50. package/dist/rules/checkValues.cjs.map +1 -1
  51. package/dist/rules/convertToJsdocComments.cjs +306 -228
  52. package/dist/rules/convertToJsdocComments.cjs.map +1 -1
  53. package/dist/rules/emptyTags.cjs +72 -62
  54. package/dist/rules/emptyTags.cjs.map +1 -1
  55. package/dist/rules/implementsOnClasses.cjs +56 -36
  56. package/dist/rules/implementsOnClasses.cjs.map +1 -1
  57. package/dist/rules/importsAsDependencies.cjs +99 -62
  58. package/dist/rules/importsAsDependencies.cjs.map +1 -1
  59. package/dist/rules/informativeDocs.cjs +142 -105
  60. package/dist/rules/informativeDocs.cjs.map +1 -1
  61. package/dist/rules/linesBeforeBlock.cjs +105 -70
  62. package/dist/rules/linesBeforeBlock.cjs.map +1 -1
  63. package/dist/rules/matchDescription.cjs +222 -160
  64. package/dist/rules/matchDescription.cjs.map +1 -1
  65. package/dist/rules/matchName.cjs +128 -73
  66. package/dist/rules/matchName.cjs.map +1 -1
  67. package/dist/rules/multilineBlocks.cjs +352 -235
  68. package/dist/rules/multilineBlocks.cjs.map +1 -1
  69. package/dist/rules/noBadBlocks.cjs +86 -63
  70. package/dist/rules/noBadBlocks.cjs.map +1 -1
  71. package/dist/rules/noBlankBlockDescriptions.cjs +57 -35
  72. package/dist/rules/noBlankBlockDescriptions.cjs.map +1 -1
  73. package/dist/rules/noBlankBlocks.cjs +48 -26
  74. package/dist/rules/noBlankBlocks.cjs.map +1 -1
  75. package/dist/rules/noDefaults.cjs +79 -52
  76. package/dist/rules/noDefaults.cjs.map +1 -1
  77. package/dist/rules/noMissingSyntax.cjs +165 -115
  78. package/dist/rules/noMissingSyntax.cjs.map +1 -1
  79. package/dist/rules/noMultiAsterisks.cjs +89 -48
  80. package/dist/rules/noMultiAsterisks.cjs.map +1 -1
  81. package/dist/rules/noRestrictedSyntax.cjs +79 -45
  82. package/dist/rules/noRestrictedSyntax.cjs.map +1 -1
  83. package/dist/rules/noTypes.cjs +80 -59
  84. package/dist/rules/noTypes.cjs.map +1 -1
  85. package/dist/rules/noUndefinedTypes.cjs +388 -297
  86. package/dist/rules/noUndefinedTypes.cjs.map +1 -1
  87. package/dist/rules/requireAsteriskPrefix.cjs +159 -108
  88. package/dist/rules/requireAsteriskPrefix.cjs.map +1 -1
  89. package/dist/rules/requireDescription.cjs +129 -89
  90. package/dist/rules/requireDescription.cjs.map +1 -1
  91. package/dist/rules/requireDescriptionCompleteSentence.cjs +262 -201
  92. package/dist/rules/requireDescriptionCompleteSentence.cjs.map +1 -1
  93. package/dist/rules/requireExample.cjs +104 -73
  94. package/dist/rules/requireExample.cjs.map +1 -1
  95. package/dist/rules/requireFileOverview.cjs +129 -75
  96. package/dist/rules/requireFileOverview.cjs.map +1 -1
  97. package/dist/rules/requireHyphenBeforeParamDescription.cjs +133 -85
  98. package/dist/rules/requireHyphenBeforeParamDescription.cjs.map +1 -1
  99. package/dist/rules/requireJsdoc.cjs +557 -384
  100. package/dist/rules/requireJsdoc.cjs.map +1 -1
  101. package/dist/rules/requireParam.cjs +526 -336
  102. package/dist/rules/requireParam.cjs.map +1 -1
  103. package/dist/rules/requireParamDescription.cjs +80 -55
  104. package/dist/rules/requireParamDescription.cjs.map +1 -1
  105. package/dist/rules/requireParamName.cjs +50 -32
  106. package/dist/rules/requireParamName.cjs.map +1 -1
  107. package/dist/rules/requireParamType.cjs +80 -55
  108. package/dist/rules/requireParamType.cjs.map +1 -1
  109. package/dist/rules/requireProperty.cjs +42 -31
  110. package/dist/rules/requireProperty.cjs.map +1 -1
  111. package/dist/rules/requirePropertyDescription.cjs +25 -17
  112. package/dist/rules/requirePropertyDescription.cjs.map +1 -1
  113. package/dist/rules/requirePropertyName.cjs +25 -17
  114. package/dist/rules/requirePropertyName.cjs.map +1 -1
  115. package/dist/rules/requirePropertyType.cjs +25 -17
  116. package/dist/rules/requirePropertyType.cjs.map +1 -1
  117. package/dist/rules/requireReturns.cjs +203 -125
  118. package/dist/rules/requireReturns.cjs.map +1 -1
  119. package/dist/rules/requireReturnsCheck.cjs +103 -60
  120. package/dist/rules/requireReturnsCheck.cjs.map +1 -1
  121. package/dist/rules/requireReturnsDescription.cjs +54 -39
  122. package/dist/rules/requireReturnsDescription.cjs.map +1 -1
  123. package/dist/rules/requireReturnsType.cjs +50 -32
  124. package/dist/rules/requireReturnsType.cjs.map +1 -1
  125. package/dist/rules/requireTemplate.cjs +178 -119
  126. package/dist/rules/requireTemplate.cjs.map +1 -1
  127. package/dist/rules/requireThrows.cjs +95 -61
  128. package/dist/rules/requireThrows.cjs.map +1 -1
  129. package/dist/rules/requireYields.cjs +166 -106
  130. package/dist/rules/requireYields.cjs.map +1 -1
  131. package/dist/rules/requireYieldsCheck.cjs +152 -96
  132. package/dist/rules/requireYieldsCheck.cjs.map +1 -1
  133. package/dist/rules/sortTags.cjs +444 -258
  134. package/dist/rules/sortTags.cjs.map +1 -1
  135. package/dist/rules/tagLines.cjs +266 -179
  136. package/dist/rules/tagLines.cjs.map +1 -1
  137. package/dist/rules/textEscaping.cjs +127 -92
  138. package/dist/rules/textEscaping.cjs.map +1 -1
  139. package/dist/rules/validTypes.cjs +265 -252
  140. package/dist/rules/validTypes.cjs.map +1 -1
  141. package/dist/tagNames.cjs +170 -134
  142. package/dist/tagNames.cjs.map +1 -1
  143. package/dist/utils/hasReturnValue.cjs +474 -246
  144. package/dist/utils/hasReturnValue.cjs.map +1 -1
  145. package/package.json +24 -40
  146. package/src/WarnSettings.js +34 -0
  147. package/src/alignTransform.js +358 -0
  148. package/src/defaultTagOrder.js +169 -0
  149. package/src/exportParser.js +978 -0
  150. package/src/getDefaultTagStructureForMode.js +969 -0
  151. package/src/getJsdocProcessorPlugin.js +672 -0
  152. package/src/index.js +530 -0
  153. package/src/iterateJsdoc.js +2541 -0
  154. package/src/jsdocUtils.js +1896 -0
  155. package/src/rules/checkAccess.js +45 -0
  156. package/src/rules/checkAlignment.js +63 -0
  157. package/src/rules/checkExamples.js +589 -0
  158. package/src/rules/checkIndentation.js +75 -0
  159. package/src/rules/checkLineAlignment.js +372 -0
  160. package/src/rules/checkParamNames.js +474 -0
  161. package/src/rules/checkPropertyNames.js +152 -0
  162. package/src/rules/checkSyntax.js +30 -0
  163. package/src/rules/checkTagNames.js +314 -0
  164. package/src/rules/checkTemplateNames.js +204 -0
  165. package/src/rules/checkTypes.js +535 -0
  166. package/src/rules/checkValues.js +248 -0
  167. package/src/rules/convertToJsdocComments.js +398 -0
  168. package/src/rules/emptyTags.js +98 -0
  169. package/src/rules/implementsOnClasses.js +64 -0
  170. package/src/rules/importsAsDependencies.js +133 -0
  171. package/src/rules/informativeDocs.js +189 -0
  172. package/src/rules/linesBeforeBlock.js +134 -0
  173. package/src/rules/matchDescription.js +286 -0
  174. package/src/rules/matchName.js +151 -0
  175. package/src/rules/multilineBlocks.js +493 -0
  176. package/src/rules/noBadBlocks.js +119 -0
  177. package/src/rules/noBlankBlockDescriptions.js +69 -0
  178. package/src/rules/noBlankBlocks.js +53 -0
  179. package/src/rules/noDefaults.js +85 -0
  180. package/src/rules/noMissingSyntax.js +195 -0
  181. package/src/rules/noMultiAsterisks.js +134 -0
  182. package/src/rules/noRestrictedSyntax.js +91 -0
  183. package/src/rules/noTypes.js +93 -0
  184. package/src/rules/noUndefinedTypes.js +543 -0
  185. package/src/rules/requireAsteriskPrefix.js +190 -0
  186. package/src/rules/requireDescription.js +161 -0
  187. package/src/rules/requireDescriptionCompleteSentence.js +335 -0
  188. package/src/rules/requireExample.js +118 -0
  189. package/src/rules/requireFileOverview.js +154 -0
  190. package/src/rules/requireHyphenBeforeParamDescription.js +176 -0
  191. package/src/rules/requireJsdoc.js +743 -0
  192. package/src/rules/requireParam.js +602 -0
  193. package/src/rules/requireParamDescription.js +89 -0
  194. package/src/rules/requireParamName.js +55 -0
  195. package/src/rules/requireParamType.js +89 -0
  196. package/src/rules/requireProperty.js +48 -0
  197. package/src/rules/requirePropertyDescription.js +25 -0
  198. package/src/rules/requirePropertyName.js +25 -0
  199. package/src/rules/requirePropertyType.js +25 -0
  200. package/src/rules/requireReturns.js +238 -0
  201. package/src/rules/requireReturnsCheck.js +145 -0
  202. package/src/rules/requireReturnsDescription.js +59 -0
  203. package/src/rules/requireReturnsType.js +51 -0
  204. package/src/rules/requireTemplate.js +201 -0
  205. package/src/rules/requireThrows.js +111 -0
  206. package/src/rules/requireYields.js +216 -0
  207. package/src/rules/requireYieldsCheck.js +208 -0
  208. package/src/rules/sortTags.js +558 -0
  209. package/src/rules/tagLines.js +359 -0
  210. package/src/rules/textEscaping.js +154 -0
  211. package/src/rules/validTypes.js +401 -0
  212. package/src/tagNames.js +238 -0
  213. package/src/utils/hasReturnValue.js +572 -0
  214. package/dist/WarnSettings.js +0 -20
  215. package/dist/WarnSettings.js.map +0 -1
  216. package/dist/_virtual/rolldown_runtime.cjs +0 -32
  217. package/dist/_virtual/rolldown_runtime.js +0 -11
  218. package/dist/alignTransform.js +0 -241
  219. package/dist/alignTransform.js.map +0 -1
  220. package/dist/defaultTagOrder.js +0 -134
  221. package/dist/defaultTagOrder.js.map +0 -1
  222. package/dist/exportParser.js +0 -518
  223. package/dist/exportParser.js.map +0 -1
  224. package/dist/getDefaultTagStructureForMode.js +0 -188
  225. package/dist/getDefaultTagStructureForMode.js.map +0 -1
  226. package/dist/getJsdocProcessorPlugin.d.cts +0 -70
  227. package/dist/getJsdocProcessorPlugin.d.cts.map +0 -1
  228. package/dist/getJsdocProcessorPlugin.js +0 -383
  229. package/dist/getJsdocProcessorPlugin.js.map +0 -1
  230. package/dist/index.d.cts +0 -2
  231. package/dist/index.js +0 -3
  232. package/dist/iterateJsdoc.d.cts +0 -472
  233. package/dist/iterateJsdoc.d.cts.map +0 -1
  234. package/dist/iterateJsdoc.js +0 -1628
  235. package/dist/iterateJsdoc.js.map +0 -1
  236. package/dist/jsdocUtils.js +0 -1123
  237. package/dist/jsdocUtils.js.map +0 -1
  238. package/dist/plugin.cjs +0 -427
  239. package/dist/plugin.cjs.map +0 -1
  240. package/dist/plugin.js +0 -427
  241. package/dist/plugin.js.map +0 -1
  242. package/dist/rules/checkAccess.js +0 -33
  243. package/dist/rules/checkAccess.js.map +0 -1
  244. package/dist/rules/checkAlignment.js +0 -47
  245. package/dist/rules/checkAlignment.js.map +0 -1
  246. package/dist/rules/checkExamples.js +0 -348
  247. package/dist/rules/checkExamples.js.map +0 -1
  248. package/dist/rules/checkIndentation.js +0 -59
  249. package/dist/rules/checkIndentation.js.map +0 -1
  250. package/dist/rules/checkLineAlignment.js +0 -229
  251. package/dist/rules/checkLineAlignment.js.map +0 -1
  252. package/dist/rules/checkParamNames.js +0 -237
  253. package/dist/rules/checkParamNames.js.map +0 -1
  254. package/dist/rules/checkPropertyNames.js +0 -88
  255. package/dist/rules/checkPropertyNames.js.map +0 -1
  256. package/dist/rules/checkSyntax.js +0 -25
  257. package/dist/rules/checkSyntax.js.map +0 -1
  258. package/dist/rules/checkTagNames.js +0 -191
  259. package/dist/rules/checkTagNames.js.map +0 -1
  260. package/dist/rules/checkTemplateNames.js +0 -124
  261. package/dist/rules/checkTemplateNames.js.map +0 -1
  262. package/dist/rules/checkTypes.js +0 -299
  263. package/dist/rules/checkTypes.js.map +0 -1
  264. package/dist/rules/checkValues.js +0 -103
  265. package/dist/rules/checkValues.js.map +0 -1
  266. package/dist/rules/convertToJsdocComments.js +0 -231
  267. package/dist/rules/convertToJsdocComments.js.map +0 -1
  268. package/dist/rules/emptyTags.js +0 -67
  269. package/dist/rules/emptyTags.js.map +0 -1
  270. package/dist/rules/implementsOnClasses.js +0 -40
  271. package/dist/rules/implementsOnClasses.js.map +0 -1
  272. package/dist/rules/importsAsDependencies.js +0 -68
  273. package/dist/rules/importsAsDependencies.js.map +0 -1
  274. package/dist/rules/informativeDocs.js +0 -110
  275. package/dist/rules/informativeDocs.js.map +0 -1
  276. package/dist/rules/linesBeforeBlock.js +0 -75
  277. package/dist/rules/linesBeforeBlock.js.map +0 -1
  278. package/dist/rules/matchDescription.js +0 -167
  279. package/dist/rules/matchDescription.js.map +0 -1
  280. package/dist/rules/matchName.js +0 -77
  281. package/dist/rules/matchName.js.map +0 -1
  282. package/dist/rules/multilineBlocks.js +0 -245
  283. package/dist/rules/multilineBlocks.js.map +0 -1
  284. package/dist/rules/noBadBlocks.js +0 -68
  285. package/dist/rules/noBadBlocks.js.map +0 -1
  286. package/dist/rules/noBlankBlockDescriptions.js +0 -41
  287. package/dist/rules/noBlankBlockDescriptions.js.map +0 -1
  288. package/dist/rules/noBlankBlocks.js +0 -30
  289. package/dist/rules/noBlankBlocks.js.map +0 -1
  290. package/dist/rules/noDefaults.js +0 -56
  291. package/dist/rules/noDefaults.js.map +0 -1
  292. package/dist/rules/noMissingSyntax.js +0 -126
  293. package/dist/rules/noMissingSyntax.js.map +0 -1
  294. package/dist/rules/noMultiAsterisks.js +0 -58
  295. package/dist/rules/noMultiAsterisks.js.map +0 -1
  296. package/dist/rules/noRestrictedSyntax.js +0 -49
  297. package/dist/rules/noRestrictedSyntax.js.map +0 -1
  298. package/dist/rules/noTypes.js +0 -65
  299. package/dist/rules/noTypes.js.map +0 -1
  300. package/dist/rules/noUndefinedTypes.js +0 -303
  301. package/dist/rules/noUndefinedTypes.js.map +0 -1
  302. package/dist/rules/requireAsteriskPrefix.js +0 -112
  303. package/dist/rules/requireAsteriskPrefix.js.map +0 -1
  304. package/dist/rules/requireDescription.js +0 -95
  305. package/dist/rules/requireDescription.js.map +0 -1
  306. package/dist/rules/requireDescriptionCompleteSentence.js +0 -220
  307. package/dist/rules/requireDescriptionCompleteSentence.js.map +0 -1
  308. package/dist/rules/requireExample.js +0 -77
  309. package/dist/rules/requireExample.js.map +0 -1
  310. package/dist/rules/requireFileOverview.js +0 -81
  311. package/dist/rules/requireFileOverview.js.map +0 -1
  312. package/dist/rules/requireHyphenBeforeParamDescription.js +0 -89
  313. package/dist/rules/requireHyphenBeforeParamDescription.js.map +0 -1
  314. package/dist/rules/requireJsdoc.js +0 -404
  315. package/dist/rules/requireJsdoc.js.map +0 -1
  316. package/dist/rules/requireParam.js +0 -344
  317. package/dist/rules/requireParam.js.map +0 -1
  318. package/dist/rules/requireParamDescription.js +0 -59
  319. package/dist/rules/requireParamDescription.js.map +0 -1
  320. package/dist/rules/requireParamName.js +0 -36
  321. package/dist/rules/requireParamName.js.map +0 -1
  322. package/dist/rules/requireParamType.js +0 -59
  323. package/dist/rules/requireParamType.js.map +0 -1
  324. package/dist/rules/requireProperty.js +0 -35
  325. package/dist/rules/requireProperty.js.map +0 -1
  326. package/dist/rules/requirePropertyDescription.js +0 -21
  327. package/dist/rules/requirePropertyDescription.js.map +0 -1
  328. package/dist/rules/requirePropertyName.js +0 -21
  329. package/dist/rules/requirePropertyName.js.map +0 -1
  330. package/dist/rules/requirePropertyType.js +0 -21
  331. package/dist/rules/requirePropertyType.js.map +0 -1
  332. package/dist/rules/requireReturns.js +0 -131
  333. package/dist/rules/requireReturns.js.map +0 -1
  334. package/dist/rules/requireReturnsCheck.js +0 -66
  335. package/dist/rules/requireReturnsCheck.js.map +0 -1
  336. package/dist/rules/requireReturnsDescription.js +0 -43
  337. package/dist/rules/requireReturnsDescription.js.map +0 -1
  338. package/dist/rules/requireReturnsType.js +0 -36
  339. package/dist/rules/requireReturnsType.js.map +0 -1
  340. package/dist/rules/requireTemplate.js +0 -122
  341. package/dist/rules/requireTemplate.js.map +0 -1
  342. package/dist/rules/requireThrows.js +0 -67
  343. package/dist/rules/requireThrows.js.map +0 -1
  344. package/dist/rules/requireYields.js +0 -115
  345. package/dist/rules/requireYields.js.map +0 -1
  346. package/dist/rules/requireYieldsCheck.js +0 -105
  347. package/dist/rules/requireYieldsCheck.js.map +0 -1
  348. package/dist/rules/sortTags.js +0 -262
  349. package/dist/rules/sortTags.js.map +0 -1
  350. package/dist/rules/tagLines.js +0 -183
  351. package/dist/rules/tagLines.js.map +0 -1
  352. package/dist/rules/textEscaping.js +0 -102
  353. package/dist/rules/textEscaping.js.map +0 -1
  354. package/dist/rules/validTypes.js +0 -259
  355. package/dist/rules/validTypes.js.map +0 -1
  356. package/dist/tagNames.js +0 -144
  357. package/dist/tagNames.js.map +0 -1
  358. package/dist/utils/hasReturnValue.js +0 -265
  359. package/dist/utils/hasReturnValue.js.map +0 -1
@@ -0,0 +1,2541 @@
1
+ import * as jsdocUtils from './jsdocUtils.js';
2
+ import {
3
+ commentHandler,
4
+ getJSDocComment,
5
+ parseComment,
6
+ } from '@es-joy/jsdoccomment';
7
+ import {
8
+ stringify as commentStringify,
9
+ util,
10
+ } from 'comment-parser';
11
+ import esquery from 'esquery';
12
+
13
+ /**
14
+ * @typedef {number} Integer
15
+ */
16
+
17
+ /**
18
+ * @typedef {import('@es-joy/jsdoccomment').JsdocBlockWithInline} JsdocBlockWithInline
19
+ */
20
+
21
+ /**
22
+ * @typedef {{
23
+ * disallowName?: string,
24
+ * allowName?: string,
25
+ * context?: string,
26
+ * comment?: string,
27
+ * tags?: string[],
28
+ * replacement?: string,
29
+ * minimum?: Integer,
30
+ * message?: string,
31
+ * forceRequireReturn?: boolean
32
+ * }} ContextObject
33
+ */
34
+ /**
35
+ * @typedef {string|ContextObject} Context
36
+ */
37
+
38
+ /**
39
+ * @callback CheckJsdoc
40
+ * @param {{
41
+ * lastIndex?: Integer,
42
+ * isFunctionContext?: boolean,
43
+ * selector?: string,
44
+ * comment?: string
45
+ * }} info
46
+ * @param {null|((jsdoc: import('@es-joy/jsdoccomment').JsdocBlockWithInline) => boolean|undefined)} handler
47
+ * @param {import('eslint').Rule.Node} node
48
+ * @returns {void}
49
+ */
50
+
51
+ /**
52
+ * @callback ForEachPreferredTag
53
+ * @param {string} tagName
54
+ * @param {(
55
+ * matchingJsdocTag: import('@es-joy/jsdoccomment').JsdocTagWithInline,
56
+ * targetTagName: string
57
+ * ) => void} arrayHandler
58
+ * @param {boolean} [skipReportingBlockedTag]
59
+ * @returns {void}
60
+ */
61
+
62
+ /**
63
+ * @callback ReportSettings
64
+ * @param {string} message
65
+ * @returns {void}
66
+ */
67
+
68
+ /**
69
+ * @callback ParseClosureTemplateTag
70
+ * @param {import('comment-parser').Spec} tag
71
+ * @returns {string[]}
72
+ */
73
+
74
+ /**
75
+ * @callback GetPreferredTagNameObject
76
+ * @param {{
77
+ * tagName: string
78
+ * }} cfg
79
+ * @returns {string|false|{
80
+ * message: string;
81
+ * replacement?: string|undefined
82
+ * }|{
83
+ * blocked: true,
84
+ * tagName: string
85
+ * }}
86
+ */
87
+
88
+ /**
89
+ * @typedef {{
90
+ * forEachPreferredTag: ForEachPreferredTag,
91
+ * reportSettings: ReportSettings,
92
+ * parseClosureTemplateTag: ParseClosureTemplateTag,
93
+ * getPreferredTagNameObject: GetPreferredTagNameObject,
94
+ * pathDoesNotBeginWith: import('./jsdocUtils.js').PathDoesNotBeginWith
95
+ * }} BasicUtils
96
+ */
97
+
98
+ /**
99
+ * @callback IsIteratingFunction
100
+ * @returns {boolean}
101
+ */
102
+
103
+ /**
104
+ * @callback IsVirtualFunction
105
+ * @returns {boolean}
106
+ */
107
+
108
+ /**
109
+ * @callback Stringify
110
+ * @param {import('comment-parser').Block} tagBlock
111
+ * @param {boolean} [specRewire]
112
+ * @returns {string}
113
+ */
114
+
115
+ /**
116
+ * @callback ReportJSDoc
117
+ * @param {string} msg
118
+ * @param {null|import('comment-parser').Spec|{line: Integer, column?: Integer}} [tag]
119
+ * @param {(() => void)|null} [handler]
120
+ * @param {boolean} [specRewire]
121
+ * @param {undefined|{
122
+ * [key: string]: string
123
+ * }} [data]
124
+ */
125
+
126
+ /**
127
+ * @callback GetRegexFromString
128
+ * @param {string} str
129
+ * @param {string} [requiredFlags]
130
+ * @returns {RegExp}
131
+ */
132
+
133
+ /**
134
+ * @callback GetTagDescription
135
+ * @param {import('comment-parser').Spec} tg
136
+ * @param {boolean} [returnArray]
137
+ * @returns {string[]|string}
138
+ */
139
+
140
+ /**
141
+ * @callback SetTagDescription
142
+ * @param {import('comment-parser').Spec} tg
143
+ * @param {RegExp} matcher
144
+ * @param {(description: string) => string} setter
145
+ * @returns {Integer}
146
+ */
147
+
148
+ /**
149
+ * @callback GetDescription
150
+ * @returns {{
151
+ * description: string,
152
+ * descriptions: string[],
153
+ * lastDescriptionLine: Integer
154
+ * }}
155
+ */
156
+
157
+ /**
158
+ * @callback SetBlockDescription
159
+ * @param {(
160
+ * info: {
161
+ * delimiter: string,
162
+ * postDelimiter: string,
163
+ * start: string
164
+ * },
165
+ * seedTokens: (
166
+ * tokens?: Partial<import('comment-parser').Tokens>
167
+ * ) => import('comment-parser').Tokens,
168
+ * descLines: string[]
169
+ * ) => import('comment-parser').Line[]} setter
170
+ * @returns {void}
171
+ */
172
+
173
+ /**
174
+ * @callback SetDescriptionLines
175
+ * @param {RegExp} matcher
176
+ * @param {(description: string) => string} setter
177
+ * @returns {Integer}
178
+ */
179
+
180
+ /**
181
+ * @callback ChangeTag
182
+ * @param {import('comment-parser').Spec} tag
183
+ * @param {...Partial<import('comment-parser').Tokens>} tokens
184
+ * @returns {void}
185
+ */
186
+
187
+ /**
188
+ * @callback SetTag
189
+ * @param {import('comment-parser').Spec & {
190
+ * line: Integer
191
+ * }} tag
192
+ * @param {Partial<import('comment-parser').Tokens>} [tokens]
193
+ * @returns {void}
194
+ */
195
+
196
+ /**
197
+ * @callback RemoveTag
198
+ * @param {Integer} tagIndex
199
+ * @param {{
200
+ * removeEmptyBlock?: boolean,
201
+ * tagSourceOffset?: Integer
202
+ * }} [cfg]
203
+ * @returns {void}
204
+ */
205
+
206
+ /**
207
+ * @callback AddTag
208
+ * @param {string} targetTagName
209
+ * @param {Integer} [number]
210
+ * @param {import('comment-parser').Tokens|{}} [tokens]
211
+ * @returns {void}
212
+ */
213
+
214
+ /**
215
+ * @callback GetFirstLine
216
+ * @returns {Integer|undefined}
217
+ */
218
+
219
+ /**
220
+ * @typedef {(
221
+ * tokens?: Partial<import('comment-parser').Tokens> | undefined
222
+ * ) => import('comment-parser').Tokens} SeedTokens
223
+ */
224
+
225
+ /**
226
+ * Sets tokens to empty string.
227
+ * @callback EmptyTokens
228
+ * @param {import('comment-parser').Tokens} tokens
229
+ * @returns {void}
230
+ */
231
+
232
+ /**
233
+ * @callback AddLine
234
+ * @param {Integer} sourceIndex
235
+ * @param {Partial<import('comment-parser').Tokens>} tokens
236
+ * @returns {void}
237
+ */
238
+
239
+ /**
240
+ * @callback AddLines
241
+ * @param {Integer} tagIndex
242
+ * @param {Integer} tagSourceOffset
243
+ * @param {Integer} numLines
244
+ * @returns {void}
245
+ */
246
+
247
+ /**
248
+ * @callback MakeMultiline
249
+ * @returns {void}
250
+ */
251
+
252
+ /**
253
+ * @callback GetFunctionParameterNames
254
+ * @param {boolean} [useDefaultObjectProperties]
255
+ * @returns {import('./jsdocUtils.js').ParamNameInfo[]}
256
+ */
257
+
258
+ /**
259
+ * @callback HasParams
260
+ * @returns {Integer}
261
+ */
262
+
263
+ /**
264
+ * @callback IsGenerator
265
+ * @returns {boolean}
266
+ */
267
+
268
+ /**
269
+ * @callback IsConstructor
270
+ * @returns {boolean}
271
+ */
272
+
273
+ /**
274
+ * @callback GetJsdocTagsDeep
275
+ * @param {string} tagName
276
+ * @returns {false|{
277
+ * idx: Integer,
278
+ * name: string,
279
+ * type: string
280
+ * }[]}
281
+ */
282
+
283
+ /**
284
+ * @callback GetPreferredTagName
285
+ * @param {{
286
+ * tagName: string,
287
+ * skipReportingBlockedTag?: boolean,
288
+ * allowObjectReturn?: boolean,
289
+ * defaultMessage?: string
290
+ * }} cfg
291
+ * @returns {string|undefined|false|{
292
+ * message: string;
293
+ * replacement?: string|undefined;
294
+ * }|{
295
+ * blocked: true,
296
+ * tagName: string
297
+ * }}
298
+ */
299
+
300
+ /**
301
+ * @callback IsValidTag
302
+ * @param {string} name
303
+ * @param {string[]} definedTags
304
+ * @returns {boolean}
305
+ */
306
+
307
+ /**
308
+ * @callback HasATag
309
+ * @param {string[]} names
310
+ * @returns {boolean}
311
+ */
312
+
313
+ /**
314
+ * @callback HasTag
315
+ * @param {string} name
316
+ * @returns {boolean}
317
+ */
318
+
319
+ /**
320
+ * @callback ComparePaths
321
+ * @param {string} name
322
+ * @returns {(otherPathName: string) => boolean}
323
+ */
324
+
325
+ /**
326
+ * @callback DropPathSegmentQuotes
327
+ * @param {string} name
328
+ * @returns {string}
329
+ */
330
+
331
+ /**
332
+ * @callback AvoidDocs
333
+ * @returns {boolean}
334
+ */
335
+
336
+ /**
337
+ * @callback TagMightHaveNamePositionTypePosition
338
+ * @param {string} tagName
339
+ * @param {import('./getDefaultTagStructureForMode.js').
340
+ * TagStructure[]} [otherModeMaps]
341
+ * @returns {boolean|{otherMode: true}}
342
+ */
343
+
344
+ /**
345
+ * @callback TagMustHave
346
+ * @param {string} tagName
347
+ * @param {import('./getDefaultTagStructureForMode.js').
348
+ * TagStructure[]} otherModeMaps
349
+ * @returns {boolean|{
350
+ * otherMode: false
351
+ * }}
352
+ */
353
+
354
+ /**
355
+ * @callback TagMissingRequiredTypeOrNamepath
356
+ * @param {import('comment-parser').Spec} tag
357
+ * @param {import('./getDefaultTagStructureForMode.js').
358
+ * TagStructure[]} otherModeMaps
359
+ * @returns {boolean|{
360
+ * otherMode: false
361
+ * }}
362
+ */
363
+
364
+ /**
365
+ * @callback IsNamepathX
366
+ * @param {string} tagName
367
+ * @returns {boolean}
368
+ */
369
+
370
+ /**
371
+ * @callback GetTagStructureForMode
372
+ * @param {import('./jsdocUtils.js').ParserMode} mde
373
+ * @returns {import('./getDefaultTagStructureForMode.js').TagStructure}
374
+ */
375
+
376
+ /**
377
+ * @callback MayBeUndefinedTypeTag
378
+ * @param {import('comment-parser').Spec} tag
379
+ * @returns {boolean}
380
+ */
381
+
382
+ /**
383
+ * @callback HasValueOrExecutorHasNonEmptyResolveValue
384
+ * @param {boolean} anyPromiseAsReturn
385
+ * @param {boolean} [allBranches]
386
+ * @returns {boolean}
387
+ */
388
+
389
+ /**
390
+ * @callback HasYieldValue
391
+ * @returns {boolean}
392
+ */
393
+
394
+ /**
395
+ * @callback HasYieldReturnValue
396
+ * @returns {boolean}
397
+ */
398
+
399
+ /**
400
+ * @callback HasThrowValue
401
+ * @returns {boolean}
402
+ */
403
+
404
+ /**
405
+ * @callback IsAsync
406
+ * @returns {boolean|undefined}
407
+ */
408
+
409
+ /**
410
+ * @callback GetTags
411
+ * @param {string} tagName
412
+ * @returns {import('comment-parser').Spec[]}
413
+ */
414
+
415
+ /**
416
+ * @callback GetPresentTags
417
+ * @param {string[]} tagList
418
+ * @returns {import('@es-joy/jsdoccomment').JsdocTagWithInline[]}
419
+ */
420
+
421
+ /**
422
+ * @callback FilterTags
423
+ * @param {(tag: import('@es-joy/jsdoccomment').JsdocTagWithInline) => boolean} filter
424
+ * @returns {import('@es-joy/jsdoccomment').JsdocTagWithInline[]}
425
+ */
426
+
427
+ /**
428
+ * @callback FilterAllTags
429
+ * @param {(tag: (import('comment-parser').Spec|
430
+ * import('@es-joy/jsdoccomment').JsdocInlineTagNoType)) => boolean} filter
431
+ * @returns {(import('comment-parser').Spec|
432
+ * import('@es-joy/jsdoccomment').JsdocInlineTagNoType)[]}
433
+ */
434
+
435
+ /**
436
+ * @callback GetTagsByType
437
+ * @param {import('comment-parser').Spec[]} tags
438
+ * @returns {{
439
+ * tagsWithNames: import('comment-parser').Spec[],
440
+ * tagsWithoutNames: import('comment-parser').Spec[]
441
+ * }}
442
+ */
443
+
444
+ /**
445
+ * @callback HasOptionTag
446
+ * @param {string} tagName
447
+ * @returns {boolean}
448
+ */
449
+
450
+ /**
451
+ * @callback GetClassNode
452
+ * @returns {Node|null}
453
+ */
454
+
455
+ /**
456
+ * @callback GetClassJsdoc
457
+ * @returns {null|JsdocBlockWithInline}
458
+ */
459
+
460
+ /**
461
+ * @callback ClassHasTag
462
+ * @param {string} tagName
463
+ * @returns {boolean}
464
+ */
465
+
466
+ /**
467
+ * @callback FindContext
468
+ * @param {Context[]} contexts
469
+ * @param {string|undefined} comment
470
+ * @returns {{
471
+ * foundContext: Context|undefined,
472
+ * contextStr: string
473
+ * }}
474
+ */
475
+
476
+ /**
477
+ * @typedef {BasicUtils & {
478
+ * isIteratingFunction: IsIteratingFunction,
479
+ * isIteratingFunctionOrVariable: IsIteratingFunction,
480
+ * isVirtualFunction: IsVirtualFunction,
481
+ * stringify: Stringify,
482
+ * reportJSDoc: ReportJSDoc,
483
+ * getRegexFromString: GetRegexFromString,
484
+ * getTagDescription: GetTagDescription,
485
+ * setTagDescription: SetTagDescription,
486
+ * getDescription: GetDescription,
487
+ * setBlockDescription: SetBlockDescription,
488
+ * setDescriptionLines: SetDescriptionLines,
489
+ * changeTag: ChangeTag,
490
+ * setTag: SetTag,
491
+ * removeTag: RemoveTag,
492
+ * addTag: AddTag,
493
+ * getFirstLine: GetFirstLine,
494
+ * seedTokens: SeedTokens,
495
+ * emptyTokens: EmptyTokens,
496
+ * addLine: AddLine,
497
+ * addLines: AddLines,
498
+ * makeMultiline: MakeMultiline,
499
+ * flattenRoots: import('./jsdocUtils.js').FlattenRoots,
500
+ * getFunctionParameterNames: GetFunctionParameterNames,
501
+ * hasParams: HasParams,
502
+ * isGenerator: IsGenerator,
503
+ * isConstructor: IsConstructor,
504
+ * getJsdocTagsDeep: GetJsdocTagsDeep,
505
+ * getPreferredTagName: GetPreferredTagName,
506
+ * isValidTag: IsValidTag,
507
+ * hasATag: HasATag,
508
+ * hasTag: HasTag,
509
+ * comparePaths: ComparePaths,
510
+ * dropPathSegmentQuotes: DropPathSegmentQuotes,
511
+ * avoidDocs: AvoidDocs,
512
+ * tagMightHaveNamePosition: TagMightHaveNamePositionTypePosition,
513
+ * tagMightHaveTypePosition: TagMightHaveNamePositionTypePosition,
514
+ * tagMustHaveNamePosition: TagMustHave,
515
+ * tagMustHaveTypePosition: TagMustHave,
516
+ * tagMissingRequiredTypeOrNamepath: TagMissingRequiredTypeOrNamepath,
517
+ * isNamepathDefiningTag: IsNamepathX,
518
+ * isNamepathReferencingTag: IsNamepathX,
519
+ * isNamepathOrUrlReferencingTag: IsNamepathX,
520
+ * tagMightHaveNamepath: IsNamepathX,
521
+ * getTagStructureForMode: GetTagStructureForMode,
522
+ * mayBeUndefinedTypeTag: MayBeUndefinedTypeTag,
523
+ * hasValueOrExecutorHasNonEmptyResolveValue: HasValueOrExecutorHasNonEmptyResolveValue,
524
+ * hasYieldValue: HasYieldValue,
525
+ * hasYieldReturnValue: HasYieldReturnValue,
526
+ * hasThrowValue: HasThrowValue,
527
+ * isAsync: IsAsync,
528
+ * getTags: GetTags,
529
+ * getPresentTags: GetPresentTags,
530
+ * filterTags: FilterTags,
531
+ * filterAllTags: FilterAllTags,
532
+ * getTagsByType: GetTagsByType,
533
+ * hasOptionTag: HasOptionTag,
534
+ * getClassNode: GetClassNode,
535
+ * getClassJsdoc: GetClassJsdoc,
536
+ * classHasTag: ClassHasTag,
537
+ * findContext: FindContext
538
+ * }} Utils
539
+ */
540
+
541
+ const {
542
+ rewireSpecs,
543
+ seedTokens,
544
+ } = util;
545
+
546
+ // todo: Change these `any` types once importing types properly.
547
+
548
+ /**
549
+ * Should use ESLint rule's typing.
550
+ * @typedef {import('eslint').Rule.RuleMetaData} EslintRuleMeta
551
+ */
552
+
553
+ /**
554
+ * A plain object for tracking state as needed by rules across iterations.
555
+ * @typedef {{
556
+ * globalTags: {},
557
+ * hasDuplicates: {
558
+ * [key: string]: boolean
559
+ * },
560
+ * selectorMap: {
561
+ * [selector: string]: {
562
+ * [comment: string]: Integer
563
+ * }
564
+ * },
565
+ * hasTag: {
566
+ * [key: string]: boolean
567
+ * },
568
+ * hasNonComment: number,
569
+ * hasNonCommentBeforeTag: {
570
+ * [key: string]: boolean|number
571
+ * }
572
+ * }} StateObject
573
+ */
574
+
575
+ /**
576
+ * The Node AST as supplied by the parser.
577
+ * @typedef {import('eslint').Rule.Node} Node
578
+ */
579
+
580
+ /*
581
+ const {
582
+ align as commentAlign,
583
+ flow: commentFlow,
584
+ indent: commentIndent,
585
+ } = transforms;
586
+ */
587
+
588
+ const globalState = new Map();
589
+ /**
590
+ * @param {import('eslint').Rule.RuleContext} context
591
+ * @param {{
592
+ * tagNamePreference?: import('./jsdocUtils.js').TagNamePreference,
593
+ * mode?: import('./jsdocUtils.js').ParserMode
594
+ * }} cfg
595
+ * @returns {BasicUtils}
596
+ */
597
+ const getBasicUtils = (context, {
598
+ mode,
599
+ tagNamePreference,
600
+ }) => {
601
+ /** @type {BasicUtils} */
602
+ const utils = {};
603
+
604
+ /** @type {ReportSettings} */
605
+ utils.reportSettings = (message) => {
606
+ context.report({
607
+ loc: {
608
+ end: {
609
+ column: 1,
610
+ line: 1,
611
+ },
612
+ start: {
613
+ column: 1,
614
+ line: 1,
615
+ },
616
+ },
617
+ message,
618
+ });
619
+ };
620
+
621
+ /** @type {ParseClosureTemplateTag} */
622
+ utils.parseClosureTemplateTag = (tag) => {
623
+ return jsdocUtils.parseClosureTemplateTag(tag);
624
+ };
625
+
626
+ utils.pathDoesNotBeginWith = jsdocUtils.pathDoesNotBeginWith;
627
+
628
+ /** @type {GetPreferredTagNameObject} */
629
+ utils.getPreferredTagNameObject = ({
630
+ tagName,
631
+ }) => {
632
+ const ret = jsdocUtils.getPreferredTagNameSimple(
633
+ tagName,
634
+ /** @type {import('./jsdocUtils.js').ParserMode} */ (mode),
635
+ tagNamePreference,
636
+ context,
637
+ );
638
+ const isObject = ret && typeof ret === 'object';
639
+ if (ret === false || (isObject && !ret.replacement)) {
640
+ return {
641
+ blocked: true,
642
+ tagName,
643
+ };
644
+ }
645
+
646
+ return ret;
647
+ };
648
+
649
+ return utils;
650
+ };
651
+
652
+ /**
653
+ * @callback Report
654
+ * @param {string} message
655
+ * @param {import('eslint').Rule.ReportFixer|null} [fix]
656
+ * @param {null|
657
+ * {line?: Integer, column?: Integer}|
658
+ * import('comment-parser').Spec & {line?: Integer}
659
+ * } [jsdocLoc]
660
+ * @param {undefined|{
661
+ * [key: string]: string
662
+ * }} [data]
663
+ * @returns {void}
664
+ */
665
+
666
+ /**
667
+ * @param {Node|null} node
668
+ * @param {JsdocBlockWithInline} jsdoc
669
+ * @param {import('eslint').AST.Token} jsdocNode
670
+ * @param {Settings} settings
671
+ * @param {Report} report
672
+ * @param {import('eslint').Rule.RuleContext} context
673
+ * @param {import('eslint').SourceCode} sc
674
+ * @param {boolean|undefined} iteratingAll
675
+ * @param {RuleConfig} ruleConfig
676
+ * @param {string} indent
677
+ * @returns {Utils}
678
+ */
679
+ const getUtils = (
680
+ node,
681
+ jsdoc,
682
+ jsdocNode,
683
+ settings,
684
+ report,
685
+ context,
686
+ sc,
687
+ iteratingAll,
688
+ ruleConfig,
689
+ indent,
690
+ ) => {
691
+ const ancestors = /** @type {import('eslint').Rule.Node[]} */ (node ?
692
+ (sc.getAncestors ?
693
+ (
694
+ sc.getAncestors(node)
695
+ /* c8 ignore next 4 */
696
+ ) :
697
+ (
698
+ context.getAncestors()
699
+ )) :
700
+ []);
701
+
702
+ /* c8 ignore next -- Fallback to deprecated method */
703
+ const {
704
+ sourceCode = context.getSourceCode(),
705
+ } = context;
706
+
707
+ const utils = /** @type {Utils} */ (getBasicUtils(context, settings));
708
+
709
+ const {
710
+ augmentsExtendsReplacesDocs,
711
+ ignoreReplacesDocs,
712
+ implementsReplacesDocs,
713
+ maxLines,
714
+ minLines,
715
+ mode,
716
+ overrideReplacesDocs,
717
+ tagNamePreference,
718
+ } = settings;
719
+
720
+ const functionTypes = [
721
+ 'ArrowFunctionExpression',
722
+ 'FunctionDeclaration',
723
+ 'FunctionExpression',
724
+ 'MethodDefinition',
725
+ ];
726
+
727
+ /** @type {IsIteratingFunction} */
728
+ utils.isIteratingFunction = () => {
729
+ return !iteratingAll || functionTypes.includes(String(node?.type));
730
+ };
731
+
732
+ /** @type {IsIteratingFunction} */
733
+ utils.isIteratingFunctionOrVariable = () => {
734
+ if (utils.isIteratingFunction()) {
735
+ return true;
736
+ }
737
+
738
+ /** @type {import('estree').VariableDeclarator[]} */
739
+ const declarations = node?.type === 'VariableDeclaration' ?
740
+ node.declarations :
741
+ (node?.type === 'ExportNamedDeclaration' && node.declaration?.type === 'VariableDeclaration' ?
742
+ node.declaration.declarations :
743
+ []);
744
+
745
+ return declarations.some(({
746
+ init,
747
+ }) => {
748
+ return functionTypes.includes(String(init?.type));
749
+ });
750
+ };
751
+
752
+ /** @type {IsVirtualFunction} */
753
+ utils.isVirtualFunction = () => {
754
+ return Boolean(iteratingAll) && utils.hasATag([
755
+ 'callback', 'function', 'func', 'method',
756
+ ]);
757
+ };
758
+
759
+ /** @type {Stringify} */
760
+ utils.stringify = (tagBlock, specRewire) => {
761
+ let block;
762
+ if (specRewire) {
763
+ block = rewireSpecs(tagBlock);
764
+ }
765
+
766
+ return commentStringify(/** @type {import('comment-parser').Block} */ (
767
+ specRewire ? block : tagBlock));
768
+ };
769
+
770
+ /** @type {ReportJSDoc} */
771
+ utils.reportJSDoc = (msg, tag, handler, specRewire, data) => {
772
+ report(msg, handler ? /** @type {import('eslint').Rule.ReportFixer} */ (
773
+ fixer,
774
+ ) => {
775
+ handler();
776
+ const replacement = utils.stringify(jsdoc, specRewire);
777
+
778
+ if (!replacement) {
779
+ const text = sourceCode.getText();
780
+ const lastLineBreakPos = text.slice(
781
+ 0, jsdocNode.range[0],
782
+ ).search(/\n[ \t]*$/v);
783
+ if (lastLineBreakPos > -1) {
784
+ return fixer.removeRange([
785
+ lastLineBreakPos, jsdocNode.range[1],
786
+ ]);
787
+ }
788
+
789
+ return fixer.removeRange(
790
+ (/\s/v).test(text.charAt(jsdocNode.range[1])) ?
791
+ [
792
+ jsdocNode.range[0], jsdocNode.range[1] + 1,
793
+ ] :
794
+ jsdocNode.range,
795
+ );
796
+ }
797
+
798
+ return fixer.replaceText(jsdocNode, replacement);
799
+ } : null, tag, data);
800
+ };
801
+
802
+ /** @type {GetRegexFromString} */
803
+ utils.getRegexFromString = (str, requiredFlags) => {
804
+ return jsdocUtils.getRegexFromString(str, requiredFlags);
805
+ };
806
+
807
+ /** @type {GetTagDescription} */
808
+ utils.getTagDescription = (tg, returnArray) => {
809
+ return jsdocUtils.getTagDescription(tg, returnArray);
810
+ };
811
+
812
+ /** @type {SetTagDescription} */
813
+ utils.setTagDescription = (tg, matcher, setter) => {
814
+ let finalIdx = 0;
815
+ tg.source.some(({
816
+ tokens: {
817
+ description,
818
+ },
819
+ }, idx) => {
820
+ if (description && matcher.test(description)) {
821
+ tg.source[idx].tokens.description = setter(description);
822
+ finalIdx = idx;
823
+ return true;
824
+ }
825
+
826
+ return false;
827
+ });
828
+
829
+ return finalIdx;
830
+ };
831
+
832
+ /** @type {GetDescription} */
833
+ utils.getDescription = () => {
834
+ /** @type {string[]} */
835
+ const descriptions = [];
836
+ let lastDescriptionLine = 0;
837
+ let tagsBegun = false;
838
+ jsdoc.source.some(({
839
+ tokens: {
840
+ description,
841
+ end,
842
+ tag,
843
+ },
844
+ }, idx) => {
845
+ if (tag) {
846
+ tagsBegun = true;
847
+ }
848
+
849
+ if (idx && (tag || end)) {
850
+ lastDescriptionLine = idx - 1;
851
+ if (!tagsBegun && description) {
852
+ descriptions.push(description);
853
+ }
854
+
855
+ return true;
856
+ }
857
+
858
+ if (!tagsBegun && (idx || description)) {
859
+ descriptions.push(description || (descriptions.length ? '' : '\n'));
860
+ }
861
+
862
+ return false;
863
+ });
864
+
865
+ return {
866
+ description: descriptions.join('\n'),
867
+ descriptions,
868
+ lastDescriptionLine,
869
+ };
870
+ };
871
+
872
+ /** @type {SetBlockDescription} */
873
+ utils.setBlockDescription = (setter) => {
874
+ /** @type {string[]} */
875
+ const descLines = [];
876
+ /**
877
+ * @type {undefined|Integer}
878
+ */
879
+ let startIdx;
880
+ /**
881
+ * @type {undefined|Integer}
882
+ */
883
+ let endIdx;
884
+
885
+ /**
886
+ * @type {undefined|{
887
+ * delimiter: string,
888
+ * postDelimiter: string,
889
+ * start: string
890
+ * }}
891
+ */
892
+ let info;
893
+
894
+ jsdoc.source.some(({
895
+ tokens: {
896
+ delimiter,
897
+ description,
898
+ end,
899
+ postDelimiter,
900
+ start,
901
+ tag,
902
+ },
903
+ }, idx) => {
904
+ if (delimiter === '/**') {
905
+ return false;
906
+ }
907
+
908
+ if (startIdx === undefined) {
909
+ startIdx = idx;
910
+ info = {
911
+ delimiter,
912
+ postDelimiter,
913
+ start,
914
+ };
915
+ }
916
+
917
+ if (tag || end) {
918
+ endIdx = idx;
919
+ return true;
920
+ }
921
+
922
+ descLines.push(description);
923
+ return false;
924
+ });
925
+
926
+ /* c8 ignore else -- Won't be called if missing */
927
+ if (descLines.length) {
928
+ jsdoc.source.splice(
929
+ /** @type {Integer} */ (startIdx),
930
+ /** @type {Integer} */ (endIdx) - /** @type {Integer} */ (startIdx),
931
+ ...setter(
932
+ /**
933
+ * @type {{
934
+ * delimiter: string,
935
+ * postDelimiter: string,
936
+ * start: string
937
+ * }}
938
+ */
939
+ (info),
940
+ seedTokens,
941
+ descLines,
942
+ ),
943
+ );
944
+ }
945
+ };
946
+
947
+ /** @type {SetDescriptionLines} */
948
+ utils.setDescriptionLines = (matcher, setter) => {
949
+ let finalIdx = 0;
950
+ jsdoc.source.some(({
951
+ tokens: {
952
+ description,
953
+ end,
954
+ tag,
955
+ },
956
+ }, idx) => {
957
+ /* c8 ignore next 3 -- Already checked */
958
+ if (idx && (tag || end)) {
959
+ return true;
960
+ }
961
+
962
+ if (description && matcher.test(description)) {
963
+ jsdoc.source[idx].tokens.description = setter(description);
964
+ finalIdx = idx;
965
+ return true;
966
+ }
967
+
968
+ return false;
969
+ });
970
+
971
+ return finalIdx;
972
+ };
973
+
974
+ /** @type {ChangeTag} */
975
+ utils.changeTag = (tag, ...tokens) => {
976
+ for (const [
977
+ idx,
978
+ src,
979
+ ] of tag.source.entries()) {
980
+ src.tokens = {
981
+ ...src.tokens,
982
+ ...tokens[idx],
983
+ };
984
+ }
985
+ };
986
+
987
+ /** @type {SetTag} */
988
+ utils.setTag = (tag, tokens) => {
989
+ tag.source = [
990
+ {
991
+ number: tag.line,
992
+ // Or tag.source[0].number?
993
+ source: '',
994
+ tokens: seedTokens({
995
+ delimiter: '*',
996
+ postDelimiter: ' ',
997
+ start: indent + ' ',
998
+ tag: '@' + tag.tag,
999
+ ...tokens,
1000
+ }),
1001
+ },
1002
+ ];
1003
+ };
1004
+
1005
+ /** @type {RemoveTag} */
1006
+ utils.removeTag = (tagIndex, {
1007
+ removeEmptyBlock = false,
1008
+ tagSourceOffset = 0,
1009
+ } = {}) => {
1010
+ const {
1011
+ source: tagSource,
1012
+ } = jsdoc.tags[tagIndex];
1013
+ /** @type {Integer|undefined} */
1014
+ let lastIndex;
1015
+ const firstNumber = jsdoc.source[0].number;
1016
+ tagSource.some(({
1017
+ number,
1018
+ }, tagIdx) => {
1019
+ const sourceIndex = jsdoc.source.findIndex(({
1020
+ number: srcNumber,
1021
+ }) => {
1022
+ return number === srcNumber;
1023
+ });
1024
+ // c8 ignore else
1025
+ if (sourceIndex > -1) {
1026
+ let spliceCount = 1;
1027
+ tagSource.slice(tagIdx + 1).some(({
1028
+ tokens: {
1029
+ end: ending,
1030
+ tag,
1031
+ },
1032
+ }) => {
1033
+ if (!tag && !ending) {
1034
+ spliceCount++;
1035
+
1036
+ return false;
1037
+ }
1038
+
1039
+ return true;
1040
+ });
1041
+
1042
+ const spliceIdx = sourceIndex + tagSourceOffset;
1043
+
1044
+ const {
1045
+ delimiter,
1046
+ end,
1047
+ } = jsdoc.source[spliceIdx].tokens;
1048
+
1049
+ if (
1050
+ spliceIdx === 0 && jsdoc.tags.length >= 2 ||
1051
+ !removeEmptyBlock && (end || delimiter === '/**')
1052
+ ) {
1053
+ const {
1054
+ tokens,
1055
+ } = jsdoc.source[spliceIdx];
1056
+ for (const item of [
1057
+ 'postDelimiter',
1058
+ 'tag',
1059
+ 'postTag',
1060
+ 'type',
1061
+ 'postType',
1062
+ 'name',
1063
+ 'postName',
1064
+ 'description',
1065
+ ]) {
1066
+ tokens[
1067
+ /**
1068
+ * @type {"postDelimiter"|"tag"|"type"|"postType"|
1069
+ * "postTag"|"name"|"postName"|"description"}
1070
+ */ (
1071
+ item
1072
+ )
1073
+ ] = '';
1074
+ }
1075
+ } else {
1076
+ jsdoc.source.splice(spliceIdx, spliceCount - tagSourceOffset + (spliceIdx ? 0 : jsdoc.source.length));
1077
+ tagSource.splice(tagIdx + tagSourceOffset, spliceCount - tagSourceOffset + (spliceIdx ? 0 : jsdoc.source.length));
1078
+ }
1079
+
1080
+ lastIndex = sourceIndex;
1081
+
1082
+ return true;
1083
+ }
1084
+ /* c8 ignore next 2 */
1085
+ // eslint-disable-next-line @stylistic/padding-line-between-statements -- c8
1086
+ return false;
1087
+ });
1088
+ for (const [
1089
+ idx,
1090
+ src,
1091
+ ] of jsdoc.source.slice(lastIndex).entries()) {
1092
+ src.number = firstNumber + /** @type {Integer} */ (lastIndex) + idx;
1093
+ }
1094
+
1095
+ // Todo: Once rewiring of tags may be fixed in comment-parser to reflect
1096
+ // missing tags, this step should be added here (so that, e.g.,
1097
+ // if accessing `jsdoc.tags`, such as to add a new tag, the
1098
+ // correct information will be available)
1099
+ };
1100
+
1101
+ /** @type {AddTag} */
1102
+ utils.addTag = (
1103
+ targetTagName,
1104
+ number = (jsdoc.tags[jsdoc.tags.length - 1]?.source[0]?.number ?? jsdoc.source.findIndex(({
1105
+ tokens: {
1106
+ tag,
1107
+ },
1108
+ }) => {
1109
+ return tag;
1110
+ }) - 1) + 1,
1111
+ tokens = {},
1112
+ ) => {
1113
+ jsdoc.source.splice(number, 0, {
1114
+ number,
1115
+ source: '',
1116
+ tokens: seedTokens({
1117
+ delimiter: '*',
1118
+ postDelimiter: ' ',
1119
+ start: indent + ' ',
1120
+ tag: `@${targetTagName}`,
1121
+ ...tokens,
1122
+ }),
1123
+ });
1124
+ for (const src of jsdoc.source.slice(number + 1)) {
1125
+ src.number++;
1126
+ }
1127
+ };
1128
+
1129
+ /** @type {GetFirstLine} */
1130
+ utils.getFirstLine = () => {
1131
+ let firstLine;
1132
+ for (const {
1133
+ number,
1134
+ tokens: {
1135
+ tag,
1136
+ },
1137
+ } of jsdoc.source) {
1138
+ if (tag) {
1139
+ firstLine = number;
1140
+ break;
1141
+ }
1142
+ }
1143
+
1144
+ return firstLine;
1145
+ };
1146
+
1147
+ /** @type {SeedTokens} */
1148
+ utils.seedTokens = seedTokens;
1149
+
1150
+ /** @type {EmptyTokens} */
1151
+ utils.emptyTokens = (tokens) => {
1152
+ for (const prop of [
1153
+ 'start',
1154
+ 'postDelimiter',
1155
+ 'tag',
1156
+ 'type',
1157
+ 'postType',
1158
+ 'postTag',
1159
+ 'name',
1160
+ 'postName',
1161
+ 'description',
1162
+ 'end',
1163
+ 'lineEnd',
1164
+ ]) {
1165
+ tokens[
1166
+ /**
1167
+ * @type {"start"|"postDelimiter"|"tag"|"type"|"postType"|
1168
+ * "postTag"|"name"|"postName"|"description"|"end"|"lineEnd"}
1169
+ */ (
1170
+ prop
1171
+ )
1172
+ ] = '';
1173
+ }
1174
+ };
1175
+
1176
+ /** @type {AddLine} */
1177
+ utils.addLine = (sourceIndex, tokens) => {
1178
+ const number = (jsdoc.source[sourceIndex - 1]?.number || 0) + 1;
1179
+ jsdoc.source.splice(sourceIndex, 0, {
1180
+ number,
1181
+ source: '',
1182
+ tokens: seedTokens(tokens),
1183
+ });
1184
+
1185
+ for (const src of jsdoc.source.slice(number + 1)) {
1186
+ src.number++;
1187
+ }
1188
+ // If necessary, we can rewire the tags (misnamed method)
1189
+ // rewireSource(jsdoc);
1190
+ };
1191
+
1192
+ /** @type {AddLines} */
1193
+ utils.addLines = (tagIndex, tagSourceOffset, numLines) => {
1194
+ const {
1195
+ source: tagSource,
1196
+ } = jsdoc.tags[tagIndex];
1197
+ /** @type {Integer|undefined} */
1198
+ let lastIndex;
1199
+ const firstNumber = jsdoc.source[0].number;
1200
+ tagSource.some(({
1201
+ number,
1202
+ }) => {
1203
+ const makeLine = () => {
1204
+ return {
1205
+ number,
1206
+ source: '',
1207
+ tokens: seedTokens({
1208
+ delimiter: '*',
1209
+ start: indent + ' ',
1210
+ }),
1211
+ };
1212
+ };
1213
+
1214
+ const makeLines = () => {
1215
+ return Array.from({
1216
+ length: numLines,
1217
+ }, makeLine);
1218
+ };
1219
+
1220
+ const sourceIndex = jsdoc.source.findIndex(({
1221
+ number: srcNumber,
1222
+ tokens: {
1223
+ end,
1224
+ },
1225
+ }) => {
1226
+ return number === srcNumber && !end;
1227
+ });
1228
+ // c8 ignore else
1229
+ if (sourceIndex > -1) {
1230
+ const lines = makeLines();
1231
+ jsdoc.source.splice(sourceIndex + tagSourceOffset, 0, ...lines);
1232
+
1233
+ // tagSource.splice(tagIdx + 1, 0, ...makeLines());
1234
+ lastIndex = sourceIndex;
1235
+
1236
+ return true;
1237
+ }
1238
+ /* c8 ignore next 2 */
1239
+ // eslint-disable-next-line @stylistic/padding-line-between-statements -- c8
1240
+ return false;
1241
+ });
1242
+
1243
+ for (const [
1244
+ idx,
1245
+ src,
1246
+ ] of jsdoc.source.slice(lastIndex).entries()) {
1247
+ src.number = firstNumber + /** @type {Integer} */ (lastIndex) + idx;
1248
+ }
1249
+ };
1250
+
1251
+ /** @type {MakeMultiline} */
1252
+ utils.makeMultiline = () => {
1253
+ const {
1254
+ source: [
1255
+ {
1256
+ tokens,
1257
+ },
1258
+ ],
1259
+ } = jsdoc;
1260
+ const {
1261
+ description,
1262
+ lineEnd,
1263
+ name,
1264
+ postDelimiter,
1265
+ tag,
1266
+ type,
1267
+ } = tokens;
1268
+
1269
+ let {
1270
+ tokens: {
1271
+ postName,
1272
+ postTag,
1273
+ postType,
1274
+ },
1275
+ } = jsdoc.source[0];
1276
+
1277
+ // Strip trailing leftovers from single line ending
1278
+ if (!description) {
1279
+ if (postName) {
1280
+ postName = '';
1281
+ } else if (postType) {
1282
+ postType = '';
1283
+ } else /* c8 ignore else -- `comment-parser` prevents empty blocks currently per https://github.com/syavorsky/comment-parser/issues/128 */ if (postTag) {
1284
+ postTag = '';
1285
+ }
1286
+ }
1287
+
1288
+ utils.emptyTokens(tokens);
1289
+
1290
+ utils.addLine(1, {
1291
+ delimiter: '*',
1292
+
1293
+ // If a description were present, it may have whitespace attached
1294
+ // due to being at the end of the single line
1295
+ description: description.trimEnd(),
1296
+ name,
1297
+ postDelimiter,
1298
+ postName,
1299
+ postTag,
1300
+ postType,
1301
+ start: indent + ' ',
1302
+ tag,
1303
+ type,
1304
+ });
1305
+ utils.addLine(2, {
1306
+ end: '*/',
1307
+ lineEnd,
1308
+ start: indent + ' ',
1309
+ });
1310
+ };
1311
+
1312
+ /**
1313
+ * @type {import('./jsdocUtils.js').FlattenRoots}
1314
+ */
1315
+ utils.flattenRoots = jsdocUtils.flattenRoots;
1316
+
1317
+ /** @type {GetFunctionParameterNames} */
1318
+ utils.getFunctionParameterNames = (useDefaultObjectProperties) => {
1319
+ return jsdocUtils.getFunctionParameterNames(node, useDefaultObjectProperties);
1320
+ };
1321
+
1322
+ /** @type {HasParams} */
1323
+ utils.hasParams = () => {
1324
+ return jsdocUtils.hasParams(/** @type {Node} */ (node));
1325
+ };
1326
+
1327
+ /** @type {IsGenerator} */
1328
+ utils.isGenerator = () => {
1329
+ return node !== null && Boolean(
1330
+ /**
1331
+ * @type {import('estree').FunctionDeclaration|
1332
+ * import('estree').FunctionExpression}
1333
+ */ (node).generator ||
1334
+ node.type === 'MethodDefinition' && node.value.generator ||
1335
+ [
1336
+ 'ExportDefaultDeclaration', 'ExportNamedDeclaration',
1337
+ ].includes(node.type) &&
1338
+ /** @type {import('estree').FunctionDeclaration} */
1339
+ (
1340
+ /**
1341
+ * @type {import('estree').ExportNamedDeclaration|
1342
+ * import('estree').ExportDefaultDeclaration}
1343
+ */ (node).declaration
1344
+ )?.generator,
1345
+ );
1346
+ };
1347
+
1348
+ /** @type {IsConstructor} */
1349
+ utils.isConstructor = () => {
1350
+ return jsdocUtils.isConstructor(/** @type {Node} */ (node));
1351
+ };
1352
+
1353
+ /** @type {GetJsdocTagsDeep} */
1354
+ utils.getJsdocTagsDeep = (tagName) => {
1355
+ const name = /** @type {string|false} */ (utils.getPreferredTagName({
1356
+ tagName,
1357
+ }));
1358
+ if (!name) {
1359
+ return false;
1360
+ }
1361
+
1362
+ return jsdocUtils.getJsdocTagsDeep(jsdoc, name);
1363
+ };
1364
+
1365
+ /** @type {GetPreferredTagName} */
1366
+ utils.getPreferredTagName = (args) => {
1367
+ return jsdocUtils.getPreferredTagName(
1368
+ jsdoc, {
1369
+ ...args,
1370
+ context,
1371
+ mode,
1372
+ report,
1373
+ tagNamePreference,
1374
+ },
1375
+ );
1376
+ };
1377
+
1378
+ /** @type {IsValidTag} */
1379
+ utils.isValidTag = (name, definedTags) => {
1380
+ return jsdocUtils.isValidTag(context, mode, name, definedTags);
1381
+ };
1382
+
1383
+ /** @type {HasATag} */
1384
+ utils.hasATag = (names) => {
1385
+ return jsdocUtils.hasATag(jsdoc, names);
1386
+ };
1387
+
1388
+ /** @type {HasTag} */
1389
+ utils.hasTag = (name) => {
1390
+ return jsdocUtils.hasTag(jsdoc, name);
1391
+ };
1392
+
1393
+ /** @type {ComparePaths} */
1394
+ utils.comparePaths = (name) => {
1395
+ return jsdocUtils.comparePaths(name);
1396
+ };
1397
+
1398
+ /** @type {DropPathSegmentQuotes} */
1399
+ utils.dropPathSegmentQuotes = (name) => {
1400
+ return jsdocUtils.dropPathSegmentQuotes(name);
1401
+ };
1402
+
1403
+ /** @type {AvoidDocs} */
1404
+ utils.avoidDocs = () => {
1405
+ if (
1406
+ ignoreReplacesDocs !== false &&
1407
+ (utils.hasTag('ignore') || utils.classHasTag('ignore')) ||
1408
+ overrideReplacesDocs !== false &&
1409
+ (utils.hasTag('override') || utils.classHasTag('override')) ||
1410
+ implementsReplacesDocs !== false &&
1411
+ (utils.hasTag('implements') || utils.classHasTag('implements')) ||
1412
+
1413
+ augmentsExtendsReplacesDocs &&
1414
+ (utils.hasATag([
1415
+ 'augments', 'extends',
1416
+ ]) ||
1417
+ utils.classHasTag('augments') ||
1418
+ utils.classHasTag('extends'))) {
1419
+ return true;
1420
+ }
1421
+
1422
+ if (jsdocUtils.exemptSpeciaMethods(
1423
+ jsdoc,
1424
+ node,
1425
+ context,
1426
+ /** @type {import('json-schema').JSONSchema4|import('json-schema').JSONSchema4[]} */ (
1427
+ ruleConfig.meta.schema
1428
+ ),
1429
+ )) {
1430
+ return true;
1431
+ }
1432
+
1433
+ const exemptedBy = context.options[0]?.exemptedBy ?? [
1434
+ 'inheritDoc',
1435
+ ...mode === 'closure' ? [] : [
1436
+ 'inheritdoc',
1437
+ ],
1438
+ ];
1439
+ if (exemptedBy.length && utils.getPresentTags(exemptedBy).length) {
1440
+ return true;
1441
+ }
1442
+
1443
+ return false;
1444
+ };
1445
+
1446
+ for (const method of [
1447
+ 'tagMightHaveNamePosition',
1448
+ 'tagMightHaveTypePosition',
1449
+ ]) {
1450
+ /** @type {TagMightHaveNamePositionTypePosition} */
1451
+ utils[
1452
+ /** @type {"tagMightHaveNamePosition"|"tagMightHaveTypePosition"} */ (
1453
+ method
1454
+ )
1455
+ ] = (tagName, otherModeMaps) => {
1456
+ const result = jsdocUtils[
1457
+ /** @type {"tagMightHaveNamePosition"|"tagMightHaveTypePosition"} */
1458
+ (method)
1459
+ ](tagName);
1460
+ if (result) {
1461
+ return true;
1462
+ }
1463
+
1464
+ if (!otherModeMaps) {
1465
+ return false;
1466
+ }
1467
+
1468
+ const otherResult = otherModeMaps.some((otherModeMap) => {
1469
+ return jsdocUtils[
1470
+ /** @type {"tagMightHaveNamePosition"|"tagMightHaveTypePosition"} */
1471
+ (method)
1472
+ ](tagName, otherModeMap);
1473
+ });
1474
+
1475
+ return otherResult ? {
1476
+ otherMode: true,
1477
+ } : false;
1478
+ };
1479
+ }
1480
+
1481
+ /** @type {TagMissingRequiredTypeOrNamepath} */
1482
+ utils.tagMissingRequiredTypeOrNamepath = (tagName, otherModeMaps) => {
1483
+ const result = jsdocUtils.tagMissingRequiredTypeOrNamepath(tagName);
1484
+ if (!result) {
1485
+ return false;
1486
+ }
1487
+
1488
+ const otherResult = otherModeMaps.every((otherModeMap) => {
1489
+ return jsdocUtils.tagMissingRequiredTypeOrNamepath(tagName, otherModeMap);
1490
+ });
1491
+
1492
+ return otherResult ? true : {
1493
+ otherMode: false,
1494
+ };
1495
+ };
1496
+
1497
+ for (const method of [
1498
+ 'tagMustHaveNamePosition',
1499
+ 'tagMustHaveTypePosition',
1500
+ ]) {
1501
+ /** @type {TagMustHave} */
1502
+ utils[
1503
+ /** @type {"tagMustHaveNamePosition"|"tagMustHaveTypePosition"} */
1504
+ (method)
1505
+ ] = (tagName, otherModeMaps) => {
1506
+ const result = jsdocUtils[
1507
+ /** @type {"tagMustHaveNamePosition"|"tagMustHaveTypePosition"} */
1508
+ (method)
1509
+ ](tagName);
1510
+ if (!result) {
1511
+ return false;
1512
+ }
1513
+
1514
+ // if (!otherModeMaps) { return true; }
1515
+
1516
+ const otherResult = otherModeMaps.every((otherModeMap) => {
1517
+ return jsdocUtils[
1518
+ /** @type {"tagMustHaveNamePosition"|"tagMustHaveTypePosition"} */
1519
+ (method)
1520
+ ](tagName, otherModeMap);
1521
+ });
1522
+
1523
+ return otherResult ? true : {
1524
+ otherMode: false,
1525
+ };
1526
+ };
1527
+ }
1528
+
1529
+ for (const method of [
1530
+ 'isNamepathDefiningTag',
1531
+ 'isNamepathReferencingTag',
1532
+ 'isNamepathOrUrlReferencingTag',
1533
+ 'tagMightHaveNamepath',
1534
+ ]) {
1535
+ /** @type {IsNamepathX} */
1536
+ utils[
1537
+ /** @type {"isNamepathDefiningTag"|"isNamepathReferencingTag"|"isNamepathOrUrlReferencingTag"|"tagMightHaveNamepath"} */ (
1538
+ method
1539
+ )] = (tagName) => {
1540
+ return jsdocUtils[
1541
+ /** @type {"isNamepathDefiningTag"|"isNamepathReferencingTag"|"isNamepathOrUrlReferencingTag"|"tagMightHaveNamepath"} */
1542
+ (method)
1543
+ ](tagName);
1544
+ };
1545
+ }
1546
+
1547
+ /** @type {GetTagStructureForMode} */
1548
+ utils.getTagStructureForMode = (mde) => {
1549
+ return jsdocUtils.getTagStructureForMode(mde, settings.structuredTags);
1550
+ };
1551
+
1552
+ /** @type {MayBeUndefinedTypeTag} */
1553
+ utils.mayBeUndefinedTypeTag = (tag) => {
1554
+ return jsdocUtils.mayBeUndefinedTypeTag(tag, settings.mode);
1555
+ };
1556
+
1557
+ /** @type {HasValueOrExecutorHasNonEmptyResolveValue} */
1558
+ utils.hasValueOrExecutorHasNonEmptyResolveValue = (anyPromiseAsReturn, allBranches) => {
1559
+ return jsdocUtils.hasValueOrExecutorHasNonEmptyResolveValue(
1560
+ /** @type {Node} */ (node), anyPromiseAsReturn, allBranches,
1561
+ );
1562
+ };
1563
+
1564
+ /** @type {HasYieldValue} */
1565
+ utils.hasYieldValue = () => {
1566
+ if ([
1567
+ 'ExportDefaultDeclaration', 'ExportNamedDeclaration',
1568
+ ].includes(/** @type {Node} */ (node).type)) {
1569
+ return jsdocUtils.hasYieldValue(
1570
+ /** @type {import('estree').Declaration|import('estree').Expression} */ (
1571
+ /** @type {import('estree').ExportNamedDeclaration|import('estree').ExportDefaultDeclaration} */
1572
+ (node).declaration
1573
+ ),
1574
+ );
1575
+ }
1576
+
1577
+ return jsdocUtils.hasYieldValue(/** @type {Node} */ (node));
1578
+ };
1579
+
1580
+ /** @type {HasYieldReturnValue} */
1581
+ utils.hasYieldReturnValue = () => {
1582
+ return jsdocUtils.hasYieldValue(/** @type {Node} */ (node), true);
1583
+ };
1584
+
1585
+ /** @type {HasThrowValue} */
1586
+ utils.hasThrowValue = () => {
1587
+ return jsdocUtils.hasThrowValue(node);
1588
+ };
1589
+
1590
+ /** @type {IsAsync} */
1591
+ utils.isAsync = () => {
1592
+ return Boolean(node && 'async' in node && node.async);
1593
+ };
1594
+
1595
+ /** @type {GetTags} */
1596
+ utils.getTags = (tagName) => {
1597
+ return jsdocUtils.getTags(jsdoc, tagName);
1598
+ };
1599
+
1600
+ /** @type {GetPresentTags} */
1601
+ utils.getPresentTags = (tagList) => {
1602
+ return jsdocUtils.filterTags(jsdoc, (tag) => {
1603
+ return tagList.includes(tag.tag);
1604
+ });
1605
+ };
1606
+
1607
+ /** @type {FilterTags} */
1608
+ utils.filterTags = (filter) => {
1609
+ return jsdocUtils.filterTags(jsdoc, (tag) => {
1610
+ return filter(tag);
1611
+ });
1612
+ };
1613
+
1614
+ /** @type {FilterAllTags} */
1615
+ utils.filterAllTags = (filter) => {
1616
+ const tags = jsdocUtils.getAllTags(jsdoc);
1617
+ return tags.filter((tag) => {
1618
+ return filter(tag);
1619
+ });
1620
+ };
1621
+
1622
+ /** @type {GetTagsByType} */
1623
+ utils.getTagsByType = (tags) => {
1624
+ return jsdocUtils.getTagsByType(context, mode, tags);
1625
+ };
1626
+
1627
+ /** @type {HasOptionTag} */
1628
+ utils.hasOptionTag = (tagName) => {
1629
+ const {
1630
+ tags,
1631
+ } = context.options[0] ?? {};
1632
+
1633
+ return Boolean(tags && tags.includes(tagName));
1634
+ };
1635
+
1636
+ /** @type {GetClassNode} */
1637
+ utils.getClassNode = () => {
1638
+ return [
1639
+ ...ancestors, node,
1640
+ ].reverse().find((parent) => {
1641
+ return parent && [
1642
+ 'ClassDeclaration', 'ClassExpression',
1643
+ ].includes(parent.type);
1644
+ }) ?? null;
1645
+ };
1646
+
1647
+ /** @type {GetClassJsdoc} */
1648
+ utils.getClassJsdoc = () => {
1649
+ const classNode = utils.getClassNode();
1650
+
1651
+ if (!classNode) {
1652
+ return null;
1653
+ }
1654
+
1655
+ const classJsdocNode = getJSDocComment(sourceCode, classNode, {
1656
+ maxLines,
1657
+ minLines,
1658
+ });
1659
+
1660
+ if (classJsdocNode) {
1661
+ return parseComment(classJsdocNode, '');
1662
+ }
1663
+
1664
+ return null;
1665
+ };
1666
+
1667
+ /** @type {ClassHasTag} */
1668
+ utils.classHasTag = (tagName) => {
1669
+ const classJsdoc = utils.getClassJsdoc();
1670
+
1671
+ return classJsdoc !== null && jsdocUtils.hasTag(classJsdoc, tagName);
1672
+ };
1673
+
1674
+ /** @type {ForEachPreferredTag} */
1675
+ utils.forEachPreferredTag = (tagName, arrayHandler, skipReportingBlockedTag) => {
1676
+ return jsdocUtils.forEachPreferredTag(
1677
+ jsdoc, tagName, arrayHandler, {
1678
+ context,
1679
+ mode,
1680
+ report,
1681
+ skipReportingBlockedTag,
1682
+ tagNamePreference,
1683
+ },
1684
+ );
1685
+ };
1686
+
1687
+ /** @type {FindContext} */
1688
+ utils.findContext = (contexts, comment) => {
1689
+ const foundContext = contexts.find((cntxt) => {
1690
+ return typeof cntxt === 'string' ?
1691
+ esquery.matches(
1692
+ /** @type {Node} */ (node),
1693
+ esquery.parse(cntxt),
1694
+ undefined,
1695
+ {
1696
+ visitorKeys: sourceCode.visitorKeys,
1697
+ },
1698
+ ) :
1699
+ (!cntxt.context || cntxt.context === 'any' ||
1700
+ esquery.matches(
1701
+ /** @type {Node} */ (node),
1702
+ esquery.parse(cntxt.context),
1703
+ undefined,
1704
+ {
1705
+ visitorKeys: sourceCode.visitorKeys,
1706
+ },
1707
+ )) && comment === cntxt.comment;
1708
+ });
1709
+
1710
+ const contextStr = typeof foundContext === 'object' ?
1711
+ foundContext.context ?? 'any' :
1712
+ String(foundContext);
1713
+
1714
+ return {
1715
+ contextStr,
1716
+ foundContext,
1717
+ };
1718
+ };
1719
+
1720
+ return utils;
1721
+ };
1722
+
1723
+ /**
1724
+ * @typedef {{
1725
+ * [key: string]: false|string|{
1726
+ * message: string,
1727
+ * replacement?: false|string
1728
+ * skipRootChecking?: boolean
1729
+ * }
1730
+ * }} PreferredTypes
1731
+ */
1732
+ /**
1733
+ * @typedef {{
1734
+ * [key: string]: {
1735
+ * name?: "text"|"namepath-defining"|"namepath-referencing"|false,
1736
+ * type?: boolean|string[],
1737
+ * required?: ("name"|"type"|"typeOrNameRequired")[]
1738
+ * }
1739
+ * }} StructuredTags
1740
+ */
1741
+ /**
1742
+ * Settings from ESLint types.
1743
+ * @typedef {{
1744
+ * maxLines: Integer,
1745
+ * minLines: Integer,
1746
+ * tagNamePreference: import('./jsdocUtils.js').TagNamePreference,
1747
+ * mode: import('./jsdocUtils.js').ParserMode,
1748
+ * preferredTypes: PreferredTypes,
1749
+ * structuredTags: StructuredTags,
1750
+ * [name: string]: any,
1751
+ * contexts?: Context[]
1752
+ * }} Settings
1753
+ */
1754
+
1755
+ /**
1756
+ * @typedef {{
1757
+ * settings?: {
1758
+ * jsdoc?: {
1759
+ * ignorePrivate: boolean,
1760
+ * ignoreInternal: boolean,
1761
+ * maxLines: Integer,
1762
+ * minLines: Integer,
1763
+ * tagNamePreference: import('./jsdocUtils.js').TagNamePreference,
1764
+ * preferredTypes: PreferredTypes,
1765
+ * structuredTags: StructuredTags,
1766
+ * overrideReplacesDocs: boolean,
1767
+ * ignoreReplacesDocs: boolean,
1768
+ * implementsReplacesDocs: boolean,
1769
+ * augmentsExtendsReplacesDocs: boolean,
1770
+ * exemptDestructuredRootsFromChecks: boolean,
1771
+ * mode: import('./jsdocUtils.js').ParserMode,
1772
+ * contexts: Context[],
1773
+ * }
1774
+ * }
1775
+ * }} JSDocSettings
1776
+ */
1777
+
1778
+ /**
1779
+ * @param {import('eslint').Rule.RuleContext & JSDocSettings} context
1780
+ * @returns {Settings|false}
1781
+ */
1782
+ const getSettings = (context) => {
1783
+ /* eslint-disable perfectionist/sort-objects */
1784
+ const settings = {
1785
+ // All rules
1786
+ ignorePrivate: Boolean(context.settings.jsdoc?.ignorePrivate),
1787
+ ignoreInternal: Boolean(context.settings.jsdoc?.ignoreInternal),
1788
+ maxLines: Number(context.settings.jsdoc?.maxLines ?? 1),
1789
+ minLines: Number(context.settings.jsdoc?.minLines ?? 0),
1790
+
1791
+ // `check-tag-names` and many returns/param rules
1792
+ tagNamePreference: context.settings.jsdoc?.tagNamePreference ?? {},
1793
+
1794
+ // `check-types` and `no-undefined-types`
1795
+ preferredTypes: context.settings.jsdoc?.preferredTypes ?? {},
1796
+
1797
+ // `check-types`, `no-undefined-types`, `valid-types`
1798
+ structuredTags: context.settings.jsdoc?.structuredTags ?? {},
1799
+
1800
+ // `require-param`, `require-description`, `require-example`,
1801
+ // `require-returns`, `require-throw`, `require-yields`
1802
+ overrideReplacesDocs: context.settings.jsdoc?.overrideReplacesDocs,
1803
+ ignoreReplacesDocs: context.settings.jsdoc?.ignoreReplacesDocs,
1804
+ implementsReplacesDocs: context.settings.jsdoc?.implementsReplacesDocs,
1805
+ augmentsExtendsReplacesDocs: context.settings.jsdoc?.augmentsExtendsReplacesDocs,
1806
+
1807
+ // `require-param-type`, `require-param-description`
1808
+ exemptDestructuredRootsFromChecks: context.settings.jsdoc?.exemptDestructuredRootsFromChecks,
1809
+
1810
+ // Many rules, e.g., `check-tag-names`
1811
+ mode: context.settings.jsdoc?.mode ?? 'typescript',
1812
+
1813
+ // Many rules
1814
+ contexts: context.settings.jsdoc?.contexts,
1815
+ };
1816
+ /* eslint-enable perfectionist/sort-objects */
1817
+
1818
+ jsdocUtils.setTagStructure(settings.mode);
1819
+ try {
1820
+ jsdocUtils.overrideTagStructure(settings.structuredTags);
1821
+ } catch (error) {
1822
+ context.report({
1823
+ loc: {
1824
+ end: {
1825
+ column: 1,
1826
+ line: 1,
1827
+ },
1828
+ start: {
1829
+ column: 1,
1830
+ line: 1,
1831
+ },
1832
+ },
1833
+ message: /** @type {Error} */ (error).message,
1834
+ });
1835
+
1836
+ return false;
1837
+ }
1838
+
1839
+ return settings;
1840
+ };
1841
+
1842
+ /**
1843
+ * Create the report function
1844
+ * @callback MakeReport
1845
+ * @param {import('eslint').Rule.RuleContext} context
1846
+ * @param {import('estree').Node} commentNode
1847
+ * @returns {Report}
1848
+ */
1849
+
1850
+ /** @type {MakeReport} */
1851
+ const makeReport = (context, commentNode) => {
1852
+ /** @type {Report} */
1853
+ const report = (message, fix = null, jsdocLoc = null, data = undefined) => {
1854
+ let loc;
1855
+
1856
+ if (jsdocLoc) {
1857
+ if (!('line' in jsdocLoc)) {
1858
+ jsdocLoc.line = /** @type {import('comment-parser').Spec & {line?: Integer}} */ (
1859
+ jsdocLoc
1860
+ ).source[0].number;
1861
+ }
1862
+
1863
+ const lineNumber = /** @type {import('eslint').AST.SourceLocation} */ (
1864
+ commentNode.loc
1865
+ ).start.line +
1866
+ /** @type {Integer} */ (jsdocLoc.line);
1867
+
1868
+ loc = {
1869
+ end: {
1870
+ column: 0,
1871
+ line: lineNumber,
1872
+ },
1873
+ start: {
1874
+ column: 0,
1875
+ line: lineNumber,
1876
+ },
1877
+ };
1878
+
1879
+ if ('column' in jsdocLoc && typeof jsdocLoc.column === 'number') {
1880
+ const colNumber = /** @type {import('eslint').AST.SourceLocation} */ (
1881
+ commentNode.loc
1882
+ ).start.column + jsdocLoc.column;
1883
+
1884
+ loc.end.column = colNumber;
1885
+ loc.start.column = colNumber;
1886
+ }
1887
+ }
1888
+
1889
+ context.report({
1890
+ data,
1891
+ fix,
1892
+ loc,
1893
+ message,
1894
+ node: commentNode,
1895
+ });
1896
+ };
1897
+
1898
+ return report;
1899
+ };
1900
+
1901
+ /**
1902
+ * @typedef {(
1903
+ * arg: {
1904
+ * context: import('eslint').Rule.RuleContext,
1905
+ * sourceCode: import('eslint').SourceCode,
1906
+ * indent?: string,
1907
+ * info?: {
1908
+ * comment?: string|undefined,
1909
+ * lastIndex?: Integer|undefined
1910
+ * },
1911
+ * state?: StateObject,
1912
+ * globalState?: Map<string, Map<string, string>>,
1913
+ * jsdoc?: JsdocBlockWithInline,
1914
+ * jsdocNode?: import('eslint').Rule.Node & {
1915
+ * range: [number, number]
1916
+ * },
1917
+ * node?: Node,
1918
+ * allComments?: import('estree').Node[]
1919
+ * report?: Report,
1920
+ * makeReport?: MakeReport,
1921
+ * settings: Settings,
1922
+ * utils: BasicUtils,
1923
+ * }
1924
+ * ) => any } JsdocVisitorBasic
1925
+ */
1926
+ /**
1927
+ * @typedef {(
1928
+ * arg: {
1929
+ * context: import('eslint').Rule.RuleContext,
1930
+ * sourceCode: import('eslint').SourceCode,
1931
+ * indent: string,
1932
+ * info: {
1933
+ * comment?: string|undefined,
1934
+ * lastIndex?: Integer|undefined
1935
+ * },
1936
+ * state: StateObject,
1937
+ * globalState: Map<string, Map<string, string>>,
1938
+ * jsdoc: JsdocBlockWithInline,
1939
+ * jsdocNode: import('eslint').Rule.Node & {
1940
+ * range: [number, number]
1941
+ * },
1942
+ * node: Node|null,
1943
+ * allComments?: import('estree').Node[]
1944
+ * report: Report,
1945
+ * makeReport?: MakeReport,
1946
+ * settings: Settings,
1947
+ * utils: Utils,
1948
+ * }
1949
+ * ) => any } JsdocVisitor
1950
+ */
1951
+
1952
+ /**
1953
+ * @param {{
1954
+ * comment?: string,
1955
+ * lastIndex?: Integer,
1956
+ * selector?: string,
1957
+ * isFunctionContext?: boolean,
1958
+ * }} info
1959
+ * @param {string} indent
1960
+ * @param {JsdocBlockWithInline} jsdoc
1961
+ * @param {RuleConfig} ruleConfig
1962
+ * @param {import('eslint').Rule.RuleContext} context
1963
+ * @param {import('@es-joy/jsdoccomment').Token} jsdocNode
1964
+ * @param {Node|null} node
1965
+ * @param {Settings} settings
1966
+ * @param {import('eslint').SourceCode} sourceCode
1967
+ * @param {JsdocVisitor} iterator
1968
+ * @param {StateObject} state
1969
+ * @param {boolean} [iteratingAll]
1970
+ * @returns {void}
1971
+ */
1972
+ const iterate = (
1973
+ info,
1974
+ indent, jsdoc,
1975
+ ruleConfig, context, jsdocNode, node, settings,
1976
+ sourceCode, iterator, state, iteratingAll,
1977
+ ) => {
1978
+ const jsdocNde = /** @type {unknown} */ (jsdocNode);
1979
+ const report = makeReport(
1980
+ context,
1981
+ /** @type {import('estree').Node} */
1982
+ (jsdocNde),
1983
+ );
1984
+
1985
+ const utils = getUtils(
1986
+ node,
1987
+ jsdoc,
1988
+ /** @type {import('eslint').AST.Token} */
1989
+ (jsdocNode),
1990
+ settings,
1991
+ report,
1992
+ context,
1993
+ sourceCode,
1994
+ iteratingAll,
1995
+ ruleConfig,
1996
+ indent,
1997
+ );
1998
+
1999
+ if (
2000
+ !ruleConfig.checkInternal && settings.ignoreInternal &&
2001
+ utils.hasTag('internal')
2002
+ ) {
2003
+ return;
2004
+ }
2005
+
2006
+ if (
2007
+ !ruleConfig.checkPrivate && settings.ignorePrivate &&
2008
+ (
2009
+ utils.hasTag('private') ||
2010
+ jsdocUtils
2011
+ .filterTags(jsdoc, ({
2012
+ tag,
2013
+ }) => {
2014
+ return tag === 'access';
2015
+ })
2016
+ .some(({
2017
+ description,
2018
+ }) => {
2019
+ return description === 'private';
2020
+ })
2021
+ )
2022
+ ) {
2023
+ return;
2024
+ }
2025
+
2026
+ iterator({
2027
+ context,
2028
+ globalState,
2029
+ indent,
2030
+ info,
2031
+ jsdoc,
2032
+ jsdocNode: /**
2033
+ * @type {import('eslint').Rule.Node & {
2034
+ * range: [number, number];}}
2035
+ */ (jsdocNde),
2036
+ node,
2037
+ report,
2038
+ settings,
2039
+ sourceCode,
2040
+ state,
2041
+ utils,
2042
+ });
2043
+ };
2044
+
2045
+ /**
2046
+ * @param {string[]} lines
2047
+ * @param {import('estree').Comment} jsdocNode
2048
+ * @returns {[indent: string, jsdoc: JsdocBlockWithInline]}
2049
+ */
2050
+ const getIndentAndJSDoc = function (lines, jsdocNode) {
2051
+ const sourceLine = lines[
2052
+ /** @type {import('estree').SourceLocation} */
2053
+ (jsdocNode.loc).start.line - 1
2054
+ ];
2055
+
2056
+ let indentChar = sourceLine.charAt(0);
2057
+ if (indentChar !== ' ' && indentChar !== '\t') {
2058
+ indentChar = ' ';
2059
+ }
2060
+
2061
+ const indnt = indentChar.repeat(
2062
+ /** @type {import('estree').SourceLocation} */
2063
+ (jsdocNode.loc).start.column,
2064
+ );
2065
+
2066
+ const jsdc = parseComment(jsdocNode, '');
2067
+
2068
+ return [
2069
+ indnt, jsdc,
2070
+ ];
2071
+ };
2072
+
2073
+ /**
2074
+ *
2075
+ * @typedef {{node: Node & {
2076
+ * range: [number, number]
2077
+ * }, state: StateObject}} NonCommentArgs
2078
+ */
2079
+
2080
+ /**
2081
+ * @typedef {object} RuleConfig
2082
+ * @property {EslintRuleMeta} meta ESLint rule meta
2083
+ * @property {import('./jsdocUtils.js').DefaultContexts} [contextDefaults] Any default contexts
2084
+ * @property {true} [contextSelected] Whether to force a `contexts` check
2085
+ * @property {true} [iterateAllJsdocs] Whether to iterate all JSDoc blocks by default
2086
+ * regardless of context
2087
+ * @property {true} [checkPrivate] Whether to check `@private` blocks (normally exempted)
2088
+ * @property {true} [checkInternal] Whether to check `@internal` blocks (normally exempted)
2089
+ * @property {true} [checkFile] Whether to iterates over all JSDoc blocks regardless of attachment
2090
+ * @property {true} [nonGlobalSettings] Whether to avoid relying on settings for global contexts
2091
+ * @property {true} [noTracking] Whether to disable the tracking of visited comment nodes (as
2092
+ * non-tracked may conduct further actions)
2093
+ * @property {true} [matchContext] Whether the rule expects contexts to be based on a match option
2094
+ * @property {(args: {
2095
+ * context: import('eslint').Rule.RuleContext,
2096
+ * state: StateObject,
2097
+ * settings: Settings,
2098
+ * utils: BasicUtils
2099
+ * }) => void} [exit] Handler to be executed upon exiting iteration of program AST
2100
+ * @property {(nca: NonCommentArgs) => void} [nonComment] Handler to be executed if rule wishes
2101
+ * to be supplied nodes without comments
2102
+ */
2103
+
2104
+ /**
2105
+ * Create an eslint rule that iterates over all JSDocs, regardless of whether
2106
+ * they are attached to a function-like node.
2107
+ * @param {JsdocVisitor} iterator
2108
+ * @param {RuleConfig} ruleConfig The rule's configuration
2109
+ * @param {ContextObject[]|null} [contexts] The `contexts` containing relevant `comment` info.
2110
+ * @param {boolean} [additiveCommentContexts] If true, will have a separate
2111
+ * iteration for each matching comment context. Otherwise, will iterate
2112
+ * once if there is a single matching comment context.
2113
+ * @returns {import('eslint').Rule.RuleModule}
2114
+ */
2115
+ const iterateAllJsdocs = (iterator, ruleConfig, contexts, additiveCommentContexts) => {
2116
+ const trackedJsdocs = new Set();
2117
+
2118
+ /** @type {import('@es-joy/jsdoccomment').CommentHandler} */
2119
+ let handler;
2120
+
2121
+ /** @type {Settings|false} */
2122
+ let settings;
2123
+
2124
+ /**
2125
+ * @param {import('eslint').Rule.RuleContext} context
2126
+ * @param {Node|null} node
2127
+ * @param {import('estree').Comment[]} jsdocNodes
2128
+ * @param {StateObject} state
2129
+ * @param {boolean} [lastCall]
2130
+ * @returns {void}
2131
+ */
2132
+ const callIterator = (context, node, jsdocNodes, state, lastCall) => {
2133
+ /* c8 ignore next -- Fallback to deprecated method */
2134
+ const {
2135
+ sourceCode = context.getSourceCode(),
2136
+ } = context;
2137
+ const {
2138
+ lines,
2139
+ } = sourceCode;
2140
+
2141
+ const utils = getBasicUtils(context, /** @type {Settings} */ (settings));
2142
+ for (const jsdocNode of jsdocNodes) {
2143
+ const jsdocNde = /** @type {unknown} */ (jsdocNode);
2144
+ if (!(/^\/\*\*\s/v).test(sourceCode.getText(
2145
+ /** @type {import('estree').Node} */
2146
+ (jsdocNde),
2147
+ ))) {
2148
+ continue;
2149
+ }
2150
+
2151
+ const [
2152
+ indent,
2153
+ jsdoc,
2154
+ ] = getIndentAndJSDoc(
2155
+ lines, jsdocNode,
2156
+ );
2157
+
2158
+ if (additiveCommentContexts) {
2159
+ for (const [
2160
+ idx,
2161
+ {
2162
+ comment,
2163
+ },
2164
+ ] of /** @type {ContextObject[]} */ (contexts).entries()) {
2165
+ if (comment && handler(comment, jsdoc) === false) {
2166
+ continue;
2167
+ }
2168
+
2169
+ iterate(
2170
+ {
2171
+ comment,
2172
+ lastIndex: idx,
2173
+ selector: node?.type,
2174
+ },
2175
+ indent,
2176
+ jsdoc,
2177
+ ruleConfig,
2178
+ context,
2179
+ jsdocNode,
2180
+ /** @type {Node} */
2181
+ (node),
2182
+ /** @type {Settings} */
2183
+ (settings),
2184
+ sourceCode,
2185
+ iterator,
2186
+ state,
2187
+ true,
2188
+ );
2189
+ }
2190
+
2191
+ continue;
2192
+ }
2193
+
2194
+ let lastComment;
2195
+ let lastIndex;
2196
+ // eslint-disable-next-line no-loop-func
2197
+ if (contexts && contexts.every(({
2198
+ comment,
2199
+ }, idx) => {
2200
+ lastComment = comment;
2201
+ lastIndex = idx;
2202
+
2203
+ return comment && handler(comment, jsdoc) === false;
2204
+ })) {
2205
+ continue;
2206
+ }
2207
+
2208
+ iterate(
2209
+ lastComment ? {
2210
+ comment: lastComment,
2211
+ lastIndex,
2212
+ selector: node?.type,
2213
+ } : {
2214
+ lastIndex,
2215
+ selector: node?.type,
2216
+ },
2217
+ indent,
2218
+ jsdoc,
2219
+ ruleConfig,
2220
+ context,
2221
+ jsdocNode,
2222
+ node,
2223
+ /** @type {Settings} */
2224
+ (settings),
2225
+ sourceCode,
2226
+ iterator,
2227
+ state,
2228
+ true,
2229
+ );
2230
+ }
2231
+
2232
+ const settngs = /** @type {Settings} */ (settings);
2233
+
2234
+ if (lastCall && ruleConfig.exit) {
2235
+ ruleConfig.exit({
2236
+ context,
2237
+ settings: settngs,
2238
+ state,
2239
+ utils,
2240
+ });
2241
+ }
2242
+ };
2243
+
2244
+ return {
2245
+ create (context) {
2246
+ /* c8 ignore next -- Fallback to deprecated method */
2247
+ const {
2248
+ sourceCode = context.getSourceCode(),
2249
+ } = context;
2250
+ settings = getSettings(context);
2251
+ if (!settings) {
2252
+ return {};
2253
+ }
2254
+
2255
+ if (contexts) {
2256
+ handler = commentHandler(settings);
2257
+ }
2258
+
2259
+ const state = {};
2260
+
2261
+ return {
2262
+ /**
2263
+ * @param {import('eslint').Rule.Node & {
2264
+ * range: [Integer, Integer];
2265
+ * }} node
2266
+ * @returns {void}
2267
+ */
2268
+ '*:not(Program)' (node) {
2269
+ const commentNode = getJSDocComment(
2270
+ sourceCode, node, /** @type {Settings} */ (settings),
2271
+ );
2272
+ if (!ruleConfig.noTracking && trackedJsdocs.has(commentNode)) {
2273
+ return;
2274
+ }
2275
+
2276
+ if (!commentNode) {
2277
+ if (ruleConfig.nonComment) {
2278
+ const ste = /** @type {StateObject} */ (state);
2279
+ ruleConfig.nonComment({
2280
+ node,
2281
+ state: ste,
2282
+ });
2283
+ }
2284
+
2285
+ return;
2286
+ }
2287
+
2288
+ trackedJsdocs.add(commentNode);
2289
+ callIterator(context, node, [
2290
+ /** @type {import('estree').Comment} */
2291
+ (commentNode),
2292
+ ], /** @type {StateObject} */ (state));
2293
+ },
2294
+ 'Program:exit' () {
2295
+ const allComments = sourceCode.getAllComments();
2296
+ const untrackedJSdoc = allComments.filter((node) => {
2297
+ return !trackedJsdocs.has(node);
2298
+ });
2299
+
2300
+ callIterator(
2301
+ context,
2302
+ null,
2303
+ untrackedJSdoc,
2304
+ /** @type {StateObject} */
2305
+ (state),
2306
+ true,
2307
+ );
2308
+ },
2309
+ };
2310
+ },
2311
+ meta: ruleConfig.meta,
2312
+ };
2313
+ };
2314
+
2315
+ /**
2316
+ * Create an eslint rule that iterates over all JSDocs, regardless of whether
2317
+ * they are attached to a function-like node.
2318
+ * @param {JsdocVisitorBasic} iterator
2319
+ * @param {RuleConfig} ruleConfig
2320
+ * @returns {import('eslint').Rule.RuleModule}
2321
+ */
2322
+ const checkFile = (iterator, ruleConfig) => {
2323
+ return {
2324
+ create (context) {
2325
+ /* c8 ignore next -- Fallback to deprecated method */
2326
+ const {
2327
+ sourceCode = context.getSourceCode(),
2328
+ } = context;
2329
+ const settings = getSettings(context);
2330
+ if (!settings) {
2331
+ return {};
2332
+ }
2333
+
2334
+ return {
2335
+ 'Program:exit' () {
2336
+ const allComms = /** @type {unknown} */ (sourceCode.getAllComments());
2337
+ const utils = getBasicUtils(context, settings);
2338
+
2339
+ iterator({
2340
+ allComments: /** @type {import('estree').Node[]} */ (allComms),
2341
+ context,
2342
+ makeReport,
2343
+ settings,
2344
+ sourceCode,
2345
+ utils,
2346
+ });
2347
+ },
2348
+ };
2349
+ },
2350
+ meta: ruleConfig.meta,
2351
+ };
2352
+ };
2353
+
2354
+ export {
2355
+ getSettings,
2356
+ // dslint-disable-next-line unicorn/prefer-export-from -- Avoid experimental parser
2357
+
2358
+ };
2359
+
2360
+ /**
2361
+ * @param {JsdocVisitor} iterator
2362
+ * @param {RuleConfig} ruleConfig
2363
+ * @returns {import('eslint').Rule.RuleModule}
2364
+ */
2365
+ export default function iterateJsdoc (iterator, ruleConfig) {
2366
+ const metaType = ruleConfig?.meta?.type;
2367
+ if (!metaType || ![
2368
+ 'layout', 'problem', 'suggestion',
2369
+ ].includes(metaType)) {
2370
+ throw new TypeError('Rule must include `meta.type` option (with value "problem", "suggestion", or "layout")');
2371
+ }
2372
+
2373
+ if (typeof iterator !== 'function') {
2374
+ throw new TypeError('The iterator argument must be a function.');
2375
+ }
2376
+
2377
+ if (ruleConfig.checkFile) {
2378
+ return checkFile(
2379
+ /** @type {JsdocVisitorBasic} */ (iterator),
2380
+ ruleConfig,
2381
+ );
2382
+ }
2383
+
2384
+ if (ruleConfig.iterateAllJsdocs) {
2385
+ return iterateAllJsdocs(iterator, ruleConfig);
2386
+ }
2387
+
2388
+ /** @type {import('eslint').Rule.RuleModule} */
2389
+ return {
2390
+ /**
2391
+ * The entrypoint for the JSDoc rule.
2392
+ * @param {import('eslint').Rule.RuleContext} context
2393
+ * a reference to the context which hold all important information
2394
+ * like settings and the sourcecode to check.
2395
+ * @returns {import('eslint').Rule.RuleListener}
2396
+ * a listener with parser callback function.
2397
+ */
2398
+ create (context) {
2399
+ const settings = getSettings(context);
2400
+ if (!settings) {
2401
+ return {};
2402
+ }
2403
+
2404
+ /**
2405
+ * @type {Context[]|undefined}
2406
+ */
2407
+ let contexts;
2408
+ if (ruleConfig.contextDefaults || ruleConfig.contextSelected || ruleConfig.matchContext) {
2409
+ contexts = ruleConfig.matchContext && context.options[0]?.match ?
2410
+ context.options[0].match :
2411
+ jsdocUtils.enforcedContexts(context, ruleConfig.contextDefaults, ruleConfig.nonGlobalSettings ? {} : settings);
2412
+
2413
+ if (contexts) {
2414
+ contexts = contexts.map((obj) => {
2415
+ if (typeof obj === 'object' && !obj.context) {
2416
+ return {
2417
+ ...obj,
2418
+ context: 'any',
2419
+ };
2420
+ }
2421
+
2422
+ return obj;
2423
+ });
2424
+ }
2425
+
2426
+ const hasPlainAny = contexts?.includes('any');
2427
+ const hasObjectAny = !hasPlainAny && contexts?.find((ctxt) => {
2428
+ if (typeof ctxt === 'string') {
2429
+ return false;
2430
+ }
2431
+
2432
+ return ctxt?.context === 'any';
2433
+ });
2434
+ if (hasPlainAny || hasObjectAny) {
2435
+ return iterateAllJsdocs(
2436
+ iterator,
2437
+ ruleConfig,
2438
+ hasObjectAny ? /** @type {ContextObject[]} */ (contexts) : null,
2439
+ ruleConfig.matchContext,
2440
+ ).create(context);
2441
+ }
2442
+ }
2443
+
2444
+ /* c8 ignore next -- Fallback to deprecated method */
2445
+ const {
2446
+ sourceCode = context.getSourceCode(),
2447
+ } = context;
2448
+ const {
2449
+ lines,
2450
+ } = sourceCode;
2451
+
2452
+ /** @type {Partial<StateObject>} */
2453
+ const state = {};
2454
+
2455
+ /** @type {CheckJsdoc} */
2456
+ const checkJsdoc = (info, handler, node) => {
2457
+ const jsdocNode = getJSDocComment(sourceCode, node, settings);
2458
+ if (!jsdocNode) {
2459
+ return;
2460
+ }
2461
+
2462
+ const [
2463
+ indent,
2464
+ jsdoc,
2465
+ ] = getIndentAndJSDoc(
2466
+ lines,
2467
+ /** @type {import('estree').Comment} */
2468
+ (jsdocNode),
2469
+ );
2470
+
2471
+ if (
2472
+ // Note, `handler` should already be bound in its first argument
2473
+ // with these only to be called after the value of
2474
+ // `comment`
2475
+ handler && handler(jsdoc) === false
2476
+ ) {
2477
+ return;
2478
+ }
2479
+
2480
+ iterate(
2481
+ info,
2482
+ indent,
2483
+ jsdoc,
2484
+ ruleConfig,
2485
+ context,
2486
+ jsdocNode,
2487
+ node,
2488
+ settings,
2489
+ sourceCode,
2490
+ iterator,
2491
+ /** @type {StateObject} */
2492
+ (state),
2493
+ );
2494
+ };
2495
+
2496
+ /** @type {import('eslint').Rule.RuleListener} */
2497
+ let contextObject = {};
2498
+
2499
+ if (contexts && (
2500
+ ruleConfig.contextDefaults || ruleConfig.contextSelected || ruleConfig.matchContext
2501
+ )) {
2502
+ contextObject = jsdocUtils.getContextObject(
2503
+ contexts,
2504
+ checkJsdoc,
2505
+ commentHandler(settings),
2506
+ );
2507
+ } else {
2508
+ for (const prop of [
2509
+ 'ArrowFunctionExpression',
2510
+ 'FunctionDeclaration',
2511
+ 'FunctionExpression',
2512
+ 'TSDeclareFunction',
2513
+ ]) {
2514
+ contextObject[prop] = checkJsdoc.bind(null, {
2515
+ selector: prop,
2516
+ }, null);
2517
+ }
2518
+ }
2519
+
2520
+ if (typeof ruleConfig.exit === 'function') {
2521
+ contextObject['Program:exit'] = () => {
2522
+ const ste = /** @type {StateObject} */ (state);
2523
+
2524
+ // @ts-expect-error `utils` not needed at this point
2525
+ /** @type {Required<RuleConfig>} */ (ruleConfig).exit({
2526
+ context,
2527
+ settings,
2528
+ state: ste,
2529
+ });
2530
+ };
2531
+ }
2532
+
2533
+ return contextObject;
2534
+ },
2535
+ meta: ruleConfig.meta,
2536
+ };
2537
+ }
2538
+
2539
+ export {
2540
+ parseComment,
2541
+ } from '@es-joy/jsdoccomment';